Added Derivate function tests.
authorDaniel Hegedus <dhegedus.uszeged@partner.samsung.com>
Fri, 22 Apr 2016 13:23:42 +0000 (15:23 +0200)
committerAkos Dirner <adirner.uszeged@partner.samsung.com>
Tue, 14 Jun 2016 13:14:57 +0000 (15:14 +0200)
external/vulkancts/modules/vulkan/shaderrender/CMakeLists.txt
external/vulkancts/modules/vulkan/shaderrender/vktShaderRender.cpp
external/vulkancts/modules/vulkan/shaderrender/vktShaderRender.hpp
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderDerivateTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderDerivateTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/vktTestPackage.cpp

index 83fe317..d85c4a0 100644 (file)
@@ -5,6 +5,8 @@ include_directories(
 set(DEQP_VK_SHADERRENDER_SRCS
        vktShaderRender.cpp
        vktShaderRender.hpp
+       vktShaderRenderDerivateTests.cpp
+       vktShaderRenderDerivateTests.hpp
        vktShaderRenderDiscardTests.cpp
        vktShaderRenderDiscardTests.hpp
        vktShaderRenderIndexingTests.cpp
index ca39af5..611616d 100644 (file)
@@ -513,6 +513,8 @@ ShaderRenderCaseInstance::ShaderRenderCaseInstance (Context&                                        context,
        , m_evaluator                   (&evaluator)
        , m_uniformSetup                (&uniformSetup)
        , m_attribFunc                  (attribFunc)
+       , m_sampleCount                 (VK_SAMPLE_COUNT_1_BIT)
+       , m_multisampling               (false)
 {
 }
 
@@ -532,6 +534,8 @@ ShaderRenderCaseInstance::ShaderRenderCaseInstance (Context&                                        context,
        , m_evaluator                   (evaluator)
        , m_uniformSetup                (uniformSetup)
        , m_attribFunc                  (attribFunc)
+       , m_sampleCount                 (VK_SAMPLE_COUNT_1_BIT)
+       , m_multisampling               (false)
 {
 }
 
@@ -819,6 +823,12 @@ const tcu::UVec2 ShaderRenderCaseInstance::getViewportSize (void) const
                                          de::min(m_renderSize.y(), MAX_RENDER_HEIGHT));
 }
 
+void ShaderRenderCaseInstance::setSampleCount (VkSampleCountFlagBits sampleCount)
+{
+       m_sampleCount   = sampleCount;
+       m_multisampling = (m_sampleCount != VK_SAMPLE_COUNT_1_BIT);
+}
+
 void ShaderRenderCaseInstance::uploadImage (const tcu::TextureFormat&                  texFormat,
                                                                                        const TextureData&                                      textureData,
                                                                                        const tcu::Sampler&                                     refSampler,
@@ -1359,6 +1369,9 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
        vk::Move<vk::VkImage>                                                           colorImage;
        de::MovePtr<vk::Allocation>                                                     colorImageAlloc;
        vk::Move<vk::VkImageView>                                                       colorImageView;
+       vk::Move<vk::VkImage>                                                           resolvedImage;
+       de::MovePtr<vk::Allocation>                                                     resolvedImageAlloc;
+       vk::Move<vk::VkImageView>                                                       resolvedImageView;
        vk::Move<vk::VkRenderPass>                                                      renderPass;
        vk::Move<vk::VkFramebuffer>                                                     framebuffer;
        vk::Move<vk::VkPipelineLayout>                                          pipelineLayout;
@@ -1386,7 +1399,7 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
                        { m_renderSize.x(), m_renderSize.y(), 1u },                                                                     // VkExtent3D                   extent;
                        1u,                                                                                                                                                     // deUint32                             mipLevels;
                        1u,                                                                                                                                                     // deUint32                             arraySize;
-                       VK_SAMPLE_COUNT_1_BIT,                                                                                                          // deUint32                             samples;
+                       m_sampleCount,                                                                                                                          // deUint32                             samples;
                        VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                tiling;
                        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags    usage;
                        VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                sharingMode;
@@ -1430,19 +1443,103 @@ void ShaderRenderCaseInstance::render (deUint32                                numVertices,
                colorImageView = createImageView(vk, vkDevice, &colorImageViewParams);
        }
 
+       if (m_multisampling)
+       {
+               // Resolved Image
+               {
+                       const VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+                       VkImageFormatProperties properties;
+
+                       if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(),
+                                                                                                                                                                                m_colorFormat,
+                                                                                                                                                                                VK_IMAGE_TYPE_2D,
+                                                                                                                                                                                VK_IMAGE_TILING_OPTIMAL,
+                                                                                                                                                                                imageUsage,
+                                                                                                                                                                                0,
+                                                                                                                                                                                &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
+                       {
+                               TCU_THROW(NotSupportedError, "Format not supported");
+                       }
+
+                       const VkImageCreateInfo                                 imageCreateInfo                 =
+                       {
+                               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,            // VkStructureType                      sType;
+                               DE_NULL,                                                                        // const void*                          pNext;
+                               0u,                                                                                     // VkImageCreateFlags           flags;
+                               VK_IMAGE_TYPE_2D,                                                       // VkImageType                          imageType;
+                               m_colorFormat,                                                          // VkFormat                                     format;
+                               { m_renderSize.x(),     m_renderSize.y(), 1u }, // VkExtent3D                           extent;
+                               1u,                                                                                     // deUint32                                     mipLevels;
+                               1u,                                                                                     // deUint32                                     arrayLayers;
+                               VK_SAMPLE_COUNT_1_BIT,                                          // VkSampleCountFlagBits        samples;
+                               VK_IMAGE_TILING_OPTIMAL,                                        // VkImageTiling                        tiling;
+                               imageUsage,                                                                     // VkImageUsageFlags            usage;
+                               VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                        sharingMode;
+                               1u,                                                                                     // deUint32                                     queueFamilyIndexCount;
+                               &queueFamilyIndex,                                                      // const deUint32*                      pQueueFamilyIndices;
+                               VK_IMAGE_LAYOUT_UNDEFINED                                       // VkImageLayout                        initialLayout;
+                       };
+
+                       resolvedImage           = vk::createImage(vk, vkDevice, &imageCreateInfo, DE_NULL);
+                       resolvedImageAlloc      = m_memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *resolvedImage), MemoryRequirement::Any);
+                       VK_CHECK(vk.bindImageMemory(vkDevice, *resolvedImage, resolvedImageAlloc->getMemory(), resolvedImageAlloc->getOffset()));
+               }
+
+               // Resolved Image View
+               {
+                       const VkImageViewCreateInfo                             imageViewCreateInfo             =
+                       {
+                               VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,       // VkStructureType                              sType;
+                               DE_NULL,                                                                        // const void*                                  pNext;
+                               0u,                                                                                     // VkImageViewCreateFlags               flags;
+                               *resolvedImage,                                                         // VkImage                                              image;
+                               VK_IMAGE_VIEW_TYPE_2D,                                          // VkImageViewType                              viewType;
+                               m_colorFormat,                                                          // VkFormat                                             format;
+                               {
+                                       VK_COMPONENT_SWIZZLE_R,                                 // VkChannelSwizzle             r;
+                                       VK_COMPONENT_SWIZZLE_G,                                 // VkChannelSwizzle             g;
+                                       VK_COMPONENT_SWIZZLE_B,                                 // VkChannelSwizzle             b;
+                                       VK_COMPONENT_SWIZZLE_A                                  // VkChannelSwizzle             a;
+                               },
+                               {
+                                       VK_IMAGE_ASPECT_COLOR_BIT,                                      // VkImageAspectFlags                   aspectMask;
+                                       0u,                                                                                     // deUint32                                             baseMipLevel;
+                                       1u,                                                                                     // deUint32                                             mipLevels;
+                                       0u,                                                                                     // deUint32                                             baseArrayLayer;
+                                       1u,                                                                                     // deUint32                                             arraySize;
+                               },                                                                                      // VkImageSubresourceRange              subresourceRange;
+                       };
+
+                       resolvedImageView = vk::createImageView(vk, vkDevice, &imageViewCreateInfo, DE_NULL);
+               }
+       }
+
        // Create render pass
        {
-               const VkAttachmentDescription                                   attachmentDescription           =
+               const VkAttachmentDescription                                   attachmentDescription[]         =
                {
-                       (VkAttachmentDescriptionFlags)0,
-                       m_colorFormat,                                                                          // VkFormat                                             format;
-                       VK_SAMPLE_COUNT_1_BIT,                                                          // deUint32                                             samples;
-                       VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                   loadOp;
-                       VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                  storeOp;
-                       VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                        // VkAttachmentLoadOp                   stencilLoadOp;
-                       VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                  stencilStoreOp;
-                       VK_IMAGE_LAYOUT_UNDEFINED,                                                      // VkImageLayout                                initialLayout;
-                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                finalLayout;
+                       {
+                               (VkAttachmentDescriptionFlags)0,                                        // VkAttachmentDescriptionFlags         flags;
+                               m_colorFormat,                                                                          // VkFormat                                                     format;
+                               m_sampleCount,                                                                          // deUint32                                                     samples;
+                               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           loadOp;
+                               VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                          storeOp;
+                               VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                        // VkAttachmentLoadOp                           stencilLoadOp;
+                               VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                          stencilStoreOp;
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                        initialLayout;
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                        finalLayout;
+                       },
+                       {
+                               (VkAttachmentDescriptionFlags)0,                                        // VkAttachmentDescriptionFlags         flags;
+                               m_colorFormat,                                                                          // VkFormat                                                     format;
+                               VK_SAMPLE_COUNT_1_BIT,                                                          // VkSampleCountFlagBits                        samples;
+                               VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                           loadOp;
+                               VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                          storeOp;
+                               VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                        // VkAttachmentLoadOp                           stencilLoadOp;
+                               VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                          stencilStoreOp;
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                        initialLayout;
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                        finalLayout;
+                       }
                };
 
                const VkAttachmentReference                                             attachmentReference                     =
@@ -1451,6 +1548,12 @@ void ShaderRenderCaseInstance::render (deUint32                          numVertices,
                        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
                };
 
+               const VkAttachmentReference                                             resolveAttachmentRef            =
+               {
+                       1u,                                                                                                     // deUint32                     attachment;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
+               };
+
                const VkSubpassDescription                                              subpassDescription                      =
                {
                        0u,                                                                                                     // VkSubpassDescriptionFlags    flags;
@@ -1459,7 +1562,7 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
                        DE_NULL,                                                                                        // constVkAttachmentReference*  pInputAttachments;
                        1u,                                                                                                     // deUint32                                             colorCount;
                        &attachmentReference,                                                           // constVkAttachmentReference*  pColorAttachments;
-                       DE_NULL,                                                                                        // constVkAttachmentReference*  pResolveAttachments;
+                       m_multisampling ? &resolveAttachmentRef : DE_NULL,      // constVkAttachmentReference*  pResolveAttachments;
                        DE_NULL,                                                                                        // VkAttachmentReference                depthStencilAttachment;
                        0u,                                                                                                     // deUint32                                             preserveCount;
                        DE_NULL                                                                                         // constVkAttachmentReference*  pPreserveAttachments;
@@ -1469,9 +1572,9 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
                {
                        VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                      // VkStructureType                                      sType;
                        DE_NULL,                                                                                        // const void*                                          pNext;
-                       (VkRenderPassCreateFlags)0,
-                       1u,                                                                                                     // deUint32                                                     attachmentCount;
-                       &attachmentDescription,                                                         // const VkAttachmentDescription*       pAttachments;
+                       0u,                                                                                                     // VkRenderPassCreateFlags                      flags;
+                       m_multisampling ? 2u : 1u,                                                      // deUint32                                                     attachmentCount;
+                       attachmentDescription,                                                          // const VkAttachmentDescription*       pAttachments;
                        1u,                                                                                                     // deUint32                                                     subpassCount;
                        &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
                        0u,                                                                                                     // deUint32                                                     dependencyCount;
@@ -1483,14 +1586,20 @@ void ShaderRenderCaseInstance::render (deUint32                         numVertices,
 
        // Create framebuffer
        {
+               const VkImageView                                                               attachments[]                           =
+               {
+                       *colorImageView,
+                       *resolvedImageView
+               };
+
                const VkFramebufferCreateInfo                                   framebufferParams                       =
                {
                        VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                      // VkStructureType                              sType;
                        DE_NULL,                                                                                        // const void*                                  pNext;
                        (VkFramebufferCreateFlags)0,
                        *renderPass,                                                                            // VkRenderPass                                 renderPass;
-                       1u,                                                                                                     // deUint32                                             attachmentCount;
-                       &*colorImageView,                                                                       // const VkImageView*                   pAttachments;
+                       m_multisampling ? 2u : 1u,                                                      // deUint32                                             attachmentCount;
+                       attachments,                                                                            // const VkImageView*                   pAttachments;
                        (deUint32)m_renderSize.x(),                                                     // deUint32                                             width;
                        (deUint32)m_renderSize.y(),                                                     // deUint32                                             height;
                        1u                                                                                                      // deUint32                                             layers;
@@ -1640,13 +1749,13 @@ void ShaderRenderCaseInstance::render (deUint32                         numVertices,
 
                const VkPipelineViewportStateCreateInfo                 viewportStateParams                     =
                {
-                       VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                  // VkStructureType              sType;
-                       DE_NULL,                                                                                                                // const void*                  pNext;
-                       (VkPipelineViewportStateCreateFlags)0,
-                       1u,                                                                                                                             // deUint32                             viewportCount;
-                       &viewport,                                                                                                              // const VkViewport*    pViewports;
-                       1u,                                                                                                                             // deUint32                             scissorsCount;
-                       &scissor,                                                                                                               // const VkRect2D*              pScissors;
+                       VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                  // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                                // const void*                                                  pNext;
+                       0u,                                                                                                                             // VkPipelineViewportStateCreateFlags   flags;
+                       1u,                                                                                                                             // deUint32                                                             viewportCount;
+                       &viewport,                                                                                                              // const VkViewport*                                    pViewports;
+                       1u,                                                                                                                             // deUint32                                                             scissorsCount;
+                       &scissor,                                                                                                               // const VkRect2D*                                              pScissors;
                };
 
                const VkPipelineRasterizationStateCreateInfo    rasterStateParams                       =
@@ -1671,7 +1780,7 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
                        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,               // VkStructureType                                                      sType;
                        DE_NULL,                                                                                                                // const void*                                                          pNext;
                        0u,                                                                                                                             // VkPipelineMultisampleStateCreateFlags        flags;
-                       VK_SAMPLE_COUNT_1_BIT,                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
+                       m_sampleCount,                                                                                                  // VkSampleCountFlagBits                                        rasterizationSamples;
                        VK_FALSE,                                                                                                               // VkBool32                                                                     sampleShadingEnable;
                        0.0f,                                                                                                                   // float                                                                        minSampleShading;
                        DE_NULL,                                                                                                                // const VkSampleMask*                                          pSampleMask;
@@ -1809,6 +1918,55 @@ void ShaderRenderCaseInstance::render (deUint32                          numVertices,
 
                VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
 
+               {
+                       const VkImageMemoryBarrier                                      imageBarrier                            =
+                       {
+                               VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                                                                         // VkStructureType                      sType;
+                               DE_NULL,                                                                                                                                        // const void*                          pNext;
+                               0u,                                                                                                                                                     // VkAccessFlags                        srcAccessMask;
+                               VK_PIPELINE_STAGE_TRANSFER_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags                        dstAccessMask;
+                               VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                      // VkImageLayout                        oldLayout;
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                                                       // VkImageLayout                        newLayout;
+                               VK_QUEUE_FAMILY_IGNORED,                                                                                                        // deUint32                                     srcQueueFamilyIndex;
+                               VK_QUEUE_FAMILY_IGNORED,                                                                                                        // deUint32                                     dstQueueFamilyIndex;
+                               *colorImage,                                                                                                                            // VkImage                                      image;
+                               {                                                                                                                                                       // VkImageSubresourceRange      subresourceRange;
+                                       VK_IMAGE_ASPECT_COLOR_BIT,                                                                                              // VkImageAspectFlags           aspectMask;
+                                       0u,                                                                                                                                             // deUint32                                     baseMipLevel;
+                                       1u,                                                                                                                                             // deUint32                                     mipLevels;
+                                       0u,                                                                                                                                             // deUint32                                     baseArrayLayer;
+                                       1u,                                                                                                                                             // deUint32                                     arraySize;
+                               }
+                       };
+
+                       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, DE_NULL, 1, &imageBarrier);
+
+                       if (m_multisampling) {
+                               // add multisample barrier
+                               const VkImageMemoryBarrier                              multiSampleImageBarrier         =
+                               {
+                                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                                                                         // VkStructureType                      sType;
+                                       DE_NULL,                                                                                                                                        // const void*                          pNext;
+                                       0u,                                                                                                                                                     // VkAccessFlags                        srcAccessMask;
+                                       VK_PIPELINE_STAGE_TRANSFER_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,          // VkAccessFlags                        dstAccessMask;
+                                       VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                      // VkImageLayout                        oldLayout;
+                                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                                                       // VkImageLayout                        newLayout;
+                                       VK_QUEUE_FAMILY_IGNORED,                                                                                                        // deUint32                                     srcQueueFamilyIndex;
+                                       VK_QUEUE_FAMILY_IGNORED,                                                                                                        // deUint32                                     dstQueueFamilyIndex;
+                                       *resolvedImage,                                                                                                                         // VkImage                                      image;
+                                       {                                                                                                                                                       // VkImageSubresourceRange      subresourceRange;
+                                               VK_IMAGE_ASPECT_COLOR_BIT,                                                                                              // VkImageAspectFlags           aspectMask;
+                                               0u,                                                                                                                                             // deUint32                                     baseMipLevel;
+                                               1u,                                                                                                                                             // deUint32                                     mipLevels;
+                                               0u,                                                                                                                                             // deUint32                                     baseArrayLayer;
+                                               1u,                                                                                                                                             // deUint32                                     arraySize;
+                                       }
+                               };
+
+                               vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, DE_NULL, 1, &multiSampleImageBarrier);
+                       }
+               }
+
                vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
 
                vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
@@ -1865,7 +2023,8 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
 
        // Read back the result
        {
-               const VkDeviceSize                                                              imageSizeBytes                          = (VkDeviceSize)(sizeof(deUint32) * m_renderSize.x() * m_renderSize.y());
+               const tcu::TextureFormat                                                resultFormat                            = mapVkFormat(m_colorFormat);
+               const VkDeviceSize                                                              imageSizeBytes                          = (VkDeviceSize)(resultFormat.getPixelSize() * m_renderSize.x() * m_renderSize.y());
                const VkBufferCreateInfo                                                readImageBufferParams           =
                {
                        VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           //  VkStructureType             sType;
@@ -1931,27 +2090,27 @@ void ShaderRenderCaseInstance::render (deUint32                         numVertices,
 
                VK_CHECK(vk.beginCommandBuffer(*resultCmdBuffer, &cmdBufferBeginInfo));
 
-               const VkImageMemoryBarrier imageBarrier =
+               const VkImageMemoryBarrier                                              imageBarrier                            =
                {
-                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,         // VkStructureType                      sType;
-                       DE_NULL,                                                                        // const void*                          pNext;
-                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,           // VkAccessFlags                        srcAccessMask;
-                       VK_ACCESS_TRANSFER_READ_BIT,                            // VkAccessFlags                        dstAccessMask;
-                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,       // VkImageLayout                        oldLayout;
-                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,           // VkImageLayout                        newLayout;
-                       VK_QUEUE_FAMILY_IGNORED,                                        // deUint32                                     srcQueueFamilyIndex;
-                       VK_QUEUE_FAMILY_IGNORED,                                        // deUint32                                     dstQueueFamilyIndex;
-                       *colorImage,                                                            // VkImage                                      image;
-                       {                                                                                       // VkImageSubresourceRange      subresourceRange;
-                               VK_IMAGE_ASPECT_COLOR_BIT,                              // VkImageAspectFlags   aspectMask;
-                               0u,                                                     // deUint32                             baseMipLevel;
-                               1u,                                                     // deUint32                             mipLevels;
-                               0u,                                                     // deUint32                             baseArraySlice;
-                               1u                                                      // deUint32                             arraySize;
+                       VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,                                                                 // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                // const void*                          pNext;
+                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,    // VkAccessFlags                        srcAccessMask;
+                       VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,                             // VkAccessFlags                        dstAccessMask;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                                               // VkImageLayout                        oldLayout;
+                       VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,                                                                   // VkImageLayout                        newLayout;
+                       VK_QUEUE_FAMILY_IGNORED,                                                                                                // deUint32                                     srcQueueFamilyIndex;
+                       VK_QUEUE_FAMILY_IGNORED,                                                                                                // deUint32                                     dstQueueFamilyIndex;
+                       m_multisampling ? *resolvedImage : *colorImage,                                                 // VkImage                                      image;
+                       {                                                                                                                                               // VkImageSubresourceRange      subresourceRange;
+                               VK_IMAGE_ASPECT_COLOR_BIT,                                                                                      // VkImageAspectFlags           aspectMask;
+                               0u,                                                                                                                                     // deUint32                                     baseMipLevel;
+                               1u,                                                                                                                                     // deUint32                                     mipLevels;
+                               0u,                                                                                                                                     // deUint32                                     baseArraySlice;
+                               1u                                                                                                                                      // deUint32                                     arraySize;
                        }
                };
 
-               const VkBufferMemoryBarrier bufferBarrier =
+               const VkBufferMemoryBarrier                                             bufferBarrier                           =
                {
                        VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,        // VkStructureType      sType;
                        DE_NULL,                                                                        // const void*          pNext;
@@ -1965,7 +2124,7 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
                };
 
                vk.cmdPipelineBarrier(*resultCmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &imageBarrier);
-               vk.cmdCopyImageToBuffer(*resultCmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
+               vk.cmdCopyImageToBuffer(*resultCmdBuffer, m_multisampling ? *resolvedImage : *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
                vk.cmdPipelineBarrier(*resultCmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &bufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
 
                VK_CHECK(vk.endCommandBuffer(*resultCmdBuffer));
@@ -1976,7 +2135,6 @@ void ShaderRenderCaseInstance::render (deUint32                           numVertices,
 
                invalidateMappedMemoryRange(vk, vkDevice, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset(), imageSizeBytes);
 
-               const tcu::TextureFormat                                                resultFormat                            = mapVkFormat(m_colorFormat);
                const tcu::ConstPixelBufferAccess                               resultAccess                            (resultFormat, m_renderSize.x(), m_renderSize.y(), 1, readImageBufferMemory->getHostPtr());
 
                m_resultImage.setStorage(resultFormat, m_renderSize.x(), m_renderSize.y());
index c9dba84..fe11e24 100644 (file)
@@ -37,6 +37,7 @@
 #include "vkMemUtil.hpp"
 #include "vkBuilderUtil.hpp"
 #include "vkTypeUtil.hpp"
+#include "vkPlatform.hpp"
 
 #include "vktTestCaseUtil.hpp"
 
@@ -363,7 +364,10 @@ enum BaseUniformType
 
        UV4_BLACK,
        UV4_GRAY,
-       UV4_WHITE
+       UV4_WHITE,
+
+// Last
+       U_LAST
 };
 
 enum BaseAttributeType
@@ -443,6 +447,8 @@ protected:
 
        const tcu::UVec2                                                                        getViewportSize                         (void) const;
 
+       void                                                                                            setSampleCount                          (vk::VkSampleCountFlagBits sampleCount);
+
        vk::Allocator&                                                                          m_memAlloc;
        const tcu::Vec4                                                                         m_clearColor;
        const bool                                                                                      m_isVertexCase;
@@ -551,6 +557,9 @@ private:
 
        std::vector<VkBufferSp>                                                         m_vertexBuffers;
        std::vector<AllocationSp>                                                       m_vertexBufferAllocs;
+
+       vk::VkSampleCountFlagBits                                                       m_sampleCount;
+       bool                                                                                            m_multisampling;
 };
 
 template<typename T>
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderDerivateTests.cpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderDerivateTests.cpp
new file mode 100644 (file)
index 0000000..c6942d9
--- /dev/null
@@ -0,0 +1,1855 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Shader derivate function tests.
+ *
+ * \todo [2013-06-25 pyry] Missing features:
+ *  - lines and points
+ *  - projected coordinates
+ *  - continous non-trivial functions (sin, exp)
+ *  - non-continous functions (step)
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderRenderDerivateTests.hpp"
+#include "vktShaderRender.hpp"
+#include "vkImageUtil.hpp"
+
+#include "gluTextureUtil.hpp"
+
+#include "tcuStringTemplate.hpp"
+#include "tcuSurface.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuVectorUtil.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuRGBA.hpp"
+#include "tcuFloat.hpp"
+#include "tcuInterval.hpp"
+
+#include "deUniquePtr.hpp"
+#include "glwEnums.hpp"
+
+#include <sstream>
+#include <string>
+
+namespace vkt
+{
+namespace sr
+{
+namespace
+{
+
+using namespace vk;
+
+using std::vector;
+using std::string;
+using std::map;
+using tcu::TestLog;
+using std::ostringstream;
+
+enum
+{
+       VIEWPORT_WIDTH                  = 99,
+       VIEWPORT_HEIGHT                 = 133,
+       MAX_FAILED_MESSAGES             = 10
+};
+
+enum DerivateFunc
+{
+       DERIVATE_DFDX                   = 0,
+       DERIVATE_DFDXFINE,
+       DERIVATE_DFDXCOARSE,
+
+       DERIVATE_DFDY,
+       DERIVATE_DFDYFINE,
+       DERIVATE_DFDYCOARSE,
+
+       DERIVATE_FWIDTH,
+       DERIVATE_FWIDTHFINE,
+       DERIVATE_FWIDTHCOARSE,
+
+       DERIVATE_LAST
+};
+
+enum SurfaceType
+{
+       SURFACETYPE_UNORM_FBO   = 0,
+       SURFACETYPE_FLOAT_FBO,  // \note Uses RGBA32UI fbo actually, since FP rendertargets are not in core spec.
+
+       SURFACETYPE_LAST
+};
+
+// Utilities
+
+static const char* getDerivateFuncName (DerivateFunc func)
+{
+       switch (func)
+       {
+               case DERIVATE_DFDX:                             return "dFdx";
+               case DERIVATE_DFDXFINE:                 return "dFdxFine";
+               case DERIVATE_DFDXCOARSE:               return "dFdxCoarse";
+               case DERIVATE_DFDY:                             return "dFdy";
+               case DERIVATE_DFDYFINE:                 return "dFdyFine";
+               case DERIVATE_DFDYCOARSE:               return "dFdyCoarse";
+               case DERIVATE_FWIDTH:                   return "fwidth";
+               case DERIVATE_FWIDTHFINE:               return "fwidthFine";
+               case DERIVATE_FWIDTHCOARSE:             return "fwidthCoarse";
+               default:
+                       DE_ASSERT(false);
+                       return DE_NULL;
+       }
+}
+
+static const char* getDerivateFuncCaseName (DerivateFunc func)
+{
+       switch (func)
+       {
+               case DERIVATE_DFDX:                             return "dfdx";
+               case DERIVATE_DFDXFINE:                 return "dfdxfine";
+               case DERIVATE_DFDXCOARSE:               return "dfdxcoarse";
+               case DERIVATE_DFDY:                             return "dfdy";
+               case DERIVATE_DFDYFINE:                 return "dfdyfine";
+               case DERIVATE_DFDYCOARSE:               return "dfdycoarse";
+               case DERIVATE_FWIDTH:                   return "fwidth";
+               case DERIVATE_FWIDTHFINE:               return "fwidthfine";
+               case DERIVATE_FWIDTHCOARSE:             return "fwidthcoarse";
+               default:
+                       DE_ASSERT(false);
+                       return DE_NULL;
+       }
+}
+
+static inline bool isDfdxFunc (DerivateFunc func)
+{
+       return func == DERIVATE_DFDX || func == DERIVATE_DFDXFINE || func == DERIVATE_DFDXCOARSE;
+}
+
+static inline bool isDfdyFunc (DerivateFunc func)
+{
+       return func == DERIVATE_DFDY || func == DERIVATE_DFDYFINE || func == DERIVATE_DFDYCOARSE;
+}
+
+static inline bool isFwidthFunc (DerivateFunc func)
+{
+       return func == DERIVATE_FWIDTH || func == DERIVATE_FWIDTHFINE || func == DERIVATE_FWIDTHCOARSE;
+}
+
+static inline tcu::BVec4 getDerivateMask (glu::DataType type)
+{
+       switch (type)
+       {
+               case glu::TYPE_FLOAT:           return tcu::BVec4(true, false, false, false);
+               case glu::TYPE_FLOAT_VEC2:      return tcu::BVec4(true, true, false, false);
+               case glu::TYPE_FLOAT_VEC3:      return tcu::BVec4(true, true, true, false);
+               case glu::TYPE_FLOAT_VEC4:      return tcu::BVec4(true, true, true, true);
+               default:
+                       DE_ASSERT(false);
+                       return tcu::BVec4(true);
+       }
+}
+
+static inline tcu::Vec4 readDerivate (const tcu::ConstPixelBufferAccess& surface, const tcu::Vec4& derivScale, const tcu::Vec4& derivBias, int x, int y)
+{
+       return (surface.getPixel(x, y) - derivBias) / derivScale;
+}
+
+static inline tcu::UVec4 getCompExpBits (const tcu::Vec4& v)
+{
+       return tcu::UVec4(tcu::Float32(v[0]).exponentBits(),
+                                         tcu::Float32(v[1]).exponentBits(),
+                                         tcu::Float32(v[2]).exponentBits(),
+                                         tcu::Float32(v[3]).exponentBits());
+}
+
+float computeFloatingPointError (const float value, const int numAccurateBits)
+{
+       const int               numGarbageBits  = 23-numAccurateBits;
+       const deUint32  mask                    = (1u<<numGarbageBits)-1u;
+       const int               exp                             = tcu::Float32(value).exponent();
+
+       return tcu::Float32::construct(+1, exp, (1u<<23) | mask).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
+}
+
+static int getNumMantissaBits (const glu::Precision precision)
+{
+       switch (precision)
+       {
+               case glu::PRECISION_HIGHP:              return 23;
+               case glu::PRECISION_MEDIUMP:    return 10;
+               case glu::PRECISION_LOWP:               return 6;
+               default:
+                       DE_ASSERT(false);
+                       return 0;
+       }
+}
+
+static int getMinExponent (const glu::Precision precision)
+{
+       switch (precision)
+       {
+               case glu::PRECISION_HIGHP:              return -126;
+               case glu::PRECISION_MEDIUMP:    return -14;
+               case glu::PRECISION_LOWP:               return -8;
+               default:
+                       DE_ASSERT(false);
+                       return 0;
+       }
+}
+
+static float getSingleULPForExponent (int exp, int numMantissaBits)
+{
+       if (numMantissaBits > 0)
+       {
+               DE_ASSERT(numMantissaBits <= 23);
+
+               const int ulpBitNdx = 23-numMantissaBits;
+               return tcu::Float32::construct(+1, exp, (1<<23) | (1 << ulpBitNdx)).asFloat() - tcu::Float32::construct(+1, exp, (1<<23)).asFloat();
+       }
+       else
+       {
+               DE_ASSERT(numMantissaBits == 0);
+               return tcu::Float32::construct(+1, exp, (1<<23)).asFloat();
+       }
+}
+
+static float getSingleULPForValue (float value, int numMantissaBits)
+{
+       const int exp = tcu::Float32(value).exponent();
+       return getSingleULPForExponent(exp, numMantissaBits);
+}
+
+static float convertFloatFlushToZeroRtn (float value, int minExponent, int numAccurateBits)
+{
+       if (value == 0.0f)
+       {
+               return 0.0f;
+       }
+       else
+       {
+               const tcu::Float32      inputFloat                      = tcu::Float32(value);
+               const int                       numTruncatedBits        = 23-numAccurateBits;
+               const deUint32          truncMask                       = (1u<<numTruncatedBits)-1u;
+
+               if (value > 0.0f)
+               {
+                       if (value > 0.0f && tcu::Float32(value).exponent() < minExponent)
+                       {
+                               // flush to zero if possible
+                               return 0.0f;
+                       }
+                       else
+                       {
+                               // just mask away non-representable bits
+                               return tcu::Float32::construct(+1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).asFloat();
+                       }
+               }
+               else
+               {
+                       if (inputFloat.mantissa() & truncMask)
+                       {
+                               // decrement one ulp if truncated bits are non-zero (i.e. if value is not representable)
+                               return tcu::Float32::construct(-1, inputFloat.exponent(), inputFloat.mantissa() & ~truncMask).asFloat() - getSingleULPForExponent(inputFloat.exponent(), numAccurateBits);
+                       }
+                       else
+                       {
+                               // value is representable, no need to do anything
+                               return value;
+                       }
+               }
+       }
+}
+
+static float convertFloatFlushToZeroRtp (float value, int minExponent, int numAccurateBits)
+{
+       return -convertFloatFlushToZeroRtn(-value, minExponent, numAccurateBits);
+}
+
+static float addErrorUlp (float value, float numUlps, int numMantissaBits)
+{
+       return value + numUlps * getSingleULPForValue(value, numMantissaBits);
+}
+
+enum
+{
+       INTERPOLATION_LOST_BITS = 3, // number mantissa of bits allowed to be lost in varying interpolation
+};
+
+static inline tcu::Vec4 getDerivateThreshold (const glu::Precision precision, const tcu::Vec4& valueMin, const tcu::Vec4& valueMax, const tcu::Vec4& expectedDerivate)
+{
+       const int                       baseBits                = getNumMantissaBits(precision);
+       const tcu::UVec4        derivExp                = getCompExpBits(expectedDerivate);
+       const tcu::UVec4        maxValueExp             = max(getCompExpBits(valueMin), getCompExpBits(valueMax));
+       const tcu::UVec4        numBitsLost             = maxValueExp - min(maxValueExp, derivExp);
+       const tcu::IVec4        numAccurateBits = max(baseBits - numBitsLost.asInt() - (int)INTERPOLATION_LOST_BITS, tcu::IVec4(0));
+
+       return tcu::Vec4(computeFloatingPointError(expectedDerivate[0], numAccurateBits[0]),
+                                        computeFloatingPointError(expectedDerivate[1], numAccurateBits[1]),
+                                        computeFloatingPointError(expectedDerivate[2], numAccurateBits[2]),
+                                        computeFloatingPointError(expectedDerivate[3], numAccurateBits[3]));
+}
+
+struct LogVecComps
+{
+       const tcu::Vec4&        v;
+       int                                     numComps;
+
+       LogVecComps (const tcu::Vec4& v_, int numComps_)
+               : v                     (v_)
+               , numComps      (numComps_)
+       {
+       }
+};
+
+std::ostream& operator<< (std::ostream& str, const LogVecComps& v)
+{
+       DE_ASSERT(de::inRange(v.numComps, 1, 4));
+       if (v.numComps == 1)            return str << v.v[0];
+       else if (v.numComps == 2)       return str << v.v.toWidth<2>();
+       else if (v.numComps == 3)       return str << v.v.toWidth<3>();
+       else                                            return str << v.v;
+}
+
+enum VerificationLogging
+{
+       LOG_ALL = 0,
+       LOG_NOTHING
+};
+
+static bool verifyConstantDerivate (tcu::TestLog&                                              log,
+                                                                       const tcu::ConstPixelBufferAccess&      result,
+                                                                       const tcu::PixelBufferAccess&           errorMask,
+                                                                       glu::DataType                                           dataType,
+                                                                       const tcu::Vec4&                                        reference,
+                                                                       const tcu::Vec4&                                        threshold,
+                                                                       const tcu::Vec4&                                        scale,
+                                                                       const tcu::Vec4&                                        bias,
+                                                                       VerificationLogging                                     logPolicy = LOG_ALL)
+{
+       const int                       numComps                = glu::getDataTypeFloatScalars(dataType);
+       const tcu::BVec4        mask                    = tcu::logicalNot(getDerivateMask(dataType));
+       int                                     numFailedPixels = 0;
+
+       if (logPolicy == LOG_ALL)
+               log << TestLog::Message << "Expecting " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps) << TestLog::EndMessage;
+
+       for (int y = 0; y < result.getHeight(); y++)
+       {
+               for (int x = 0; x < result.getWidth(); x++)
+               {
+                       const tcu::Vec4         resDerivate             = readDerivate(result, scale, bias, x, y);
+                       const bool                      isOk                    = tcu::allEqual(tcu::logicalOr(tcu::lessThanEqual(tcu::abs(reference - resDerivate), threshold), mask), tcu::BVec4(true));
+
+                       if (!isOk)
+                       {
+                               if (numFailedPixels < MAX_FAILED_MESSAGES && logPolicy == LOG_ALL)
+                                       log << TestLog::Message << "FAIL: got " << LogVecComps(resDerivate, numComps)
+                                                                                       << ", diff = " << LogVecComps(tcu::abs(reference - resDerivate), numComps)
+                                                                                       << ", at x = " << x << ", y = " << y
+                                               << TestLog::EndMessage;
+                               numFailedPixels += 1;
+                               errorMask.setPixel(tcu::RGBA::red().toVec(), x, y);
+                       }
+               }
+       }
+
+       if (numFailedPixels >= MAX_FAILED_MESSAGES && logPolicy == LOG_ALL)
+               log << TestLog::Message << "..." << TestLog::EndMessage;
+
+       if (numFailedPixels > 0 && logPolicy == LOG_ALL)
+               log << TestLog::Message << "FAIL: found " << numFailedPixels << " failed pixels" << TestLog::EndMessage;
+
+       return numFailedPixels == 0;
+}
+
+struct Linear2DFunctionEvaluator
+{
+       tcu::Matrix<float, 4, 3> matrix;
+
+       //      .-----.
+       //      | s_x |
+       //  M x | s_y |
+       //      | 1.0 |
+       //      '-----'
+       tcu::Vec4 evaluateAt (float screenX, float screenY) const;
+};
+
+tcu::Vec4 Linear2DFunctionEvaluator::evaluateAt (float screenX, float screenY) const
+{
+       const tcu::Vec3 position(screenX, screenY, 1.0f);
+       return matrix * position;
+}
+
+static bool reverifyConstantDerivateWithFlushRelaxations (tcu::TestLog&                                                        log,
+                                                                                                                 const tcu::ConstPixelBufferAccess&    result,
+                                                                                                                 const tcu::PixelBufferAccess&                 errorMask,
+                                                                                                                 glu::DataType                                                 dataType,
+                                                                                                                 glu::Precision                                                precision,
+                                                                                                                 const tcu::Vec4&                                              derivScale,
+                                                                                                                 const tcu::Vec4&                                              derivBias,
+                                                                                                                 const tcu::Vec4&                                              surfaceThreshold,
+                                                                                                                 DerivateFunc                                                  derivateFunc,
+                                                                                                                 const Linear2DFunctionEvaluator&              function)
+{
+       DE_ASSERT(result.getWidth() == errorMask.getWidth());
+       DE_ASSERT(result.getHeight() == errorMask.getHeight());
+       DE_ASSERT(isDfdxFunc(derivateFunc) || isDfdyFunc(derivateFunc));
+
+       const tcu::IVec4        red                                             (255, 0, 0, 255);
+       const tcu::IVec4        green                                   (0, 255, 0, 255);
+       const float                     divisionErrorUlps               = 2.5f;
+
+       const int                       numComponents                   = glu::getDataTypeFloatScalars(dataType);
+       const int                       numBits                                 = getNumMantissaBits(precision);
+       const int                       minExponent                             = getMinExponent(precision);
+
+       const int                       numVaryingSampleBits    = numBits - INTERPOLATION_LOST_BITS;
+       int                                     numFailedPixels                 = 0;
+
+       tcu::clear(errorMask, green);
+
+       // search for failed pixels
+       for (int y = 0; y < result.getHeight(); ++y)
+       for (int x = 0; x < result.getWidth(); ++x)
+       {
+               //                 flushToZero?(f2z?(functionValueCurrent) - f2z?(functionValueBefore))
+               // flushToZero? ( ------------------------------------------------------------------------ +- 2.5 ULP )
+               //                                                  dx
+
+               const tcu::Vec4 resultDerivative                = readDerivate(result, derivScale, derivBias, x, y);
+
+               // sample at the front of the back pixel and the back of the front pixel to cover the whole area of
+               // legal sample positions. In general case this is NOT OK, but we know that the target funtion is
+               // (mostly*) linear which allows us to take the sample points at arbitrary points. This gets us the
+               // maximum difference possible in exponents which are used in error bound calculations.
+               // * non-linearity may happen around zero or with very high function values due to subnorms not
+               //   behaving well.
+               const tcu::Vec4 functionValueForward    = (isDfdxFunc(derivateFunc))
+                                                                                                       ? (function.evaluateAt((float)x + 2.0f, (float)y + 0.5f))
+                                                                                                       : (function.evaluateAt((float)x + 0.5f, (float)y + 2.0f));
+               const tcu::Vec4 functionValueBackward   = (isDfdyFunc(derivateFunc))
+                                                                                                       ? (function.evaluateAt((float)x - 1.0f, (float)y + 0.5f))
+                                                                                                       : (function.evaluateAt((float)x + 0.5f, (float)y - 1.0f));
+
+               bool    anyComponentFailed                              = false;
+
+               // check components separately
+               for (int c = 0; c < numComponents; ++c)
+               {
+                       // Simulate interpolation. Add allowed interpolation error and round to target precision. Allow one half ULP (i.e. correct rounding)
+                       const tcu::Interval     forwardComponent                (convertFloatFlushToZeroRtn(addErrorUlp((float)functionValueForward[c],  -0.5f, numVaryingSampleBits), minExponent, numBits),
+                                                                                                                convertFloatFlushToZeroRtp(addErrorUlp((float)functionValueForward[c],  +0.5f, numVaryingSampleBits), minExponent, numBits));
+                       const tcu::Interval     backwardComponent               (convertFloatFlushToZeroRtn(addErrorUlp((float)functionValueBackward[c], -0.5f, numVaryingSampleBits), minExponent, numBits),
+                                                                                                                convertFloatFlushToZeroRtp(addErrorUlp((float)functionValueBackward[c], +0.5f, numVaryingSampleBits), minExponent, numBits));
+                       const int                       maxValueExp                             = de::max(de::max(tcu::Float32(forwardComponent.lo()).exponent(),   tcu::Float32(forwardComponent.hi()).exponent()),
+                                                                                                                                 de::max(tcu::Float32(backwardComponent.lo()).exponent(),  tcu::Float32(backwardComponent.hi()).exponent()));
+
+                       // subtraction in numerator will likely cause a cancellation of the most
+                       // significant bits. Apply error bounds.
+
+                       const tcu::Interval     numerator                               (forwardComponent - backwardComponent);
+                       const int                       numeratorLoExp                  = tcu::Float32(numerator.lo()).exponent();
+                       const int                       numeratorHiExp                  = tcu::Float32(numerator.hi()).exponent();
+                       const int                       numeratorLoBitsLost             = de::max(0, maxValueExp - numeratorLoExp); //!< must clamp to zero since if forward and backward components have different
+                       const int                       numeratorHiBitsLost             = de::max(0, maxValueExp - numeratorHiExp); //!< sign, numerator might have larger exponent than its operands.
+                       const int                       numeratorLoBits                 = de::max(0, numBits - numeratorLoBitsLost);
+                       const int                       numeratorHiBits                 = de::max(0, numBits - numeratorHiBitsLost);
+
+                       const tcu::Interval     numeratorRange                  (convertFloatFlushToZeroRtn((float)numerator.lo(), minExponent, numeratorLoBits),
+                                                                                                                convertFloatFlushToZeroRtp((float)numerator.hi(), minExponent, numeratorHiBits));
+
+                       const tcu::Interval     divisionRange                   = numeratorRange / 3.0f; // legal sample area is anywhere within this and neighboring pixels (i.e. size = 3)
+                       const tcu::Interval     divisionResultRange             (convertFloatFlushToZeroRtn(addErrorUlp((float)divisionRange.lo(), -divisionErrorUlps, numBits), minExponent, numBits),
+                                                                                                                convertFloatFlushToZeroRtp(addErrorUlp((float)divisionRange.hi(), +divisionErrorUlps, numBits), minExponent, numBits));
+                       const tcu::Interval     finalResultRange                (divisionResultRange.lo() - surfaceThreshold[c], divisionResultRange.hi() + surfaceThreshold[c]);
+
+                       if (resultDerivative[c] >= finalResultRange.lo() && resultDerivative[c] <= finalResultRange.hi())
+                       {
+                               // value ok
+                       }
+                       else
+                       {
+                               if (numFailedPixels < MAX_FAILED_MESSAGES)
+                                       log << tcu::TestLog::Message
+                                               << "Error in pixel at " << x << ", " << y << " with component " << c << " (channel " << ("rgba"[c]) << ")\n"
+                                               << "\tGot pixel value " << result.getPixelInt(x, y) << "\n"
+                                               << "\t\tdFd" << ((isDfdxFunc(derivateFunc)) ? ('x') : ('y')) << " ~= " << resultDerivative[c] << "\n"
+                                               << "\t\tdifference to a valid range: "
+                                                       << ((resultDerivative[c] < finalResultRange.lo()) ? ("-") : ("+"))
+                                                       << ((resultDerivative[c] < finalResultRange.lo()) ? (finalResultRange.lo() - resultDerivative[c]) : (resultDerivative[c] - finalResultRange.hi()))
+                                                       << "\n"
+                                               << "\tDerivative value range:\n"
+                                               << "\t\tMin: " << finalResultRange.lo() << "\n"
+                                               << "\t\tMax: " << finalResultRange.hi() << "\n"
+                                               << tcu::TestLog::EndMessage;
+
+                               ++numFailedPixels;
+                               anyComponentFailed = true;
+                       }
+               }
+
+               if (anyComponentFailed)
+                       errorMask.setPixel(red, x, y);
+       }
+
+       if (numFailedPixels >= MAX_FAILED_MESSAGES)
+               log << TestLog::Message << "..." << TestLog::EndMessage;
+
+       if (numFailedPixels > 0)
+               log << TestLog::Message << "FAIL: found " << numFailedPixels << " failed pixels" << TestLog::EndMessage;
+
+       return numFailedPixels == 0;
+}
+
+// TestCase utils
+
+struct DerivateCaseDefinition
+{
+       DerivateCaseDefinition (void)
+       {
+               func                            = DERIVATE_LAST;
+               dataType                        = glu::TYPE_LAST;
+               precision                       = glu::PRECISION_LAST;
+               coordDataType           = glu::TYPE_LAST;
+               coordPrecision          = glu::PRECISION_LAST;
+               surfaceType                     = SURFACETYPE_UNORM_FBO;
+               numSamples                      = 0;
+       }
+
+       DerivateFunc                    func;
+       glu::DataType                   dataType;
+       glu::Precision                  precision;
+
+       glu::DataType                   coordDataType;
+       glu::Precision                  coordPrecision;
+
+       SurfaceType                             surfaceType;
+       int                                             numSamples;
+};
+
+struct DerivateCaseValues
+{
+       tcu::Vec4       coordMin;
+       tcu::Vec4       coordMax;
+       tcu::Vec4       derivScale;
+       tcu::Vec4       derivBias;
+};
+
+struct TextureCaseValues
+{
+       tcu::Vec4       texValueMin;
+       tcu::Vec4       texValueMax;
+};
+
+class DerivateUniformSetup : public UniformSetup
+{
+public:
+                                               DerivateUniformSetup            (bool useSampler);
+       virtual                         ~DerivateUniformSetup           (void);
+
+       virtual void            setup                                           (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const;
+
+private:
+       const bool                      m_useSampler;
+};
+
+DerivateUniformSetup::DerivateUniformSetup (bool useSampler)
+       : m_useSampler(useSampler)
+{
+}
+
+DerivateUniformSetup::~DerivateUniformSetup (void)
+{
+}
+
+// TriangleDerivateCaseInstance
+
+class TriangleDerivateCaseInstance : public ShaderRenderCaseInstance
+{
+public:
+                                                                       TriangleDerivateCaseInstance    (Context&                                               context,
+                                                                                                                                        const UniformSetup&                    uniformSetup,
+                                                                                                                                        const DerivateCaseDefinition&  definitions,
+                                                                                                                                        const DerivateCaseValues&              values);
+       virtual                                                 ~TriangleDerivateCaseInstance   (void);
+       virtual tcu::TestStatus                 iterate                                                 (void);
+       DerivateCaseDefinition                  getDerivateCaseDefinition               (void) { return m_definitions; }
+       DerivateCaseValues                              getDerivateCaseValues                   (void) { return m_values; }
+
+protected:
+       virtual bool                                    verify                                                  (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask) = 0;
+       tcu::Vec4                                               getSurfaceThreshold                             (void) const;
+       virtual void                                    setupDefaultInputs                              (void);
+
+       const DerivateCaseDefinition&   m_definitions;
+       const DerivateCaseValues&               m_values;
+};
+
+static VkSampleCountFlagBits getVkSampleCount (int numSamples)
+{
+       switch (numSamples)
+       {
+               case 0:         return VK_SAMPLE_COUNT_1_BIT;
+               case 2:         return VK_SAMPLE_COUNT_2_BIT;
+               case 4:         return VK_SAMPLE_COUNT_4_BIT;
+               default:
+                       DE_ASSERT(false);
+                       return (VkSampleCountFlagBits)0;
+       }
+}
+
+TriangleDerivateCaseInstance::TriangleDerivateCaseInstance (Context&                                           context,
+                                                                                                                       const UniformSetup&                             uniformSetup,
+                                                                                                                       const DerivateCaseDefinition&   definitions,
+                                                                                                                       const DerivateCaseValues&               values)
+       : ShaderRenderCaseInstance      (context, true, DE_NULL, uniformSetup, DE_NULL)
+       , m_definitions                         (definitions)
+       , m_values                                      (values)
+{
+       m_renderSize    = tcu::UVec2(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+       m_colorFormat   = vk::mapTextureFormat(glu::mapGLInternalFormat(m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO ? GL_RGBA32UI : GL_RGBA8));
+
+       setSampleCount(getVkSampleCount(definitions.numSamples));
+}
+
+TriangleDerivateCaseInstance::~TriangleDerivateCaseInstance (void)
+{
+}
+
+tcu::Vec4 TriangleDerivateCaseInstance::getSurfaceThreshold (void) const
+{
+       switch (m_definitions.surfaceType)
+       {
+               case SURFACETYPE_UNORM_FBO:                             return tcu::IVec4(1).asFloat() / 255.0f;
+               case SURFACETYPE_FLOAT_FBO:                             return tcu::Vec4(0.0f);
+               default:
+                       DE_ASSERT(false);
+                       return tcu::Vec4(0.0f);
+       }
+}
+
+void TriangleDerivateCaseInstance::setupDefaultInputs (void)
+{
+       const int               numVertices                     = 4;
+       const float             positions[]                     =
+       {
+               -1.0f, -1.0f, 0.0f, 1.0f,
+               -1.0f,  1.0f, 0.0f, 1.0f,
+               1.0f, -1.0f, 0.0f, 1.0f,
+               1.0f,  1.0f, 0.0f, 1.0f
+       };
+       const float             coords[]                        =
+       {
+               m_values.coordMin.x(), m_values.coordMin.y(), m_values.coordMin.z(),                                                            m_values.coordMax.w(),
+               m_values.coordMin.x(), m_values.coordMax.y(), (m_values.coordMin.z()+m_values.coordMax.z())*0.5f,       (m_values.coordMin.w()+m_values.coordMax.w())*0.5f,
+               m_values.coordMax.x(), m_values.coordMin.y(), (m_values.coordMin.z()+m_values.coordMax.z())*0.5f,       (m_values.coordMin.w()+m_values.coordMax.w())*0.5f,
+               m_values.coordMax.x(), m_values.coordMax.y(), m_values.coordMax.z(),                                                            m_values.coordMin.w()
+       };
+
+       addAttribute(0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 4 * sizeof(float), numVertices, positions);
+       if (m_definitions.coordDataType != glu::TYPE_LAST)
+               addAttribute(1u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 4 * sizeof(float), numVertices, coords);
+}
+
+tcu::TestStatus TriangleDerivateCaseInstance::iterate (void)
+{
+       tcu::TestLog&                           log                             = m_context.getTestContext().getLog();
+       const deUint32                          numVertices             = 4;
+       const deUint32                          numTriangles    = 2;
+       const deUint16                          indices[]               = { 0, 2, 1, 2, 3, 1 };
+       tcu::TextureLevel                       resultImage;
+
+       setup();
+
+       render(numVertices, numTriangles, indices);
+
+       {
+               const tcu::TextureLevel&                renderedImage   = getResultImage();
+
+               if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
+               {
+                       const tcu::TextureFormat        dataFormat              (tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT);
+
+                       resultImage.setStorage(dataFormat, renderedImage.getWidth(), renderedImage.getHeight());
+                       tcu::copy(resultImage.getAccess(), tcu::ConstPixelBufferAccess(dataFormat, renderedImage.getSize(), renderedImage.getAccess().getDataPtr()));
+               }
+               else
+               {
+                       resultImage = renderedImage;
+               }
+       }
+
+       // Verify
+       {
+               tcu::Surface errorMask(resultImage.getWidth(), resultImage.getHeight());
+               tcu::clear(errorMask.getAccess(), tcu::RGBA::green().toVec());
+
+               const bool isOk = verify(resultImage.getAccess(), errorMask.getAccess());
+
+               log << TestLog::ImageSet("Result", "Result images")
+                       << TestLog::Image("Rendered", "Rendered image", resultImage);
+
+               if (!isOk)
+                       log << TestLog::Image("ErrorMask", "Error mask", errorMask);
+
+               log << TestLog::EndImageSet;
+
+               if (isOk)
+                       return tcu::TestStatus::pass("Pass");
+               else
+                       return tcu::TestStatus::fail("Image comparison failed");
+       }
+}
+
+void DerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
+{
+       DerivateCaseDefinition  definitions             = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseDefinition();
+       DerivateCaseValues              values                  = dynamic_cast<TriangleDerivateCaseInstance&>(instance).getDerivateCaseValues();
+
+       DE_ASSERT(glu::isDataTypeFloatOrVec(definitions.dataType));
+
+       instance.addUniform(0u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivScale.getPtr());
+       instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, glu::getDataTypeScalarSize(definitions.dataType) * sizeof(float), values.derivBias.getPtr());
+
+       if (m_useSampler)
+               instance.useSampler(2u, 0u); // To the uniform binding location 2 bind the texture 0
+}
+
+// TriangleDerivateCase
+
+class TriangleDerivateCase : public ShaderRenderCase
+{
+public:
+                                                                       TriangleDerivateCase    (tcu::TestContext&              testCtx,
+                                                                                                                        const std::string&             name,
+                                                                                                                        const std::string&             description,
+                                                                                                                        const UniformSetup*    uniformSetup);
+       virtual                                                 ~TriangleDerivateCase   (void);
+
+protected:
+       mutable DerivateCaseDefinition  m_definitions;
+       mutable DerivateCaseValues              m_values;
+};
+
+TriangleDerivateCase::TriangleDerivateCase (tcu::TestContext&          testCtx,
+                                                                                       const std::string&              name,
+                                                                                       const std::string&              description,
+                                                                                       const UniformSetup*             uniformSetup)
+       : ShaderRenderCase              (testCtx, name, description, false, (ShaderEvaluator*)DE_NULL, uniformSetup, DE_NULL)
+       , m_definitions                 ()
+{
+}
+
+TriangleDerivateCase::~TriangleDerivateCase (void)
+{
+}
+
+static std::string genVertexSource (glu::DataType coordType, glu::Precision precision)
+{
+       DE_ASSERT(coordType == glu::TYPE_LAST || glu::isDataTypeFloatOrVec(coordType));
+
+       const std::string vertexTmpl =
+               "#version 450\n"
+               "layout(location = 0) in highp vec4 a_position;\n"
+               + string(coordType != glu::TYPE_LAST ? "layout(location = 1) in ${PRECISION} ${DATATYPE} a_coord;\n"
+                                                                                          "layout(location = 0) out ${PRECISION} ${DATATYPE} v_coord;\n" : "") +
+               "void main (void)\n"
+               "{\n"
+               "       gl_Position = a_position;\n"
+               + string(coordType != glu::TYPE_LAST ? "        v_coord = a_coord;\n" : "") +
+               "}\n";
+
+       map<string, string> vertexParams;
+
+       if (coordType != glu::TYPE_LAST)
+       {
+               vertexParams["PRECISION"]       = glu::getPrecisionName(precision);
+               vertexParams["DATATYPE"]        = glu::getDataTypeName(coordType);
+       }
+
+       return tcu::StringTemplate(vertexTmpl).specialize(vertexParams);
+}
+
+// ConstantDerivateCaseInstance
+
+class ConstantDerivateCaseInstance : public TriangleDerivateCaseInstance
+{
+public:
+                                                               ConstantDerivateCaseInstance    (Context&                                               context,
+                                                                                                                                const UniformSetup&                    uniformSetup,
+                                                                                                                                const DerivateCaseDefinition&  definitions,
+                                                                                                                                const DerivateCaseValues&              values);
+       virtual                                         ~ConstantDerivateCaseInstance   (void);
+
+       virtual bool                            verify                                                  (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
+};
+
+ConstantDerivateCaseInstance::ConstantDerivateCaseInstance (Context&                                                   context,
+                                                                                                                       const UniformSetup&                                     uniformSetup,
+                                                                                                                       const DerivateCaseDefinition&           definitions,
+                                                                                                                       const DerivateCaseValues&                       values)
+       : TriangleDerivateCaseInstance  (context, uniformSetup, definitions, values)
+{
+}
+
+ConstantDerivateCaseInstance::~ConstantDerivateCaseInstance (void)
+{
+}
+
+bool ConstantDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
+{
+       const tcu::Vec4 reference       (0.0f); // Derivate of constant argument should always be 0
+       const tcu::Vec4 threshold       = getSurfaceThreshold() / abs(m_values.derivScale);
+
+       return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
+                                                                 reference, threshold, m_values.derivScale, m_values.derivBias);
+}
+
+// ConstantDerivateCase
+
+class ConstantDerivateCase : public TriangleDerivateCase
+{
+public:
+                                                       ConstantDerivateCase            (tcu::TestContext&              testCtx,
+                                                                                                                const std::string&             name,
+                                                                                                                const std::string&             description,
+                                                                                                                DerivateFunc                   func,
+                                                                                                                glu::DataType                  type);
+       virtual                                 ~ConstantDerivateCase           (void);
+
+       virtual void                    initPrograms                            (vk::SourceCollections& programCollection) const;
+       virtual TestInstance*   createInstance                          (Context& context) const;
+};
+
+ConstantDerivateCase::ConstantDerivateCase (tcu::TestContext&          testCtx,
+                                                                                       const std::string&              name,
+                                                                                       const std::string&              description,
+                                                                                       DerivateFunc                    func,
+                                                                                       glu::DataType                   type)
+       : TriangleDerivateCase  (testCtx, name, description, new DerivateUniformSetup(false))
+{
+       m_definitions.func                              = func;
+       m_definitions.dataType                  = type;
+       m_definitions.precision                 = glu::PRECISION_HIGHP;
+}
+
+ConstantDerivateCase::~ConstantDerivateCase (void)
+{
+}
+
+TestInstance* ConstantDerivateCase::createInstance (Context& context) const
+{
+       DE_ASSERT(m_uniformSetup != DE_NULL);
+       return new ConstantDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
+}
+
+void ConstantDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       const char* fragmentTmpl =
+               "#version 450\n"
+               "layout(location = 0) out mediump vec4 o_color;\n"
+               "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+               "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; }; \n"
+               "void main (void)\n"
+               "{\n"
+               "       ${PRECISION} ${DATATYPE} res = ${FUNC}(${VALUE}) * u_scale + u_bias;\n"
+               "       o_color = ${CAST_TO_OUTPUT};\n"
+               "}\n";
+
+       map<string, string> fragmentParams;
+       fragmentParams["PRECISION"]                     = glu::getPrecisionName(m_definitions.precision);
+       fragmentParams["DATATYPE"]                      = glu::getDataTypeName(m_definitions.dataType);
+       fragmentParams["FUNC"]                          = getDerivateFuncName(m_definitions.func);
+       fragmentParams["VALUE"]                         = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "vec4(1.0, 7.2, -1e5, 0.0)" :
+                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec3(1e2, 8.0, 0.01)" :
+                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec2(-0.0, 2.7)" :
+                                                                                 /* TYPE_FLOAT */                                                                 "7.7";
+       fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
+                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
+                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
+                                                                                 /* TYPE_FLOAT */                                                                 "vec4(res, 0.0, 0.0, 1.0)";
+
+       std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
+       programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
+       programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
+
+       m_values.derivScale             = tcu::Vec4(1e3f, 1e3f, 1e3f, 1e3f);
+       m_values.derivBias              = tcu::Vec4(0.5f, 0.5f, 0.5f, 0.5f);
+}
+
+// Linear cases
+
+class LinearDerivateUniformSetup : public DerivateUniformSetup
+{
+public:
+                                       LinearDerivateUniformSetup              (bool useSampler, BaseUniformType usedDefaultUniform);
+       virtual                 ~LinearDerivateUniformSetup             (void);
+
+       virtual void    setup                                                   (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const;
+
+private:
+       const BaseUniformType   m_usedDefaultUniform;
+};
+
+LinearDerivateUniformSetup::LinearDerivateUniformSetup (bool useSampler, BaseUniformType usedDefaultUniform)
+       : DerivateUniformSetup  (useSampler)
+       , m_usedDefaultUniform  (usedDefaultUniform)
+{
+}
+
+LinearDerivateUniformSetup::~LinearDerivateUniformSetup (void)
+{
+}
+
+void LinearDerivateUniformSetup::setup (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) const
+{
+       DerivateUniformSetup::setup(instance, constCoords);
+
+       if (m_usedDefaultUniform != U_LAST)
+               switch (m_usedDefaultUniform)
+               {
+                       case UB_TRUE:
+                       case UI_ONE:
+                       case UI_TWO:
+                               instance.useUniform(2u, m_usedDefaultUniform);
+                               break;
+                       default:
+                               DE_ASSERT(false);
+                               break;
+               }
+}
+
+class LinearDerivateCaseInstance : public TriangleDerivateCaseInstance
+{
+public:
+                                                               LinearDerivateCaseInstance      (Context&                                               context,
+                                                                                                                        const UniformSetup&                    uniformSetup,
+                                                                                                                        const DerivateCaseDefinition&  definitions,
+                                                                                                                        const DerivateCaseValues&              values);
+       virtual                                         ~LinearDerivateCaseInstance     (void);
+
+       virtual bool                            verify                                          (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
+};
+
+LinearDerivateCaseInstance::LinearDerivateCaseInstance (Context&                                               context,
+                                                                                                               const UniformSetup&                             uniformSetup,
+                                                                                                               const DerivateCaseDefinition&   definitions,
+                                                                                                               const DerivateCaseValues&               values)
+       : TriangleDerivateCaseInstance  (context, uniformSetup, definitions, values)
+{
+}
+
+LinearDerivateCaseInstance::~LinearDerivateCaseInstance (void)
+{
+}
+
+bool LinearDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
+{
+       const tcu::Vec4         xScale                          = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
+       const tcu::Vec4         yScale                          = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
+       const tcu::Vec4         surfaceThreshold        = getSurfaceThreshold() / abs(m_values.derivScale);
+
+       if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
+       {
+               const bool                      isX                     = isDfdxFunc(m_definitions.func);
+               const float                     div                     = isX ? float(result.getWidth()) : float(result.getHeight());
+               const tcu::Vec4         scale           = isX ? xScale : yScale;
+               const tcu::Vec4         reference       = ((m_values.coordMax - m_values.coordMin) / div) * scale;
+               const tcu::Vec4         opThreshold     = getDerivateThreshold(m_definitions.precision, m_values.coordMin*scale, m_values.coordMax*scale, reference);
+               const tcu::Vec4         threshold       = max(surfaceThreshold, opThreshold);
+               const int                       numComps        = glu::getDataTypeFloatScalars(m_definitions.dataType);
+
+               m_context.getTestContext().getLog()
+                       << tcu::TestLog::Message
+                       << "Verifying result image.\n"
+                       << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
+                       << tcu::TestLog::EndMessage;
+
+               // short circuit if result is strictly within the normal value error bounds.
+               // This improves performance significantly.
+               if (verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
+                                                                  reference, threshold, m_values.derivScale, m_values.derivBias,
+                                                                  LOG_NOTHING))
+               {
+                       m_context.getTestContext().getLog()
+                               << tcu::TestLog::Message
+                               << "No incorrect derivatives found, result valid."
+                               << tcu::TestLog::EndMessage;
+
+                       return true;
+               }
+
+               // some pixels exceed error bounds calculated for normal values. Verify that these
+               // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
+
+               m_context.getTestContext().getLog()
+                       << tcu::TestLog::Message
+                       << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
+                       << "\tVerifying each result derivative is within its range of legal result values."
+                       << tcu::TestLog::EndMessage;
+
+               {
+                       const tcu::UVec2                        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+                       const float                                     w                               = float(viewportSize.x());
+                       const float                                     h                               = float(viewportSize.y());
+                       const tcu::Vec4                         valueRamp               = (m_values.coordMax - m_values.coordMin);
+                       Linear2DFunctionEvaluator       function;
+
+                       function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_values.coordMin.x()));
+                       function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_values.coordMin.y()));
+                       function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_values.coordMin.z() + m_values.coordMin.z()) / 2.0f);
+                       function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_values.coordMax.w() + m_values.coordMax.w()) / 2.0f);
+
+                       return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), result, errorMask,
+                                                                                                                               m_definitions.dataType, m_definitions.precision, m_values.derivScale,
+                                                                                                                               m_values.derivBias, surfaceThreshold, m_definitions.func,
+                                                                                                                               function);
+               }
+       }
+       else
+       {
+               DE_ASSERT(isFwidthFunc(m_definitions.func));
+               const float                     w                       = float(result.getWidth());
+               const float                     h                       = float(result.getHeight());
+
+               const tcu::Vec4         dx                      = ((m_values.coordMax - m_values.coordMin) / w) * xScale;
+               const tcu::Vec4         dy                      = ((m_values.coordMax - m_values.coordMin) / h) * yScale;
+               const tcu::Vec4         reference       = tcu::abs(dx) + tcu::abs(dy);
+               const tcu::Vec4         dxThreshold     = getDerivateThreshold(m_definitions.precision, m_values.coordMin*xScale, m_values.coordMax*xScale, dx);
+               const tcu::Vec4         dyThreshold     = getDerivateThreshold(m_definitions.precision, m_values.coordMin*yScale, m_values.coordMax*yScale, dy);
+               const tcu::Vec4         threshold       = max(surfaceThreshold, max(dxThreshold, dyThreshold));
+
+               return verifyConstantDerivate(m_context.getTestContext().getLog(), result, errorMask, m_definitions.dataType,
+                                                                         reference, threshold, m_values.derivScale, m_values.derivBias);
+       }
+}
+
+// LinearDerivateCase
+
+class LinearDerivateCase : public TriangleDerivateCase
+{
+public:
+                                                       LinearDerivateCase                      (tcu::TestContext&              testCtx,
+                                                                                                                const std::string&             name,
+                                                                                                                const std::string&             description,
+                                                                                                                DerivateFunc                   func,
+                                                                                                                glu::DataType                  type,
+                                                                                                                glu::Precision                 precision,
+                                                                                                                SurfaceType                    surfaceType,
+                                                                                                                int                                    numSamples,
+                                                                                                                const std::string&             fragmentSrcTmpl,
+                                                                                                                BaseUniformType                usedDefaultUniform);
+       virtual                                 ~LinearDerivateCase                     (void);
+
+       virtual void                    initPrograms                            (vk::SourceCollections& programCollection) const;
+       virtual TestInstance*   createInstance                          (Context& context) const;
+
+private:
+       const std::string               m_fragmentTmpl;
+};
+
+LinearDerivateCase::LinearDerivateCase (tcu::TestContext&              testCtx,
+                                                                               const std::string&              name,
+                                                                               const std::string&              description,
+                                                                               DerivateFunc                    func,
+                                                                               glu::DataType                   type,
+                                                                               glu::Precision                  precision,
+                                                                               SurfaceType                             surfaceType,
+                                                                               int                                             numSamples,
+                                                                               const std::string&              fragmentSrcTmpl,
+                                                                               BaseUniformType                 usedDefaultUniform)
+       : TriangleDerivateCase  (testCtx, name, description, new LinearDerivateUniformSetup(false, usedDefaultUniform))
+       , m_fragmentTmpl                (fragmentSrcTmpl)
+{
+       m_definitions.func                              = func;
+       m_definitions.dataType                  = type;
+       m_definitions.precision                 = precision;
+       m_definitions.coordDataType             = m_definitions.dataType;
+       m_definitions.coordPrecision    = m_definitions.precision;
+       m_definitions.surfaceType               = surfaceType;
+       m_definitions.numSamples                = numSamples;
+}
+
+LinearDerivateCase::~LinearDerivateCase (void)
+{
+}
+
+TestInstance* LinearDerivateCase::createInstance (Context& context) const
+{
+       DE_ASSERT(m_uniformSetup != DE_NULL);
+       return new LinearDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values);
+}
+
+void LinearDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       const tcu::UVec2        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+       const float                     w                               = float(viewportSize.x());
+       const float                     h                               = float(viewportSize.y());
+       const bool                      packToInt               = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
+       map<string, string>     fragmentParams;
+
+       fragmentParams["OUTPUT_TYPE"]           = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
+       fragmentParams["OUTPUT_PREC"]           = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
+       fragmentParams["PRECISION"]                     = glu::getPrecisionName(m_definitions.precision);
+       fragmentParams["DATATYPE"]                      = glu::getDataTypeName(m_definitions.dataType);
+       fragmentParams["FUNC"]                          = getDerivateFuncName(m_definitions.func);
+
+       if (packToInt)
+       {
+               fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
+                                                                                         m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
+                                                                                         m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
+                                                                                         /* TYPE_FLOAT */                                                                 "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
+       }
+       else
+       {
+               fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
+                                                                                         m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
+                                                                                         m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
+                                                                                         /* TYPE_FLOAT */                                                                 "vec4(res, 0.0, 0.0, 1.0)";
+       }
+
+       std::string fragmentSrc = tcu::StringTemplate(m_fragmentTmpl).specialize(fragmentParams);
+       programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
+       programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
+
+       switch (m_definitions.precision)
+       {
+               case glu::PRECISION_HIGHP:
+                       m_values.coordMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
+                       m_values.coordMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
+                       break;
+
+               case glu::PRECISION_MEDIUMP:
+                       m_values.coordMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
+                       m_values.coordMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
+                       break;
+
+               case glu::PRECISION_LOWP:
+                       m_values.coordMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
+                       m_values.coordMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
+       {
+               // No scale or bias used for accuracy.
+               m_values.derivScale     = tcu::Vec4(1.0f);
+               m_values.derivBias              = tcu::Vec4(0.0f);
+       }
+       else
+       {
+               // Compute scale - bias that normalizes to 0..1 range.
+               const tcu::Vec4 dx = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
+               const tcu::Vec4 dy = (m_values.coordMax - m_values.coordMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
+
+               if (isDfdxFunc(m_definitions.func))
+                       m_values.derivScale = 0.5f / dx;
+               else if (isDfdyFunc(m_definitions.func))
+                       m_values.derivScale = 0.5f / dy;
+               else if (isFwidthFunc(m_definitions.func))
+                       m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
+               else
+                       DE_ASSERT(false);
+
+               m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
+       }
+}
+
+// TextureDerivateCaseInstance
+
+class TextureDerivateCaseInstance : public TriangleDerivateCaseInstance
+{
+public:
+                                                               TextureDerivateCaseInstance             (Context&                                                       context,
+                                                                                                                                const UniformSetup&                            uniformSetup,
+                                                                                                                                const DerivateCaseDefinition&          definitions,
+                                                                                                                                const DerivateCaseValues&                      values,
+                                                                                                                                const TextureCaseValues&                       textureValues);
+       virtual                                         ~TextureDerivateCaseInstance    (void);
+
+       virtual bool                            verify                                                  (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask);
+
+private:
+       const TextureCaseValues&        m_textureValues;
+};
+
+TextureDerivateCaseInstance::TextureDerivateCaseInstance (Context&                                                     context,
+                                                                                                                 const UniformSetup&                           uniformSetup,
+                                                                                                                 const DerivateCaseDefinition&         definitions,
+                                                                                                                 const DerivateCaseValues&                     values,
+                                                                                                                 const TextureCaseValues&                      textureValues)
+       : TriangleDerivateCaseInstance  (context, uniformSetup, definitions, values)
+       , m_textureValues                               (textureValues)
+{
+       de::MovePtr<tcu::Texture2D>             texture;
+
+       // Lowp and mediump cases use RGBA16F format, while highp uses RGBA32F.
+       {
+               const tcu::UVec2                        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+               const tcu::TextureFormat        format                  = glu::mapGLInternalFormat(m_definitions.precision == glu::PRECISION_HIGHP ? GL_RGBA32F : GL_RGBA16F);
+
+               texture = de::MovePtr<tcu::Texture2D>(new tcu::Texture2D(format, viewportSize.x(), viewportSize.y()));
+               texture->allocLevel(0);
+       }
+
+       // Fill with gradients.
+       {
+               const tcu::PixelBufferAccess level0 = texture->getLevel(0);
+               for (int y = 0; y < level0.getHeight(); y++)
+               {
+                       for (int x = 0; x < level0.getWidth(); x++)
+                       {
+                               const float             xf              = (float(x)+0.5f) / float(level0.getWidth());
+                               const float             yf              = (float(y)+0.5f) / float(level0.getHeight());
+                               const tcu::Vec4 s               = tcu::Vec4(xf, yf, (xf+yf)/2.0f, 1.0f - (xf+yf)/2.0f);
+
+                               level0.setPixel(m_textureValues.texValueMin + (m_textureValues.texValueMax - m_textureValues.texValueMin)*s, x, y);
+                       }
+               }
+       }
+
+       de::SharedPtr<TextureBinding>   testTexture             (new TextureBinding(texture.release(),
+                                                                                                                                               tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE,
+                                                                                                                                                                        tcu::Sampler::CLAMP_TO_EDGE,
+                                                                                                                                                                        tcu::Sampler::CLAMP_TO_EDGE,
+                                                                                                                                                                        tcu::Sampler::NEAREST,
+                                                                                                                                                                        tcu::Sampler::NEAREST)));
+       m_textures.push_back(testTexture);
+}
+
+TextureDerivateCaseInstance::~TextureDerivateCaseInstance (void)
+{
+}
+
+bool TextureDerivateCaseInstance::verify (const tcu::ConstPixelBufferAccess& result, const tcu::PixelBufferAccess& errorMask)
+{
+       // \note Edges are ignored in comparison
+       if (result.getWidth() < 2 || result.getHeight() < 2)
+               throw tcu::NotSupportedError("Too small viewport");
+
+       tcu::ConstPixelBufferAccess     compareArea                     = tcu::getSubregion(result, 1, 1, result.getWidth()-2, result.getHeight()-2);
+       tcu::PixelBufferAccess          maskArea                        = tcu::getSubregion(errorMask, 1, 1, errorMask.getWidth()-2, errorMask.getHeight()-2);
+       const tcu::Vec4                         xScale                          = tcu::Vec4(1.0f, 0.0f, 0.5f, -0.5f);
+       const tcu::Vec4                         yScale                          = tcu::Vec4(0.0f, 1.0f, 0.5f, -0.5f);
+       const float                                     w                                       = float(result.getWidth());
+       const float                                     h                                       = float(result.getHeight());
+
+       const tcu::Vec4                         surfaceThreshold        = getSurfaceThreshold() / abs(m_values.derivScale);
+
+       if (isDfdxFunc(m_definitions.func) || isDfdyFunc(m_definitions.func))
+       {
+               const bool                      isX                     = isDfdxFunc(m_definitions.func);
+               const float                     div                     = isX ? w : h;
+               const tcu::Vec4         scale           = isX ? xScale : yScale;
+               const tcu::Vec4         reference       = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / div) * scale;
+               const tcu::Vec4         opThreshold     = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*scale, m_textureValues.texValueMax*scale, reference);
+               const tcu::Vec4         threshold       = max(surfaceThreshold, opThreshold);
+               const int                       numComps        = glu::getDataTypeFloatScalars(m_definitions.dataType);
+
+               m_context.getTestContext().getLog()
+                       << tcu::TestLog::Message
+                       << "Verifying result image.\n"
+                       << "\tValid derivative is " << LogVecComps(reference, numComps) << " with threshold " << LogVecComps(threshold, numComps)
+                       << tcu::TestLog::EndMessage;
+
+               // short circuit if result is strictly within the normal value error bounds.
+               // This improves performance significantly.
+               if (verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
+                                                                  reference, threshold, m_values.derivScale, m_values.derivBias,
+                                                                  LOG_NOTHING))
+               {
+                       m_context.getTestContext().getLog()
+                               << tcu::TestLog::Message
+                               << "No incorrect derivatives found, result valid."
+                               << tcu::TestLog::EndMessage;
+
+                       return true;
+               }
+
+               // some pixels exceed error bounds calculated for normal values. Verify that these
+               // potentially invalid pixels are in fact valid due to (for example) subnorm flushing.
+
+               m_context.getTestContext().getLog()
+                       << tcu::TestLog::Message
+                       << "Initial verification failed, verifying image by calculating accurate error bounds for each result pixel.\n"
+                       << "\tVerifying each result derivative is within its range of legal result values."
+                       << tcu::TestLog::EndMessage;
+
+               {
+                       const tcu::Vec4                         valueRamp               = (m_textureValues.texValueMax - m_textureValues.texValueMin);
+                       Linear2DFunctionEvaluator       function;
+
+                       function.matrix.setRow(0, tcu::Vec3(valueRamp.x() / w, 0.0f, m_textureValues.texValueMin.x()));
+                       function.matrix.setRow(1, tcu::Vec3(0.0f, valueRamp.y() / h, m_textureValues.texValueMin.y()));
+                       function.matrix.setRow(2, tcu::Vec3(valueRamp.z() / w, valueRamp.z() / h, m_textureValues.texValueMin.z() + m_textureValues.texValueMin.z()) / 2.0f);
+                       function.matrix.setRow(3, tcu::Vec3(-valueRamp.w() / w, -valueRamp.w() / h, m_textureValues.texValueMax.w() + m_textureValues.texValueMax.w()) / 2.0f);
+
+                       return reverifyConstantDerivateWithFlushRelaxations(m_context.getTestContext().getLog(), compareArea, maskArea,
+                                                                                                                               m_definitions.dataType, m_definitions.precision, m_values.derivScale,
+                                                                                                                               m_values.derivBias, surfaceThreshold, m_definitions.func,
+                                                                                                                               function);
+               }
+       }
+       else
+       {
+               DE_ASSERT(isFwidthFunc(m_definitions.func));
+               const tcu::Vec4 dx                      = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / w) * xScale;
+               const tcu::Vec4 dy                      = ((m_textureValues.texValueMax - m_textureValues.texValueMin) / h) * yScale;
+               const tcu::Vec4 reference       = tcu::abs(dx) + tcu::abs(dy);
+               const tcu::Vec4 dxThreshold     = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*xScale, m_textureValues.texValueMax*xScale, dx);
+               const tcu::Vec4 dyThreshold     = getDerivateThreshold(m_definitions.precision, m_textureValues.texValueMin*yScale, m_textureValues.texValueMax*yScale, dy);
+               const tcu::Vec4 threshold       = max(surfaceThreshold, max(dxThreshold, dyThreshold));
+
+               return verifyConstantDerivate(m_context.getTestContext().getLog(), compareArea, maskArea, m_definitions.dataType,
+                                                                         reference, threshold, m_values.derivScale, m_values.derivBias);
+       }
+}
+
+// TextureDerivateCase
+
+class TextureDerivateCase : public TriangleDerivateCase
+{
+public:
+                                                       TextureDerivateCase                     (tcu::TestContext&              testCtx,
+                                                                                                                const std::string&             name,
+                                                                                                                const std::string&             description,
+                                                                                                                DerivateFunc                   func,
+                                                                                                                glu::DataType                  type,
+                                                                                                                glu::Precision                 precision,
+                                                                                                                SurfaceType                    surfaceType,
+                                                                                                                int                                    numSamples);
+       virtual                                 ~TextureDerivateCase            (void);
+
+       virtual void                    initPrograms                            (vk::SourceCollections& programCollection) const;
+       virtual TestInstance*   createInstance                          (Context& context) const;
+
+private:
+       mutable TextureCaseValues       m_textureValues;
+};
+
+TextureDerivateCase::TextureDerivateCase (tcu::TestContext&            testCtx,
+                                                                                 const std::string&    name,
+                                                                                 const std::string&    description,
+                                                                                 DerivateFunc                  func,
+                                                                                 glu::DataType                 type,
+                                                                                 glu::Precision                precision,
+                                                                                 SurfaceType                   surfaceType,
+                                                                                 int                                   numSamples)
+       : TriangleDerivateCase  (testCtx, name, description, new DerivateUniformSetup(true))
+{
+       m_definitions.dataType                  = type;
+       m_definitions.func                              = func;
+       m_definitions.precision                 = precision;
+       m_definitions.coordDataType             = glu::TYPE_FLOAT_VEC2;
+       m_definitions.coordPrecision    = glu::PRECISION_HIGHP;
+       m_definitions.surfaceType               = surfaceType;
+       m_definitions.numSamples                = numSamples;
+}
+
+TextureDerivateCase::~TextureDerivateCase (void)
+{
+}
+
+TestInstance* TextureDerivateCase::createInstance (Context& context) const
+{
+       DE_ASSERT(m_uniformSetup != DE_NULL);
+       return new TextureDerivateCaseInstance(context, *m_uniformSetup, m_definitions, m_values, m_textureValues);
+}
+
+void TextureDerivateCase::initPrograms (vk::SourceCollections& programCollection) const
+{
+       // Generate shader
+       {
+               const char* fragmentTmpl =
+                       "#version 450\n"
+                       "layout(location = 0) in highp vec2 v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "layout(binding = 2) uniform ${PRECISION} sampler2D u_sampler;\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} vec4 tex = texture(u_sampler, v_coord);\n"
+                       "       ${PRECISION} ${DATATYPE} res = ${FUNC}(tex${SWIZZLE}) * u_scale + u_bias;\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n";
+
+               const bool                      packToInt               = m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO;
+               map<string, string> fragmentParams;
+
+               fragmentParams["OUTPUT_TYPE"]           = glu::getDataTypeName(packToInt ? glu::TYPE_UINT_VEC4 : glu::TYPE_FLOAT_VEC4);
+               fragmentParams["OUTPUT_PREC"]           = glu::getPrecisionName(packToInt ? glu::PRECISION_HIGHP : m_definitions.precision);
+               fragmentParams["PRECISION"]                     = glu::getPrecisionName(m_definitions.precision);
+               fragmentParams["DATATYPE"]                      = glu::getDataTypeName(m_definitions.dataType);
+               fragmentParams["FUNC"]                          = getDerivateFuncName(m_definitions.func);
+               fragmentParams["SWIZZLE"]                       = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "" :
+                                                                                         m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? ".xyz" :
+                                                                                         m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? ".xy" :
+                                                                                         /* TYPE_FLOAT */                                                                 ".x";
+
+               if (packToInt)
+               {
+                       fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "floatBitsToUint(res)" :
+                                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "floatBitsToUint(vec4(res, 1.0))" :
+                                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "floatBitsToUint(vec4(res, 0.0, 1.0))" :
+                                                                                                 /* TYPE_FLOAT */                                                                 "floatBitsToUint(vec4(res, 0.0, 0.0, 1.0))";
+               }
+               else
+               {
+                       fragmentParams["CAST_TO_OUTPUT"]        = m_definitions.dataType == glu::TYPE_FLOAT_VEC4 ? "res" :
+                                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC3 ? "vec4(res, 1.0)" :
+                                                                                                 m_definitions.dataType == glu::TYPE_FLOAT_VEC2 ? "vec4(res, 0.0, 1.0)" :
+                                                                                                 /* TYPE_FLOAT */                                                                 "vec4(res, 0.0, 0.0, 1.0)";
+               }
+
+               std::string fragmentSrc = tcu::StringTemplate(fragmentTmpl).specialize(fragmentParams);
+               programCollection.glslSources.add("vert") << glu::VertexSource(genVertexSource(m_definitions.coordDataType, m_definitions.coordPrecision));
+               programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
+       }
+
+       // Texture size matches viewport and nearest sampling is used. Thus texture sampling
+       // is equal to just interpolating the texture value range.
+
+       // Determine value range for texture.
+
+       switch (m_definitions.precision)
+       {
+               case glu::PRECISION_HIGHP:
+                       m_textureValues.texValueMin = tcu::Vec4(-97.f, 0.2f, 71.f, 74.f);
+                       m_textureValues.texValueMax = tcu::Vec4(-13.2f, -77.f, 44.f, 76.f);
+                       break;
+
+               case glu::PRECISION_MEDIUMP:
+                       m_textureValues.texValueMin = tcu::Vec4(-37.0f, 47.f, -7.f, 0.0f);
+                       m_textureValues.texValueMax = tcu::Vec4(-1.0f, 12.f, 7.f, 19.f);
+                       break;
+
+               case glu::PRECISION_LOWP:
+                       m_textureValues.texValueMin = tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f);
+                       m_textureValues.texValueMax = tcu::Vec4(1.0f, 1.0f, -1.0f, -1.0f);
+                       break;
+
+               default:
+                       DE_ASSERT(false);
+       }
+
+       // Texture coordinates
+       m_values.coordMin = tcu::Vec4(0.0f);
+       m_values.coordMax = tcu::Vec4(1.0f);
+
+       if (m_definitions.surfaceType == SURFACETYPE_FLOAT_FBO)
+       {
+               // No scale or bias used for accuracy.
+               m_values.derivScale             = tcu::Vec4(1.0f);
+               m_values.derivBias              = tcu::Vec4(0.0f);
+       }
+       else
+       {
+               // Compute scale - bias that normalizes to 0..1 range.
+               const tcu::UVec2        viewportSize    (VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
+               const float                     w                               = float(viewportSize.x());
+               const float                     h                               = float(viewportSize.y());
+               const tcu::Vec4         dx                              = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(w, w, w*0.5f, -w*0.5f);
+               const tcu::Vec4         dy                              = (m_textureValues.texValueMax - m_textureValues.texValueMin) / tcu::Vec4(h, h, h*0.5f, -h*0.5f);
+
+               if (isDfdxFunc(m_definitions.func))
+                       m_values.derivScale = 0.5f / dx;
+               else if (isDfdyFunc(m_definitions.func))
+                       m_values.derivScale = 0.5f / dy;
+               else if (isFwidthFunc(m_definitions.func))
+                       m_values.derivScale = 0.5f / (tcu::abs(dx) + tcu::abs(dy));
+               else
+                       DE_ASSERT(false);
+
+               m_values.derivBias = tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f);
+       }
+}
+
+// ShaderDerivateTests
+
+class ShaderDerivateTests : public tcu::TestCaseGroup
+{
+public:
+                                                       ShaderDerivateTests             (tcu::TestContext& testCtx);
+       virtual                                 ~ShaderDerivateTests    (void);
+
+       virtual void                    init                                    (void);
+
+private:
+                                                       ShaderDerivateTests             (const ShaderDerivateTests&);           // not allowed!
+       ShaderDerivateTests&    operator=                               (const ShaderDerivateTests&);           // not allowed!
+};
+
+ShaderDerivateTests::ShaderDerivateTests (tcu::TestContext& testCtx)
+       : TestCaseGroup(testCtx, "derivate", "Derivate Function Tests")
+{
+}
+
+ShaderDerivateTests::~ShaderDerivateTests (void)
+{
+}
+
+struct FunctionSpec
+{
+       std::string             name;
+       DerivateFunc    function;
+       glu::DataType   dataType;
+       glu::Precision  precision;
+
+       FunctionSpec (const std::string& name_, DerivateFunc function_, glu::DataType dataType_, glu::Precision precision_)
+               : name          (name_)
+               , function      (function_)
+               , dataType      (dataType_)
+               , precision     (precision_)
+       {
+       }
+};
+
+void ShaderDerivateTests::init (void)
+{
+       static const struct
+       {
+               const char*                     name;
+               const char*                     description;
+               const char*                     source;
+               BaseUniformType         usedDefaultUniform;
+       } s_linearDerivateCases[] =
+       {
+               {
+                       "linear",
+                       "Basic derivate of linearly interpolated argument",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       U_LAST
+               },
+               {
+                       "in_function",
+                       "Derivate of linear function argument",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "\n"
+                       "${PRECISION} ${DATATYPE} computeRes (${PRECISION} ${DATATYPE} value)\n"
+                       "{\n"
+                       "       return ${FUNC}(v_coord) * u_scale + u_bias;\n"
+                       "}\n"
+                       "\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res = computeRes(v_coord);\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       U_LAST
+               },
+               {
+                       "static_if",
+                       "Derivate of linearly interpolated value in static if",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res;\n"
+                       "       if (false)\n"
+                       "               res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
+                       "       else\n"
+                       "               res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       U_LAST
+               },
+               {
+                       "static_loop",
+                       "Derivate of linearly interpolated value in static loop",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
+                       "       for (int i = 0; i < 2; i++)\n"
+                       "               res += ${FUNC}(v_coord * float(i));\n"
+                       "       res = res * u_scale + u_bias;\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       U_LAST
+               },
+               {
+                       "static_switch",
+                       "Derivate of linearly interpolated value in static switch",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res;\n"
+                       "       switch (1)\n"
+                       "       {\n"
+                       "               case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias;     break;\n"
+                       "               case 1: res = ${FUNC}(v_coord) * u_scale + u_bias;      break;\n"
+                       "       }\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       U_LAST
+               },
+               {
+                       "uniform_if",
+                       "Derivate of linearly interpolated value in uniform if",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "layout(binding = 2, std140) uniform Ui_true { bool ub_true; };\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res;\n"
+                       "       if (ub_true)"
+                       "               res = ${FUNC}(v_coord) * u_scale + u_bias;\n"
+                       "       else\n"
+                       "               res = ${FUNC}(-v_coord) * u_scale + u_bias;\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       UB_TRUE
+               },
+               {
+                       "uniform_loop",
+                       "Derivate of linearly interpolated value in uniform loop",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "layout(binding = 2, std140) uniform Ui_two { int ui_two; };\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res = ${DATATYPE}(0.0);\n"
+                       "       for (int i = 0; i < ui_two; i++)\n"
+                       "               res += ${FUNC}(v_coord * float(i));\n"
+                       "       res = res * u_scale + u_bias;\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       UI_TWO
+               },
+               {
+                       "uniform_switch",
+                       "Derivate of linearly interpolated value in uniform switch",
+
+                       "#version 450\n"
+                       "layout(location = 0) in ${PRECISION} ${DATATYPE} v_coord;\n"
+                       "layout(location = 0) out ${OUTPUT_PREC} ${OUTPUT_TYPE} o_color;\n"
+                       "layout(binding = 0, std140) uniform Scale { ${PRECISION} ${DATATYPE} u_scale; };\n"
+                       "layout(binding = 1, std140) uniform Bias { ${PRECISION} ${DATATYPE} u_bias; };\n"
+                       "layout(binding = 2, std140) uniform Ui_one { int ui_one; };\n"
+                       "void main (void)\n"
+                       "{\n"
+                       "       ${PRECISION} ${DATATYPE} res;\n"
+                       "       switch (ui_one)\n"
+                       "       {\n"
+                       "               case 0: res = ${FUNC}(-v_coord) * u_scale + u_bias;     break;\n"
+                       "               case 1: res = ${FUNC}(v_coord) * u_scale + u_bias;      break;\n"
+                       "       }\n"
+                       "       o_color = ${CAST_TO_OUTPUT};\n"
+                       "}\n",
+
+                       UI_ONE
+               },
+       };
+
+       static const struct
+       {
+               const char*             name;
+               SurfaceType             surfaceType;
+               int                             numSamples;
+       } s_fboConfigs[] =
+       {
+               { "fbo",                        SURFACETYPE_UNORM_FBO,          0 },
+               { "fbo_msaa2",          SURFACETYPE_UNORM_FBO,          2 },
+               { "fbo_msaa4",          SURFACETYPE_UNORM_FBO,          4 },
+               { "fbo_float",          SURFACETYPE_FLOAT_FBO,          0 },
+       };
+
+       static const struct
+       {
+               const char*             name;
+               SurfaceType             surfaceType;
+               int                             numSamples;
+       } s_textureConfigs[] =
+       {
+               { "basic",                      SURFACETYPE_UNORM_FBO,          0 },
+               { "msaa4",                      SURFACETYPE_UNORM_FBO,          4 },
+               { "float",                      SURFACETYPE_FLOAT_FBO,          0 },
+       };
+
+       // .dfdx[fine|coarse], .dfdy[fine|coarse], .fwidth[fine|coarse]
+       for (int funcNdx = 0; funcNdx < DERIVATE_LAST; funcNdx++)
+       {
+               const DerivateFunc                                      function                = DerivateFunc(funcNdx);
+               de::MovePtr<tcu::TestCaseGroup>         functionGroup   (new tcu::TestCaseGroup(m_testCtx, getDerivateFuncCaseName(function), getDerivateFuncName(function)));
+
+               // .constant - no precision variants, checks that derivate of constant arguments is 0
+               {
+                       de::MovePtr<tcu::TestCaseGroup> constantGroup   (new tcu::TestCaseGroup(m_testCtx, "constant", "Derivate of constant argument"));
+
+                       for (int vecSize = 1; vecSize <= 4; vecSize++)
+                       {
+                               const glu::DataType                     dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
+                               constantGroup->addChild(new ConstantDerivateCase(m_testCtx, glu::getDataTypeName(dataType), "", function, dataType));
+                       }
+
+                       functionGroup->addChild(constantGroup.release());
+               }
+
+               // Cases based on LinearDerivateCase
+               for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_linearDerivateCases); caseNdx++)
+               {
+                       de::MovePtr<tcu::TestCaseGroup> linearCaseGroup (new tcu::TestCaseGroup(m_testCtx, s_linearDerivateCases[caseNdx].name, s_linearDerivateCases[caseNdx].description));
+                       const char*                                             source                  = s_linearDerivateCases[caseNdx].source;
+
+                       for (int vecSize = 1; vecSize <= 4; vecSize++)
+                       {
+                               for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
+                               {
+                                       const glu::DataType             dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
+                                       const glu::Precision    precision               = glu::Precision(precNdx);
+                                       const SurfaceType               surfaceType             = SURFACETYPE_UNORM_FBO;
+                                       const int                               numSamples              = 0;
+                                       std::ostringstream              caseName;
+
+                                       if (caseNdx != 0 && precision == glu::PRECISION_LOWP)
+                                               continue; // Skip as lowp doesn't actually produce any bits when rendered to default FB.
+
+                                       caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
+
+                                       linearCaseGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples, source, s_linearDerivateCases[caseNdx].usedDefaultUniform));
+                               }
+                       }
+
+                       functionGroup->addChild(linearCaseGroup.release());
+               }
+
+               // Fbo cases
+               for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(s_fboConfigs); caseNdx++)
+               {
+                       de::MovePtr<tcu::TestCaseGroup> fboGroup                (new tcu::TestCaseGroup(m_testCtx, s_fboConfigs[caseNdx].name, "Derivate usage when rendering into FBO"));
+                       const char*                                             source                  = s_linearDerivateCases[0].source; // use source from .linear group
+                       const SurfaceType                               surfaceType             = s_fboConfigs[caseNdx].surfaceType;
+                       const int                                               numSamples              = s_fboConfigs[caseNdx].numSamples;
+
+                       for (int vecSize = 1; vecSize <= 4; vecSize++)
+                       {
+                               for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
+                               {
+                                       const glu::DataType             dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
+                                       const glu::Precision    precision               = glu::Precision(precNdx);
+                                       std::ostringstream              caseName;
+
+                                       if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
+                                               continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
+
+                                       caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
+
+                                       fboGroup->addChild(new LinearDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples, source, U_LAST));
+                               }
+                       }
+
+                       functionGroup->addChild(fboGroup.release());
+               }
+
+               // .texture
+               {
+                       de::MovePtr<tcu::TestCaseGroup>         textureGroup    (new tcu::TestCaseGroup(m_testCtx, "texture", "Derivate of texture lookup result"));
+
+                       for (int texCaseNdx = 0; texCaseNdx < DE_LENGTH_OF_ARRAY(s_textureConfigs); texCaseNdx++)
+                       {
+                               de::MovePtr<tcu::TestCaseGroup> caseGroup               (new tcu::TestCaseGroup(m_testCtx, s_textureConfigs[texCaseNdx].name, ""));
+                               const SurfaceType                               surfaceType             = s_textureConfigs[texCaseNdx].surfaceType;
+                               const int                                               numSamples              = s_textureConfigs[texCaseNdx].numSamples;
+
+                               for (int vecSize = 1; vecSize <= 4; vecSize++)
+                               {
+                                       for (int precNdx = 0; precNdx < glu::PRECISION_LAST; precNdx++)
+                                       {
+                                               const glu::DataType             dataType                = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
+                                               const glu::Precision    precision               = glu::Precision(precNdx);
+                                               std::ostringstream              caseName;
+
+                                               if (surfaceType != SURFACETYPE_FLOAT_FBO && precision == glu::PRECISION_LOWP)
+                                                       continue; // Skip as lowp doesn't actually produce any bits when rendered to U8 RT.
+
+                                               caseName << glu::getDataTypeName(dataType) << "_" << glu::getPrecisionName(precision);
+
+                                               caseGroup->addChild(new TextureDerivateCase(m_testCtx, caseName.str(), "", function, dataType, precision, surfaceType, numSamples));
+                                       }
+                               }
+
+                               textureGroup->addChild(caseGroup.release());
+                       }
+
+                       functionGroup->addChild(textureGroup.release());
+               }
+
+               addChild(functionGroup.release());
+       }
+}
+
+} // anonymous
+
+tcu::TestCaseGroup* createDerivateTests (tcu::TestContext& testCtx)
+{
+       return new ShaderDerivateTests(testCtx);
+}
+
+} // sr
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderDerivateTests.hpp b/external/vulkancts/modules/vulkan/shaderrender/vktShaderRenderDerivateTests.hpp
new file mode 100644 (file)
index 0000000..8727225
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef _VKTSHADERRENDERDERIVATETESTS_HPP
+#define _VKTSHADERRNEDERDERIVATETESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Shader derivate function tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace sr
+{
+
+tcu::TestCaseGroup*    createDerivateTests     (tcu::TestContext& testCtx);
+
+} // sr
+} // vkt
+
+#endif // _VKTSHADERRNEDERDERIVATETESTS_HPP
index e4fefcb..8854a69 100644 (file)
@@ -45,6 +45,7 @@
 #include "vktShaderLibrary.hpp"
 #include "vktRenderPassTests.hpp"
 #include "vktMemoryTests.hpp"
+#include "vktShaderRenderDerivateTests.hpp"
 #include "vktShaderRenderDiscardTests.hpp"
 #include "vktShaderRenderIndexingTests.hpp"
 #include "vktShaderRenderLoopTests.hpp"
@@ -332,6 +333,7 @@ void createGlslTests (tcu::TestCaseGroup* glslTests)
                                                                                                         std::string("vulkan/glsl/es310/") + s_es310Tests[ndx].name + ".test").release());
 
        // ShaderRenderCase-based tests
+       glslTests->addChild(sr::createDerivateTests                     (testCtx));
        glslTests->addChild(sr::createDiscardTests                      (testCtx));
        glslTests->addChild(sr::createIndexingTests                     (testCtx));
        glslTests->addChild(sr::createLoopTests                         (testCtx));