+VkImageMemoryBarrier makeImageMemoryBarrier (const VkAccessFlags srcAccessMask,
+ const VkAccessFlags dstAccessMask,
+ const VkImageLayout oldLayout,
+ const VkImageLayout newLayout,
+ const VkImage image,
+ const VkImageSubresourceRange subresourceRange)
+{
+ const VkImageMemoryBarrier barrier =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ srcAccessMask, // VkAccessFlags outputMask;
+ dstAccessMask, // VkAccessFlags inputMask;
+ oldLayout, // VkImageLayout oldLayout;
+ newLayout, // VkImageLayout newLayout;
+ VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex;
+ image, // VkImage image;
+ subresourceRange, // VkImageSubresourceRange subresourceRange;
+ };
+ return barrier;
+}
+
+VkBufferMemoryBarrier makeBufferMemoryBarrier (const VkAccessFlags srcAccessMask,
+ const VkAccessFlags dstAccessMask,
+ const VkBuffer buffer,
+ const VkDeviceSize offset,
+ const VkDeviceSize bufferSizeBytes)
+{
+ const VkBufferMemoryBarrier barrier =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ srcAccessMask, // VkAccessFlags srcAccessMask;
+ dstAccessMask, // VkAccessFlags dstAccessMask;
+ VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex;
+ buffer, // VkBuffer buffer;
+ offset, // VkDeviceSize offset;
+ bufferSizeBytes, // VkDeviceSize size;
+ };
+ return barrier;
+}
+
+tcu::TestStatus vkt::subgroups::makeVertexFrameBufferTest(Context& context, vk::VkFormat format,
+ SSBOData* extraData, deUint32 extraDataCount,
+ bool (*checkResult)(std::vector<const void*> datas, deUint32 width, deUint32 subgroupSize))
+{
+ const deUint32 maxWidth = 1024u;
+ vector<de::SharedPtr<BufferOrImage> > inputBuffers (extraDataCount);
+ DescriptorSetLayoutBuilder layoutBuilder;
+ const Unique<VkShaderModule> vertexShaderModule (createShaderModule
+ (context.getDeviceInterface(), context.getDevice(), context.getBinaryCollection().get("vert"), 0u));
+ const Unique<VkShaderModule> fragmentShaderModule (createShaderModule
+ (context.getDeviceInterface(), context.getDevice(), context.getBinaryCollection().get("fragment"), 0u));
+ const Unique<VkRenderPass> renderPass (makeRenderPass(context, format));
+
+ const VkVertexInputBindingDescription vertexInputBinding =
+ {
+ 0u, // binding;
+ static_cast<deUint32>(sizeof(tcu::Vec4)), // stride;
+ VK_VERTEX_INPUT_RATE_VERTEX // inputRate
+ };
+
+ const VkVertexInputAttributeDescription vertexInputAttribute =
+ {
+ 0u,
+ 0u,
+ VK_FORMAT_R32G32B32A32_SFLOAT,
+ 0u
+ };
+
+ for (deUint32 i = 0u; i < extraDataCount; i++)
+ {
+ if (extraData[i].isImage)
+ {
+ inputBuffers[i] = de::SharedPtr<BufferOrImage>(new Image(context, static_cast<deUint32>(extraData[i].numElements), 1u, extraData[i].format));
+ }
+ else
+ {
+ vk::VkDeviceSize size = getFormatSizeInBytes(extraData[i].format) * extraData[i].numElements;
+ inputBuffers[i] = de::SharedPtr<BufferOrImage>(new Buffer(context, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT));
+ }
+ const Allocation& alloc = inputBuffers[i]->getAllocation();
+ initializeMemory(context, alloc, extraData[i]);
+ }
+
+ for (deUint32 ndx = 0u; ndx < extraDataCount; ndx++)
+ layoutBuilder.addBinding(inputBuffers[ndx]->getType(), 1u, VK_SHADER_STAGE_VERTEX_BIT, DE_NULL);
+
+ const Unique<VkDescriptorSetLayout> descriptorSetLayout (layoutBuilder.build(context.getDeviceInterface(), context.getDevice()));
+
+ const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(context, *descriptorSetLayout));
+
+ const Unique<VkPipeline> pipeline (makeGraphicsPipeline(context, *pipelineLayout,
+ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
+ *vertexShaderModule, *fragmentShaderModule,
+ DE_NULL, DE_NULL, DE_NULL,
+ *renderPass, VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
+ &vertexInputBinding, &vertexInputAttribute, format));
+ DescriptorPoolBuilder poolBuilder;
+ DescriptorSetUpdateBuilder updateBuilder;
+
+
+ for (deUint32 ndx = 0u; ndx < inputBuffers.size(); ndx++)
+ poolBuilder.addType(inputBuffers[ndx]->getType());
+
+ Move <VkDescriptorPool> descriptorPool;
+ Move <VkDescriptorSet> descriptorSet;
+
+ if (extraDataCount > 0)
+ {
+ descriptorPool = poolBuilder.build(context.getDeviceInterface(), context.getDevice(),
+ VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+ descriptorSet = makeDescriptorSet(context, *descriptorPool, *descriptorSetLayout);
+ }
+
+ for (deUint32 ndx = 0u; ndx < extraDataCount; ndx++)
+ {
+ const Allocation& alloc = inputBuffers[ndx]->getAllocation();
+ initializeMemory(context, alloc, extraData[ndx]);
+ }
+
+ for (deUint32 buffersNdx = 0u; buffersNdx < inputBuffers.size(); buffersNdx++)
+ {
+ if (inputBuffers[buffersNdx]->isImage())
+ {
+ VkDescriptorImageInfo info =
+ makeDescriptorImageInfo(inputBuffers[buffersNdx]->getAsImage()->getSampler(),
+ inputBuffers[buffersNdx]->getAsImage()->getImageView(), VK_IMAGE_LAYOUT_GENERAL);
+
+ updateBuilder.writeSingle(*descriptorSet,
+ DescriptorSetUpdateBuilder::Location::binding(buffersNdx),
+ inputBuffers[buffersNdx]->getType(), &info);
+ }
+ else
+ {
+ VkDescriptorBufferInfo info =
+ makeDescriptorBufferInfo(inputBuffers[buffersNdx]->getAsBuffer()->getBuffer(),
+ 0ull, inputBuffers[buffersNdx]->getAsBuffer()->getSize());
+
+ updateBuilder.writeSingle(*descriptorSet,
+ DescriptorSetUpdateBuilder::Location::binding(buffersNdx),
+ inputBuffers[buffersNdx]->getType(), &info);
+ }
+ }
+ updateBuilder.update(context.getDeviceInterface(), context.getDevice());
+
+ const Unique<VkCommandPool> cmdPool (makeCommandPool(context));
+
+ const deUint32 subgroupSize = getSubgroupSize(context);
+
+ const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer(context, *cmdPool));
+
+ const vk::VkDeviceSize vertexBufferSize = maxWidth * sizeof(tcu::Vec4);
+ Buffer vertexBuffer (context, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
+
+ unsigned totalIterations = 0u;
+ unsigned failedIterations = 0u;
+
+ Image discardableImage (context, maxWidth, 1u, format, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+
+ {
+ const Allocation& alloc = vertexBuffer.getAllocation();
+ std::vector<tcu::Vec4> data (maxWidth, Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+ const float pixelSize = 2.0f / static_cast<float>(maxWidth);
+ float leftHandPosition = -1.0f;
+
+ for(deUint32 ndx = 0u; ndx < maxWidth; ++ndx)
+ {
+ data[ndx][0] = leftHandPosition + pixelSize / 2.0f;
+ leftHandPosition += pixelSize;
+ }
+
+ deMemcpy(alloc.getHostPtr(), &data[0], maxWidth * sizeof(tcu::Vec4));
+ vk::flushMappedMemoryRange(context.getDeviceInterface(), context.getDevice(), alloc.getMemory(), alloc.getOffset(), vertexBufferSize);
+ }
+
+ for (deUint32 width = 1u; width < maxWidth; width++)
+ {
+ totalIterations++;
+ const Unique<VkFramebuffer> framebuffer (makeFramebuffer(context, *renderPass, discardableImage.getImageView(), maxWidth, 1));
+ const VkClearValue clearValue = {{{0.0f, 0.0f, 0.0f, 0.0f}}};
+ const VkViewport viewport = {0.0f, 0.0f, static_cast<float>(maxWidth), 1.0f, 0.0f, 1.0f};
+ const VkRect2D scissor = {{0, 0}, {maxWidth, 1}};
+ const vk::VkDeviceSize imageResultSize = tcu::getPixelSize(vk::mapVkFormat(format)) * maxWidth;
+ Buffer imageBufferResult (context, imageResultSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+ const VkDeviceSize vertexBufferOffset = 0u;
+
+ for (deUint32 ndx = 0u; ndx < inputBuffers.size(); ndx++)
+ {
+ const Allocation& alloc = inputBuffers[ndx]->getAllocation();
+ initializeMemory(context, alloc, extraData[ndx]);
+ }
+
+ const VkRenderPassBeginInfo renderPassBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, DE_NULL, *renderPass,
+ *framebuffer, {{0, 0}, {maxWidth, 1}}, 1, &clearValue,
+ };
+
+ beginCommandBuffer(context, *cmdBuffer);
+ {
+ context.getDeviceInterface().cmdSetViewport(
+ *cmdBuffer, 0, 1, &viewport);
+
+ context.getDeviceInterface().cmdSetScissor(
+ *cmdBuffer, 0, 1, &scissor);
+
+ context.getDeviceInterface().cmdBeginRenderPass(
+ *cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ context.getDeviceInterface().cmdBindPipeline(
+ *cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
+
+ if (extraDataCount > 0)
+ {
+ context.getDeviceInterface().cmdBindDescriptorSets(*cmdBuffer,
+ VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u,
+ &descriptorSet.get(), 0u, DE_NULL);
+ }
+
+ context.getDeviceInterface().cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, vertexBuffer.getBufferPtr(), &vertexBufferOffset);
+
+ context.getDeviceInterface().cmdDraw(*cmdBuffer, width, 1u, 0u, 0u);
+
+ context.getDeviceInterface().cmdEndRenderPass(*cmdBuffer);
+
+ const VkImageSubresourceRange subresourceRange =
+ {
+ VK_IMAGE_ASPECT_COLOR_BIT, //VkImageAspectFlags aspectMask
+ 0u, //deUint32 baseMipLevel
+ 1u, //deUint32 levelCount
+ 0u, //deUint32 baseArrayLayer
+ 1u //deUint32 layerCount
+ };
+
+ const VkBufferImageCopy copyRegion =
+ {
+ 0ull, // VkDeviceSize bufferOffset;
+ 0u, // deUint32 bufferRowLength;
+ 0u, // deUint32 bufferImageHeight;
+ makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource;
+ makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
+ makeExtent3D(IVec3(maxWidth,1,1)), // VkExtent3D imageExtent;
+ };
+
+ const VkImageMemoryBarrier prepareForTransferBarrier = makeImageMemoryBarrier(
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ discardableImage.getImage(), subresourceRange);
+
+ const VkBufferMemoryBarrier copyBarrier = makeBufferMemoryBarrier(
+ VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
+ imageBufferResult.getBuffer(), 0ull, imageResultSize);
+
+ context.getDeviceInterface().cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 0u, (const VkBufferMemoryBarrier*)DE_NULL, 1u, &prepareForTransferBarrier);
+ context.getDeviceInterface().cmdCopyImageToBuffer(*cmdBuffer, discardableImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageBufferResult.getBuffer(), 1u, ©Region);
+ context.getDeviceInterface().cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0u, (const VkMemoryBarrier*)DE_NULL, 1u, ©Barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL);
+
+ endCommandBuffer(context, *cmdBuffer);
+ Move<VkFence> fence(submitCommandBuffer(context, *cmdBuffer));
+ waitFence(context, fence);
+ }
+
+ {
+ const Allocation& allocResult = imageBufferResult.getAllocation();
+ invalidateMappedMemoryRange(context.getDeviceInterface(), context.getDevice(), allocResult.getMemory(), allocResult.getOffset(), imageResultSize);
+
+ std::vector<const void*> datas;
+ datas.push_back(allocResult.getHostPtr());
+ if (!checkResult(datas, width, subgroupSize))
+ failedIterations++;
+ }
+ }
+
+ if (0 < failedIterations)
+ {
+ context.getTestContext().getLog()
+ << TestLog::Message << (totalIterations - failedIterations) << " / "
+ << totalIterations << " values passed" << TestLog::EndMessage;
+ return tcu::TestStatus::fail("Failed!");
+ }
+
+ return tcu::TestStatus::pass("OK");
+}
+