1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2015 The Khronos Group Inc. 6 * Copyright (c) 2015 Intel Corporation 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 *//*! 21 * \file 22 * \brief Dynamic State Viewport Tests 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktDynamicStateVPTests.hpp" 26 27 #include "vktDynamicStateBaseClass.hpp" 28 #include "vktDynamicStateTestCaseUtil.hpp" 29 30 #include "vkImageUtil.hpp" 31 32 #include "tcuTextureUtil.hpp" 33 #include "tcuImageCompare.hpp" 34 #include "tcuRGBA.hpp" 35 36 namespace vkt 37 { 38 namespace DynamicState 39 { 40 41 using namespace Draw; 42 43 namespace 44 { 45 46 class ViewportStateBaseCase : public DynamicStateBaseClass 47 { 48 public: 49 ViewportStateBaseCase (Context& context, const char* vertexShaderName, const char* fragmentShaderName) 50 : DynamicStateBaseClass (context, vertexShaderName, fragmentShaderName) 51 {} 52 53 void initialize(void) 54 { 55 m_topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; 56 57 m_data.push_back(PositionColorVertex(tcu::Vec4(-0.5f, 0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec())); 58 m_data.push_back(PositionColorVertex(tcu::Vec4(0.5f, 0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec())); 59 m_data.push_back(PositionColorVertex(tcu::Vec4(-0.5f, -0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec())); 60 m_data.push_back(PositionColorVertex(tcu::Vec4(0.5f, -0.5f, 1.0f, 1.0f), tcu::RGBA::green().toVec())); 61 62 DynamicStateBaseClass::initialize(); 63 } 64 65 virtual tcu::Texture2D buildReferenceFrame (void) 66 { 67 DE_ASSERT(false); 68 return tcu::Texture2D(tcu::TextureFormat(), 0, 0); 69 } 70 71 virtual void setDynamicStates (void) 72 { 73 DE_ASSERT(false); 74 } 75 76 virtual tcu::TestStatus iterate (void) 77 { 78 tcu::TestLog &log = m_context.getTestContext().getLog(); 79 const vk::VkQueue queue = m_context.getUniversalQueue(); 80 81 beginRenderPass(); 82 83 // set states here 84 setDynamicStates(); 85 86 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 87 88 const vk::VkDeviceSize vertexBufferOffset = 0; 89 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object(); 90 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset); 91 92 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0); 93 94 m_vk.cmdEndRenderPass(*m_cmdBuffer); 95 m_vk.endCommandBuffer(*m_cmdBuffer); 96 97 vk::VkSubmitInfo submitInfo = 98 { 99 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; 100 DE_NULL, // const void* pNext; 101 0, // deUint32 waitSemaphoreCount; 102 DE_NULL, // const VkSemaphore* pWaitSemaphores; 103 (const vk::VkPipelineStageFlags*)DE_NULL, 104 1, // deUint32 commandBufferCount; 105 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; 106 0, // deUint32 signalSemaphoreCount; 107 DE_NULL // const VkSemaphore* pSignalSemaphores; 108 }; 109 m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL); 110 111 // validation 112 { 113 VK_CHECK(m_vk.queueWaitIdle(queue)); 114 115 tcu::Texture2D referenceFrame = buildReferenceFrame(); 116 117 const vk::VkOffset3D zeroOffset = { 0, 0, 0 }; 118 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), 119 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT); 120 121 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", 122 referenceFrame.getLevel(0), renderedFrame, 0.05f, 123 tcu::COMPARE_LOG_RESULT)) 124 { 125 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed"); 126 } 127 128 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed"); 129 } 130 } 131 }; 132 133 class ViewportParamTestInstane : public ViewportStateBaseCase 134 { 135 public: 136 ViewportParamTestInstane (Context& context, ShaderMap shaders) 137 : ViewportStateBaseCase (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT]) 138 { 139 ViewportStateBaseCase::initialize(); 140 } 141 142 virtual void setDynamicStates(void) 143 { 144 const vk::VkViewport viewport = { 0.0f, 0.0f, (float)WIDTH * 2, (float)HEIGHT * 2, 0.0f, 0.0f }; 145 const vk::VkRect2D scissor = { { 0, 0 }, { WIDTH, HEIGHT } }; 146 147 setDynamicViewportState(1, &viewport, &scissor); 148 setDynamicRasterizationState(); 149 setDynamicBlendState(); 150 setDynamicDepthStencilState(); 151 } 152 153 virtual tcu::Texture2D buildReferenceFrame (void) 154 { 155 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT)); 156 referenceFrame.allocLevel(0); 157 158 const deInt32 frameWidth = referenceFrame.getWidth(); 159 const deInt32 frameHeight = referenceFrame.getHeight(); 160 161 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 162 163 for (int y = 0; y < frameHeight; y++) 164 { 165 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f; 166 167 for (int x = 0; x < frameWidth; x++) 168 { 169 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f; 170 171 if (xCoord >= 0.0f && xCoord <= 1.0f && yCoord >= 0.0f && yCoord <= 1.0f) 172 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y); 173 } 174 } 175 176 return referenceFrame; 177 } 178 }; 179 180 class ScissorParamTestInstance : public ViewportStateBaseCase 181 { 182 public: 183 ScissorParamTestInstance (Context& context, ShaderMap shaders) 184 : ViewportStateBaseCase (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT]) 185 { 186 ViewportStateBaseCase::initialize(); 187 } 188 189 virtual void setDynamicStates (void) 190 { 191 const vk::VkViewport viewport = { 0.0f, 0.0f, (float)WIDTH, (float)HEIGHT, 0.0f, 0.0f }; 192 const vk::VkRect2D scissor = { { 0, 0 }, { WIDTH / 2, HEIGHT / 2 } }; 193 194 setDynamicViewportState(1, &viewport, &scissor); 195 setDynamicRasterizationState(); 196 setDynamicBlendState(); 197 setDynamicDepthStencilState(); 198 } 199 200 virtual tcu::Texture2D buildReferenceFrame (void) 201 { 202 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT)); 203 referenceFrame.allocLevel(0); 204 205 const deInt32 frameWidth = referenceFrame.getWidth(); 206 const deInt32 frameHeight = referenceFrame.getHeight(); 207 208 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 209 210 for (int y = 0; y < frameHeight; y++) 211 { 212 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f; 213 214 for (int x = 0; x < frameWidth; x++) 215 { 216 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f; 217 218 if (xCoord >= -0.5f && xCoord <= 0.0f && yCoord >= -0.5f && yCoord <= 0.0f) 219 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y); 220 } 221 } 222 223 return referenceFrame; 224 } 225 }; 226 227 class ViewportArrayTestInstance : public DynamicStateBaseClass 228 { 229 protected: 230 std::string m_geometryShaderName; 231 232 public: 233 234 ViewportArrayTestInstance (Context& context, ShaderMap shaders) 235 : DynamicStateBaseClass (context, shaders[glu::SHADERTYPE_VERTEX], shaders[glu::SHADERTYPE_FRAGMENT]) 236 , m_geometryShaderName (shaders[glu::SHADERTYPE_GEOMETRY]) 237 { 238 // Check geometry shader support 239 { 240 const vk::VkPhysicalDeviceFeatures& deviceFeatures = m_context.getDeviceFeatures(); 241 242 if (!deviceFeatures.multiViewport) 243 throw tcu::NotSupportedError("Multi-viewport is not supported"); 244 245 if (!deviceFeatures.geometryShader) 246 throw tcu::NotSupportedError("Geometry shaders are not supported"); 247 } 248 249 for (int i = 0; i < 4; i++) 250 { 251 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, 1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec())); 252 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, 1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec())); 253 m_data.push_back(PositionColorVertex(tcu::Vec4(-1.0f, -1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec())); 254 m_data.push_back(PositionColorVertex(tcu::Vec4(1.0f, -1.0f, (float)i / 3.0f, 1.0f), tcu::RGBA::green().toVec())); 255 } 256 257 DynamicStateBaseClass::initialize(); 258 } 259 260 virtual void initPipeline (const vk::VkDevice device) 261 { 262 const vk::Unique<vk::VkShaderModule> vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_vertexShaderName), 0)); 263 const vk::Unique<vk::VkShaderModule> gs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_geometryShaderName), 0)); 264 const vk::Unique<vk::VkShaderModule> fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get(m_fragmentShaderName), 0)); 265 266 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState; 267 268 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0); 269 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT)); 270 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*gs, "main", vk::VK_SHADER_STAGE_GEOMETRY_BIT)); 271 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT)); 272 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState)); 273 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_topology)); 274 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState)); 275 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(4)); 276 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState()); 277 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState()); 278 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState()); 279 pipelineCreateInfo.addState(PipelineCreateInfo::DynamicState()); 280 281 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo); 282 } 283 284 virtual tcu::TestStatus iterate (void) 285 { 286 tcu::TestLog &log = m_context.getTestContext().getLog(); 287 const vk::VkQueue queue = m_context.getUniversalQueue(); 288 289 beginRenderPass(); 290 291 // set states here 292 const float halfWidth = (float)WIDTH / 2; 293 const float halfHeight = (float)HEIGHT / 2; 294 const deInt32 quarterWidth = WIDTH / 4; 295 const deInt32 quarterHeight = HEIGHT / 4; 296 297 const vk::VkViewport viewports[4] = 298 { 299 { 0.0f, 0.0f, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f }, 300 { halfWidth, 0.0f, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f }, 301 { halfWidth, halfHeight, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f }, 302 { 0.0f, halfHeight, (float)halfWidth, (float)halfHeight, 0.0f, 0.0f } 303 }; 304 305 const vk::VkRect2D scissors[4] = 306 { 307 { { quarterWidth, quarterHeight }, { quarterWidth, quarterHeight } }, 308 { { (deInt32)halfWidth, quarterHeight }, { quarterWidth, quarterHeight } }, 309 { { (deInt32)halfWidth, (deInt32)halfHeight }, { quarterWidth, quarterHeight } }, 310 { { quarterWidth, (deInt32)halfHeight }, { quarterWidth, quarterHeight } }, 311 }; 312 313 setDynamicViewportState(4, viewports, scissors); 314 setDynamicRasterizationState(); 315 setDynamicBlendState(); 316 setDynamicDepthStencilState(); 317 318 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 319 320 const vk::VkDeviceSize vertexBufferOffset = 0; 321 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object(); 322 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset); 323 324 m_vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_data.size()), 1, 0, 0); 325 326 m_vk.cmdEndRenderPass(*m_cmdBuffer); 327 m_vk.endCommandBuffer(*m_cmdBuffer); 328 329 vk::VkSubmitInfo submitInfo = 330 { 331 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; 332 DE_NULL, // const void* pNext; 333 0, // deUint32 waitSemaphoreCount; 334 DE_NULL, // const VkSemaphore* pWaitSemaphores; 335 (const vk::VkPipelineStageFlags*)DE_NULL, 336 1, // deUint32 commandBufferCount; 337 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; 338 0, // deUint32 signalSemaphoreCount; 339 DE_NULL // const VkSemaphore* pSignalSemaphores; 340 }; 341 m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL); 342 343 // validation 344 { 345 VK_CHECK(m_vk.queueWaitIdle(queue)); 346 347 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT)); 348 referenceFrame.allocLevel(0); 349 350 const deInt32 frameWidth = referenceFrame.getWidth(); 351 const deInt32 frameHeight = referenceFrame.getHeight(); 352 353 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 354 355 for (int y = 0; y < frameHeight; y++) 356 { 357 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f; 358 359 for (int x = 0; x < frameWidth; x++) 360 { 361 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f; 362 363 if (xCoord >= -0.5f && xCoord <= 0.5f && yCoord >= -0.5f && yCoord <= 0.5f) 364 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y); 365 } 366 } 367 368 const vk::VkOffset3D zeroOffset = { 0, 0, 0 }; 369 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), 370 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT); 371 372 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", 373 referenceFrame.getLevel(0), renderedFrame, 0.05f, 374 tcu::COMPARE_LOG_RESULT)) 375 { 376 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Image verification failed"); 377 } 378 379 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Image verification passed"); 380 } 381 } 382 }; 383 384 } //anonymous 385 386 DynamicStateVPTests::DynamicStateVPTests (tcu::TestContext& testCtx) 387 : TestCaseGroup (testCtx, "vp_state", "Tests for viewport state") 388 { 389 /* Left blank on purpose */ 390 } 391 392 DynamicStateVPTests::~DynamicStateVPTests () 393 { 394 } 395 396 void DynamicStateVPTests::init (void) 397 { 398 ShaderMap shaderPaths; 399 shaderPaths[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert"; 400 shaderPaths[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag"; 401 402 addChild(new InstanceFactory<ViewportParamTestInstane>(m_testCtx, "viewport", "Set viewport which is twice bigger than screen size", shaderPaths)); 403 addChild(new InstanceFactory<ScissorParamTestInstance>(m_testCtx, "scissor", "Perform a scissor test on 1/4 bottom-left part of the surface", shaderPaths)); 404 405 shaderPaths[glu::SHADERTYPE_GEOMETRY] = "vulkan/dynamic_state/ViewportArray.geom"; 406 addChild(new InstanceFactory<ViewportArrayTestInstance>(m_testCtx, "viewport_array", "Multiple viewports and scissors", shaderPaths)); 407 } 408 409 } // DynamicState 410 } // vkt 411