#include "tcuTextureUtil.hpp"
#include "tcuResultCollector.hpp"
#include "tcuFloatFormat.hpp"
+#include "tcuImageCompare.hpp"
#include "vkImageUtil.hpp"
#include "deStringUtil.hpp"
#include "deRandom.hpp"
return testStatus;
}
+class CullAndPrimitiveIdCase : public vkt::TestCase
+{
+public:
+ CullAndPrimitiveIdCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description)
+ : vkt::TestCase(testCtx, name, description)
+ {}
+ ~CullAndPrimitiveIdCase (void) {}
+ void initPrograms (vk::SourceCollections& programCollection) const override;
+ void checkSupport (Context& context) const override;
+ TestInstance* createInstance (Context& context) const override;
+
+ static constexpr uint32_t kCullAndPrimitiveIDWidth = 64u;
+ static constexpr uint32_t kCullAndPrimitiveIDHeight = 64u;
+};
+
+class CullAndPrimitiveIdInstance : public vkt::TestInstance
+{
+public:
+ CullAndPrimitiveIdInstance (Context& context) : vkt::TestInstance(context) {}
+ ~CullAndPrimitiveIdInstance (void) {}
+
+ tcu::TestStatus iterate (void) override;
+};
+
+TestInstance* CullAndPrimitiveIdCase::createInstance (Context& context) const
+{
+ return new CullAndPrimitiveIdInstance(context);
+}
+
+void CullAndPrimitiveIdCase::checkSupport (Context &context) const
+{
+ context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
+}
+
+void CullAndPrimitiveIdCase::initPrograms(vk::SourceCollections& sources) const
+{
+ // One triangle per image pixel, alternating clockwise and counter-clockwise.
+ std::ostringstream vert;
+ vert
+ << "#version 450\n"
+ << "void main ()\n"
+ << "{\n"
+ << " const uint width = " << kCullAndPrimitiveIDWidth << ";\n"
+ << " const uint height = " << kCullAndPrimitiveIDHeight << ";\n"
+ << " const uint uVertexIndex = uint(gl_VertexIndex);\n"
+ << " const uint triangleId = uVertexIndex / 3u;\n"
+ << " const uint vertId = uVertexIndex % 3u;\n"
+ << " const uint rowId = triangleId / width;\n"
+ << " const uint colId = triangleId % width;\n"
+ << " const float fWidth = float(width);\n"
+ << " const float fHeight = float(height);\n"
+ << " const float xPixelCoord = (float(colId) + 0.5) / fWidth * 2.0 - 1.0;\n"
+ << " const float yPixelCoord = (float(rowId) + 0.5) / fHeight * 2.0 - 1.0;\n"
+ << " const float quarterPixelWidth = (2.0 / fWidth) / 4.0;\n"
+ << " const float quarterPixelHeight = (2.0 / fHeight) / 4.0;\n"
+ << " const vec2 bottomLeft = vec2(xPixelCoord - quarterPixelWidth, yPixelCoord + quarterPixelHeight);\n"
+ << " const vec2 bottomRight = vec2(xPixelCoord + quarterPixelWidth, yPixelCoord + quarterPixelHeight);\n"
+ << " const vec2 topCenter = vec2(xPixelCoord, yPixelCoord - quarterPixelHeight);\n"
+ << " const vec2 cwCoords[3] = vec2[](bottomLeft, topCenter, bottomRight);\n"
+ << " const vec2 ccwCoords[3] = vec2[](bottomLeft, bottomRight, topCenter);\n"
+ << " // Half the triangles will be culled.\n"
+ << " const bool counterClockWise = ((triangleId % 2u) == 0u);\n"
+ << " vec2 pointCoords;\n"
+ << " if (counterClockWise) { pointCoords = ccwCoords[vertId]; }\n"
+ << " else { pointCoords = cwCoords[vertId]; }\n"
+ << " gl_Position = vec4(pointCoords, 0.0, 1.0);\n"
+ << "}\n"
+ ;
+ sources.glslSources.add("vert") << glu::VertexSource(vert.str());
+
+ std::ostringstream frag;
+ frag
+ << "#version 450\n"
+ << "layout (location=0) out vec4 outColor;\n"
+ << "\n"
+ << "void main ()\n"
+ << "{\n"
+ << " const uint primId = uint(gl_PrimitiveID);\n"
+ << " // Pixel color rotates every 3 pixels.\n"
+ << " const vec4 red = vec4(1.0, 0.0, 0.0, 1.0);\n"
+ << " const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ << " const vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);\n"
+ << " const vec4 colorPalette[3] = vec4[](red, green, blue);\n"
+ << " const uint colorIdx = primId % 3u;\n"
+ << " outColor = colorPalette[colorIdx];\n"
+ << "}\n"
+ ;
+ sources.glslSources.add("frag") << glu::FragmentSource(frag.str());
+}
+
+tcu::TestStatus CullAndPrimitiveIdInstance::iterate ()
+{
+ const auto& vkd = m_context.getDeviceInterface();
+ const auto device = m_context.getDevice();
+ auto& alloc = m_context.getDefaultAllocator();
+ const auto qIndex = m_context.getUniversalQueueFamilyIndex();
+ const auto queue = m_context.getUniversalQueue();
+ const auto kWidth = CullAndPrimitiveIdCase::kCullAndPrimitiveIDWidth;
+ const auto kHeight = CullAndPrimitiveIdCase::kCullAndPrimitiveIDHeight;
+ const auto extent = makeExtent3D(kWidth, kHeight, 1u);
+ const auto triangleCount = extent.width * extent.height * extent.depth;
+ const auto vertexCount = triangleCount * 3u;
+ const auto format = VK_FORMAT_R8G8B8A8_UNORM;
+ const auto tcuFormat = mapVkFormat(format);
+ const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+ const auto verifBufferUsage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+ const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
+
+ // Color attachment.
+ const VkImageCreateInfo colorBufferInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ 0u, // VkImageCreateFlags flags;
+ VK_IMAGE_TYPE_2D, // VkImageType imageType;
+ format, // VkFormat format;
+ extent, // VkExtent3D extent;
+ 1u, // uint32_t mipLevels;
+ 1u, // uint32_t arrayLayers;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
+ colorUsage, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 0u, // uint32_t queueFamilyIndexCount;
+ nullptr, // const uint32_t* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ };
+ ImageWithMemory colorBuffer (vkd, device, alloc, colorBufferInfo, MemoryRequirement::Any);
+ const auto colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+ const auto colorSRL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
+ const auto colorBufferView = makeImageView(vkd, device, colorBuffer.get(), VK_IMAGE_VIEW_TYPE_2D, format, colorSRR);
+
+ // Verification buffer.
+ const auto verifBufferSize = static_cast<VkDeviceSize>(tcu::getPixelSize(tcuFormat)) * extent.width * extent.height;
+ const auto verifBufferInfo = makeBufferCreateInfo(verifBufferSize, verifBufferUsage);
+ BufferWithMemory verifBuffer (vkd, device, alloc, verifBufferInfo, MemoryRequirement::HostVisible);
+ auto& verifBufferAlloc = verifBuffer.getAllocation();
+ void* verifBufferData = verifBufferAlloc.getHostPtr();
+
+ // Render pass and framebuffer.
+ const auto renderPass = makeRenderPass(vkd, device, format);
+ const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorBufferView.get(), extent.width, extent.height);
+
+ // Shader modules.
+ const auto& binaries = m_context.getBinaryCollection();
+ const auto vertModule = createShaderModule(vkd, device, binaries.get("vert"));
+ const auto fragModule = createShaderModule(vkd, device, binaries.get("frag"));
+
+ // Viewports and scissors.
+ const std::vector<VkViewport> viewports (1u, makeViewport(extent));
+ const std::vector<VkRect2D> scissors (1u, makeRect2D(extent));
+
+ // Vertex input and culling.
+ const VkPipelineVertexInputStateCreateInfo inputState = initVulkanStructure();
+ const VkPipelineRasterizationStateCreateInfo rasterizationState =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
+ nullptr, // const void* pNext;
+ 0u, // VkPipelineRasterizationStateCreateFlags flags;
+ VK_FALSE, // VkBool32 depthClampEnable;
+ VK_FALSE, // VkBool32 rasterizerDiscardEnable;
+ VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
+ VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode;
+ VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
+ VK_FALSE, // VkBool32 depthBiasEnable;
+ 0.0f, // float depthBiasConstantFactor;
+ 0.0f, // float depthBiasClamp;
+ 0.0f, // float depthBiasSlopeFactor;
+ 1.0f, // float lineWidth;
+ };
+
+ // Pipeline layout and graphics pipeline.
+ const auto pipelineLayout = makePipelineLayout(vkd, device);
+ const auto pipeline = makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
+ vertModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(),
+ renderPass.get(), viewports, scissors,
+ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u/*subpass*/, 0u/*patchControlPoints*/,
+ &inputState, &rasterizationState);
+
+ // Command pool and buffer.
+ const auto cmdPool = makeCommandPool(vkd, device, qIndex);
+ const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+ const auto cmdBuffer = cmdBufferPtr.get();
+
+ beginCommandBuffer(vkd, cmdBuffer);
+
+ // Draw.
+ beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u), clearColor);
+ vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
+ vkd.cmdDraw(cmdBuffer, vertexCount, 1u, 0u, 0u);
+ endRenderPass(vkd, cmdBuffer);
+
+ // Copy to verification buffer.
+ const auto copyRegion = makeBufferImageCopy(extent, colorSRL);
+ const auto transfer2Host = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
+ const auto color2Transfer = makeImageMemoryBarrier(
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ colorBuffer.get(), colorSRR);
+
+ cmdPipelineImageMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &color2Transfer);
+ vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verifBuffer.get(), 1u, ©Region);
+ cmdPipelineMemoryBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, &transfer2Host);
+
+ endCommandBuffer(vkd, cmdBuffer);
+
+ // Submit and validate result.
+ submitCommandsAndWait(vkd, device, queue, cmdBuffer);
+ invalidateAlloc(vkd, device, verifBufferAlloc);
+
+ const tcu::IVec3 iExtent (static_cast<int>(extent.width), static_cast<int>(extent.height), static_cast<int>(extent.depth));
+ const tcu::PixelBufferAccess verifAccess (tcuFormat, iExtent, verifBufferData);
+ tcu::TextureLevel referenceLevel (tcuFormat, iExtent.x(), iExtent.y(), iExtent.z());
+ const auto referenceAccess = referenceLevel.getAccess();
+
+ // Compose reference image.
+ const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f);
+ const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
+ const tcu::Vec4 blue (0.0f, 0.0f, 1.0f, 1.0f);
+ const std::vector<tcu::Vec4> colorPalette { red, green, blue };
+
+ for (int y = 0; y < iExtent.y(); ++y)
+ for (int x = 0; x < iExtent.x(); ++x)
+ {
+ const auto pixelId = y*iExtent.x() + x;
+ const bool culled = (pixelId % 2 == 1);
+ const auto color = (culled ? clearColor : colorPalette[pixelId % 3]);
+ referenceAccess.setPixel(color, x, y);
+ }
+
+ // Compare.
+ {
+ auto& log = m_context.getTestContext().getLog();
+ if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, verifAccess, tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f), tcu::COMPARE_LOG_ON_ERROR))
+ TCU_FAIL("Failed; check log for details");
+ }
+
+ return tcu::TestStatus::pass("Pass");
+}
+
void createRasterizationTests (tcu::TestCaseGroup* rasterizationTests)
{
tcu::TestContext& testCtx = rasterizationTests->getTestContext();
culling->addChild(new CullingTestCase(testCtx, name, "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode, polygonModes[polygonModeNdx].mode));
}
}
+
+ culling->addChild(new CullAndPrimitiveIdCase(testCtx, "primitive_id", "Cull some triangles and check primitive ID works"));
}
// .discard