[Piglit] [PATCH crucible 2/2] Add test for VK_KHR_multiview
Caio Marcelo de Oliveira Filho
caio.oliveira at intel.com
Wed Sep 26 19:01:49 UTC 2018
Uses the extension to write to two different layers of an image, then
merge those side-by-side in a final image.
---
This patch is available in my 'multiview' branch:
https://gitlab.freedesktop.org/cmarcelo/crucible/commits/multiview
Makefile.am | 2 +
data/func.multiview.ref.png | Bin 0 -> 1878 bytes
src/tests/func/multiview.c | 373 ++++++++++++++++++++++++++++++++++++
3 files changed, 375 insertions(+)
create mode 100644 data/func.multiview.ref.png
create mode 100644 src/tests/func/multiview.c
diff --git a/Makefile.am b/Makefile.am
index dc24a99..621ee83 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -99,6 +99,7 @@ bin_crucible_SOURCES = \
src/tests/func/compute-num-workgroups.c \
src/tests/func/interleaved-cmd-buffers.c \
src/tests/func/miptree/miptree.c \
+ src/tests/func/multiview.c \
src/tests/func/push-constants/basic.c \
src/tests/func/shader/constants.c \
src/tests/func/shader/fragcoord.c \
@@ -145,6 +146,7 @@ BUILT_SOURCES = \
src/tests/func/compute-num-workgroups-spirv.h \
src/tests/func/miptree/miptree-spirv.h \
src/tests/func/miptree/miptree_gen.c \
+ src/tests/func/multiview-spirv.h \
src/tests/func/push-constants/basic-spirv.h \
src/tests/func/amd/gcn_shader-spirv.h \
src/tests/func/amd/shader_trinary_minmax-spirv.h \
diff --git a/data/func.multiview.ref.png b/data/func.multiview.ref.png
new file mode 100644
index 0000000000000000000000000000000000000000..dfc81c2b6b3c60886dee1c006756e8b596ff8391
GIT binary patch
literal 1878
zcmds&|3A}t0LR~-eHF9jTG_?4>x;vk$JRMfYs}Ze=o57!v2$rB-KLW-H8N7^oa!El
z4l$QR*H$@GSbXGi5&5#^OW4+B%a_ueWNCB{kNf5RgL^#g$LBB4*W>xq>kJ&U&D?ag
zDFDFSZ at YIe01yBGh)i$*fKk~UQvmQ(KW~p+DaEfY({E6H$gN#*MXRkTuq#6xZwI at Q
z?W|1+cO4iS1_muX#YLWw2zHEe9GQ|?g;vmL@;Z57ZQH5gqjOzT#jiVx)%4A6frYid
zsqf5m4$e%~S{|rva9~5^TdBh^9l!v~!9ik$4U8yB;2<7gIe3UhUIQb)|NpR at C`y-J
zue5~hxLbnpNX@%tKxW4E?8PB1J|N<Uev}<|Z7>cg&FO6VoDBuEI?kfVoT7zjsg}ov
z0(|R1N_-&5yWwcD=c`^Udou}$Q2E)rApMX9#4yJQuCFq&<2IHr6Gd4TEz|?ePPUeG
zN%SQY|E<D_q&$kYUFQRgslI?g%G-n01^fW^@Lz_Y0F2;x24Fbs0~jPS1*dE4hV(5Z
zRUhmj<cg??CyjWVxc453>XrUFM%|y*Wlw=KMs~BlFwm#Nvj{^_YUsP$>bw*J=47jP
zM&6w=rbrT$UJnE>tOt1dHN7j_DAj1g{KJrv3~~D>8_VV9L(p(s{Jdh>-SC0 at M{yl#
zw1|T2XDG2&$D at sXyMMAdN^-nF5_BIv2cmZ4(q&x)jI&!CP5a##Q9L`o!&37?t1FJy
z(|>U`rBt8|#)l!L|1u|TT^Pp{b7of?FZwU6536E&Vc4B5eb^I(MgOZ)W_^>KxpSbj
zGxD<HE#2LT^d{-?nWs9p+Czu<`{xSYx2T<5Y8eLM-0p_nM7(~wJ*4UF&jOQU^#i0}
z)u~s&%`|@g(+P3{VX?iW at PLVW%gvFW_-JlvXnUpyF8yk-`fg-~)jl^=s;jU%W~j;7
z!S3#QWSi$3^Smbp-`yTHwS0%ARZp)*c((tUcQO?b<_0Z1<>4~j8u>VTK}!-yMiu|%
z$9#}_qA9qFJ|b;BDMg8Oel`Etqg?l0K#y!i$s3xR^pDuxBb(e07Rh!GQjRE~motdd
zn+vKnX<~*!`skwbwH%^G^1wcl+4-?a`^z4$_Mux;qzDR1*pi{!^oNb{qJP>%eA*yd
zT#-h{ny<{(6AXT8;_2g<lyAyr^4)LpXk+8iUdp1Tjwc(-n4)d-HX#<o6X70ctg<5C
zCs0t4=s!Tz$ijyD)T-xJnUQDt9p9sU?Itgrry{>X#!;JCenRO|#qz?)!%|QgJ1lI*
znR*}Z6E?Y at ZegM1)!m9KEFNv_`Q(90m!q5E%NA0!Yx(PqE8m?5)15u_Q*X5Kl|;?e
zFs~=K&Sr3h=R(U=!`g=v*$gU@^XVAVvl%Suljje+aDcMLTBgBZ*Sae%vYaJzuiUJO
z(<b`+p3E5GWA-hXf>$lLFbl6LB~jS{%h#^4p*3#ye_p8CZ+2FWPT}`CJYAXy=-(lp
zwROz>%(a)O3BxZ4?I>J*sDtypo>i1sp!{;O?r~i|_Z+Gr<HvNCw558R=-P=pFI4GK
z*<W+kE3N7eMR@!)lDv0P$nkO8#ZFDgYjwW&Y!%55uOIa+kbR(rj`B5mYA4o|Dq`Kl
z_8QfX*Q-<RCW9Rq{U_gF<z+QTRVm+8?0pL=W1XTmlD1Ck1~xDZ+7-?pk6UPN2Ms0Q
zG99N*u_|4T9KL>oDk^CFW7lYl?S_LrIo|{d8e=8_-%<LZ`%F8V at r>P_fX)XoZ77Yp
zZt?BBS=r5IwN~@pzIRc90%Sz(DNocdtdOAx$72=wx&7~rxOqtyfSKnnOE!hvj0raZ
zx1p+?g2s=;C1H|39ZY~^v2F>=vq&I(VWwB%vY3?n!8qROYJm|2y_eUhU{+tquVj`L
zihV`MR~9)&zxvAl*d~m~cTQgE5<Yq?^`w;N2 at G*1R<pJ_kvcO-^LffaigB<RTvA<1
z$O8H&OnL*j7DrEf&&ll)0li|2%S7PH+e!V#!WEV?UjQtO{N;fcCjl5aLIR%C5SBxL
e{sU}AYK-`-aCm2U^w{#H+w}7Z@|JpXGyewE7$+Y9
literal 0
HcmV?d00001
diff --git a/src/tests/func/multiview.c b/src/tests/func/multiview.c
new file mode 100644
index 0000000..bd0767f
--- /dev/null
+++ b/src/tests/func/multiview.c
@@ -0,0 +1,373 @@
+// Copyright 2018 Intel Corporation
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice (including the next
+// paragraph) shall be included in all copies or substantial portions of the
+// Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "tapi/t.h"
+
+#include "multiview-spirv.h"
+
+// Uses two subpasses, the first pass writes using VK_KHR_multiview to
+// a two layer image, with a displacement based on the gl_ViewIndex.
+// The second pass takes both layers as input and render them side by
+// side.
+
+static void
+test_multiview(void)
+{
+ t_require_ext("VK_KHR_multiview");
+
+ VkRenderPassMultiviewCreateInfo multiviewInfo = {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,
+ .subpassCount = 2,
+ .pViewMasks = (uint32_t[]) { 3, 1 },
+ };
+
+ VkRenderPass pass = qoCreateRenderPass(t_device,
+ .pNext = &multiviewInfo,
+ .attachmentCount = 4,
+ .pAttachments = (VkAttachmentDescription[]) {
+ {
+ // Multi layered image written in first subpass.
+ QO_ATTACHMENT_DESCRIPTION_DEFAULTS,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+ .finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ },
+ {
+ QO_ATTACHMENT_DESCRIPTION_DEFAULTS,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ },
+ {
+ QO_ATTACHMENT_DESCRIPTION_DEFAULTS,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+ .initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ },
+ {
+ // Final output merging both layers.
+ QO_ATTACHMENT_DESCRIPTION_DEFAULTS,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+ },
+ },
+ .subpassCount = 2,
+ .pSubpasses = (VkSubpassDescription[]) {
+ {
+ QO_SUBPASS_DESCRIPTION_DEFAULTS,
+ .colorAttachmentCount = 1,
+ .pColorAttachments = (VkAttachmentReference[]) {
+ {
+ .attachment = 0,
+ .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ },
+ },
+ },
+ {
+ QO_SUBPASS_DESCRIPTION_DEFAULTS,
+ .inputAttachmentCount = 2,
+ .pInputAttachments = (VkAttachmentReference[]) {
+ {
+ .attachment = 1,
+ .layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ },
+ {
+ .attachment = 2,
+ .layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ }
+ },
+ .colorAttachmentCount = 1,
+ .pColorAttachments = (VkAttachmentReference[]) {
+ {
+ .attachment = 3,
+ .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ },
+ },
+ },
+ },
+ .dependencyCount = 2,
+ .pDependencies = (VkSubpassDependency[]) {
+ {
+ .srcSubpass = VK_SUBPASS_EXTERNAL,
+ .dstSubpass = 0,
+ .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ .srcAccessMask = 0,
+ .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ },
+ {
+ .srcSubpass = 0,
+ .dstSubpass = 1,
+ .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
+ .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
+ },
+ });
+
+ VkShaderModule first_vs = qoCreateShaderModuleGLSL(t_device, VERTEX,
+ QO_EXTENSION GL_EXT_multiview : enable
+
+ layout(location = 0) out vec4 v_color;
+
+ vec4 positions[3] = vec4[](
+ vec4(-0.5, -0.5, 0, 1),
+ vec4(-0.2, 0.5, 0, 1),
+ vec4(-0.8, 0.5, 0, 1)
+ );
+
+ vec4 colors[3] = vec4[](
+ vec4(1, 1, 0, 1),
+ vec4(1, 0, 1, 1),
+ vec4(0, 1, 1, 1)
+ );
+
+ vec4 displacement[2] = vec4[](
+ vec4(0, 0, 0, 0),
+ vec4(1, 0.2, 0, 0)
+ );
+
+ void main()
+ {
+ gl_Position = displacement[gl_ViewIndex] + positions[gl_VertexIndex];
+ v_color = colors[gl_VertexIndex];
+ }
+ );
+
+ VkShaderModule first_fs = qoCreateShaderModuleGLSL(t_device, FRAGMENT,
+ layout(location = 0) in vec4 v_color;
+ layout(location = 0) out vec4 f_color;
+
+ void main()
+ {
+ f_color = v_color;
+ }
+ );
+
+
+ VkPipelineLayout first_layout = qoCreatePipelineLayout(t_device);
+
+ VkPipeline first_pipeline = qoCreateGraphicsPipeline(t_device, t_pipeline_cache,
+ &(QoExtraGraphicsPipelineCreateInfo) {
+ QO_EXTRA_GRAPHICS_PIPELINE_CREATE_INFO_DEFAULTS,
+ .vertexShader = first_vs,
+ .fragmentShader = first_fs,
+ .pNext =
+ &(VkGraphicsPipelineCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
+ QO_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO_DEFAULTS,
+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ },
+ .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
+ QO_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO_DEFAULTS
+ },
+ .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {},
+ .renderPass = pass,
+ .layout = first_layout,
+ .subpass = 0,
+ }});
+
+ VkShaderModule second_vs = qoCreateShaderModuleGLSL(t_device, VERTEX,
+ vec2 positions[6] = vec2[](
+ vec2( -1, -1 ),
+ vec2( 1, -1 ),
+ vec2( 1, 1 ),
+ vec2( 1, 1 ),
+ vec2( -1, 1 ),
+ vec2( -1, -1 )
+ );
+
+ void main()
+ {
+ gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
+ }
+ );
+
+ VkShaderModule second_fs = qoCreateShaderModuleGLSL(t_device, FRAGMENT,
+ layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput theInput[2];
+ layout(location = 0) out vec4 f_color;
+
+ void main()
+ {
+ f_color.a = 1.0;
+ f_color.r = subpassLoad(theInput[0]).r;
+ f_color.g = subpassLoad(theInput[1]).g;
+ f_color.b = 0.0;
+ }
+ );
+
+ VkDescriptorSetLayout set_layout = qoCreateDescriptorSetLayout(t_device,
+ .bindingCount = 1,
+ .pBindings = (VkDescriptorSetLayoutBinding[]) {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+ .descriptorCount = 2,
+ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+ },
+ });
+
+ VkPipelineLayout second_layout = qoCreatePipelineLayout(t_device,
+ .setLayoutCount = 1,
+ .pSetLayouts = &set_layout);
+
+ VkPipeline second_pipeline = qoCreateGraphicsPipeline(t_device, t_pipeline_cache,
+ &(QoExtraGraphicsPipelineCreateInfo) {
+ QO_EXTRA_GRAPHICS_PIPELINE_CREATE_INFO_DEFAULTS,
+ .vertexShader = second_vs,
+ .fragmentShader = second_fs,
+ .pNext =
+ &(VkGraphicsPipelineCreateInfo) {
+ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+ .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
+ QO_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO_DEFAULTS,
+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
+ },
+ .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
+ QO_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO_DEFAULTS
+ },
+ .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {},
+ .renderPass = pass,
+ .layout = second_layout,
+ .subpass = 1,
+ }});
+
+ VkImage layered_image = qoCreateImage(t_device,
+ .imageType = VK_IMAGE_TYPE_2D,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .tiling = VK_IMAGE_TILING_OPTIMAL,
+ .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
+ .mipLevels = 1,
+ .arrayLayers = 2,
+ .extent = {
+ .width = t_width,
+ .height = t_height,
+ .depth = 1,
+ });
+
+ VkMemoryRequirements mem_reqs;
+ vkGetImageMemoryRequirements(t_device, layered_image, &mem_reqs);
+
+ VkDeviceMemory layered_mem = qoAllocMemoryFromRequirements(t_device, &mem_reqs);
+ qoBindImageMemory(t_device, layered_image, layered_mem, 0);
+
+ VkImageView full_image_view = qoCreateImageView(t_device,
+ QO_IMAGE_VIEW_CREATE_INFO_DEFAULTS,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .image = layered_image,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ .subresourceRange.layerCount = 2);
+
+ VkImageView first_image_view = qoCreateImageView(t_device,
+ QO_IMAGE_VIEW_CREATE_INFO_DEFAULTS,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .image = layered_image,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ .subresourceRange.layerCount = 1);
+
+ VkImageView second_image_view = qoCreateImageView(t_device,
+ QO_IMAGE_VIEW_CREATE_INFO_DEFAULTS,
+ .format = VK_FORMAT_R8G8B8A8_UNORM,
+ .image = layered_image,
+ .viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
+ .subresourceRange.baseArrayLayer = 1,
+ .subresourceRange.layerCount = 1);
+
+ VkImageView attachments[] = {
+ full_image_view,
+ first_image_view,
+ second_image_view,
+
+ // We create a new framebuffer but reuse the framework's image
+ // view as a final output, so we get the bootstrapping and
+ // comparing logic for free.
+ t_color_image_view,
+ };
+
+ VkFramebuffer framebuffer = qoCreateFramebuffer(t_device,
+ .renderPass = pass,
+ .width = t_width,
+ .height = t_height,
+ .layers = 1,
+ .attachmentCount = 4,
+ .pAttachments = attachments);
+
+ VkDescriptorSet set = qoAllocateDescriptorSet(t_device,
+ .descriptorPool = t_descriptor_pool,
+ .pSetLayouts = &set_layout);
+
+ vkUpdateDescriptorSets(t_device,
+ 1, /* writeCount */
+ &(VkWriteDescriptorSet) {
+ .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ .dstSet = set,
+ .dstBinding = 0,
+ .dstArrayElement = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+ .descriptorCount = 2,
+ .pImageInfo = (VkDescriptorImageInfo[]) {
+ {
+ .imageView = first_image_view,
+ .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ },
+ {
+ .imageView = second_image_view,
+ .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+ },
+ },
+ }, 0, NULL);
+
+ vkCmdBeginRenderPass(t_cmd_buffer,
+ &(VkRenderPassBeginInfo) {
+ .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+ .renderPass = pass,
+ .framebuffer = framebuffer,
+ .renderArea = { { 0, 0 }, { t_width, t_height } },
+ .clearValueCount = 4,
+ .pClearValues = (VkClearValue[]) {
+ { .color = { .float32 = {0.0, 0.0, 0.0, 1.0} } },
+ { .color = { .float32 = {0.0, 0.0, 0.0, 1.0} } },
+ { .color = { .float32 = {0.0, 0.0, 0.0, 1.0} } },
+ { .color = { .float32 = {0.0, 0.0, 0.0, 1.0} } },
+ }
+ }, VK_SUBPASS_CONTENTS_INLINE);
+
+ // Draw triangle in both views, with displacement based on the view index.
+ vkCmdBindPipeline(t_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, first_pipeline);
+ vkCmdDraw(t_cmd_buffer, 3, 1, 0, 0);
+
+ // Render the views side by side.
+ vkCmdNextSubpass(t_cmd_buffer, VK_SUBPASS_CONTENTS_INLINE);
+ vkCmdBindPipeline(t_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, second_pipeline);
+ vkCmdBindDescriptorSets(t_cmd_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, second_layout,
+ 0, 1, &set, 0, NULL);
+ vkCmdDraw(t_cmd_buffer, 6, 1, 0, 0);
+
+ vkCmdEndRenderPass(t_cmd_buffer);
+ qoEndCommandBuffer(t_cmd_buffer);
+ qoQueueSubmit(t_queue, 1, &t_cmd_buffer, VK_NULL_HANDLE);
+}
+
+test_define {
+ .name = "func.multiview",
+ .start = test_multiview,
+};
--
2.19.0
More information about the Piglit
mailing list