+ /* FIXME */
+ /* format of vertex attributes:
+ * we have 2D vectors so we need a RG format:
+ * R for x, G for y
+ * the stride (distance between 2 consecutive elements)
+ * must be 8 because we use 32 bit floats and
+ * 32bits = 8bytes */
+ format = VK_FORMAT_R32G32_SFLOAT;
+ vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
+ assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
+ stride = 8;
+
+ // create_vertex_descriptions(ctx, renderer->geometry, 1, vert_bind_dsc, 1, vert_att_dsc);
+ memset(vert_att_dsc, 0, 4 * sizeof vert_att_dsc[0]);
+ memset(vert_bind_dsc, 0, 4 * sizeof vert_bind_dsc[0]);
+
+ /* VkVertexInputAttributeDescription */
+ vert_att_dsc[0].location = 0;
+ vert_att_dsc[0].binding = 0;
+ vert_att_dsc[0].format = format; /* see comment */
+ vert_att_dsc[0].offset = 0;
+
+ /* VkVertexInputBindingDescription */
+ vert_bind_dsc[0].binding = 0;
+ vert_bind_dsc[0].stride = stride;
+ vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ /* If using vbo, we have setup vertex_info in the renderer. */
+ bool has_geometry = renderer->geometry;
+
+ /* VkPipelineVertexInputStateCreateInfo */
+ memset(&vert_input_info, 0, sizeof vert_input_info);
+ vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vert_input_info.vertexBindingDescriptionCount = renderer->geometry ? 1 : 0;
+ vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
+ vert_input_info.vertexAttributeDescriptionCount = renderer->geometry ? 1 : 0;
+ vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
+
+ /* VkPipelineInputAssemblyStateCreateInfo */
+ memset(&asm_info, 0, sizeof asm_info);
+ asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ asm_info.topology = has_geometry ?
+ renderer->geometry->topo
+ : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ asm_info.primitiveRestartEnable = false;
+
+ /* VkViewport */
+ viewport.x = viewport.y = 0;
+ viewport.width = width;
+ viewport.height = height;
+ viewport.minDepth = 0;
+ viewport.maxDepth = 1;
+
+ /* VkRect2D scissor */
+ scissor.offset.x = scissor.offset.y = 0;
+ scissor.extent.width = width;
+ scissor.extent.height = height;
+
+ /* VkPipelineViewportStateCreateInfo */
+ memset(&viewport_info, 0, sizeof viewport_info);
+ viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewport_info.viewportCount = 1;
+ viewport_info.pViewports = &viewport;
+ viewport_info.scissorCount = 1;
+ viewport_info.pScissors = &scissor;
+
+ /* VkPipelineRasterizationStateCreateInfo */
+ memset(&rs_info, 0, sizeof rs_info);
+ rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rs_info.polygonMode = VK_POLYGON_MODE_FILL;
+ rs_info.cullMode = VK_CULL_MODE_NONE;
+ rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ rs_info.lineWidth = 1.0;
+
+ /* VkPipelineMultisampleStateCreateInfo */
+ memset(&ms_info, 0, sizeof ms_info);
+ ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ ms_info.rasterizationSamples = get_num_samples(num_samples);
+
+ /* VkStencilOpState */
+ /* The default values for ES are taken by Topi Pohjolainen's code */
+ /* defaults in OpenGL ES 3.1 */
+ memset(&front, 0, sizeof front);
+ front.compareMask = ~0;
+ front.writeMask = ~0;
+ front.reference = 0;
+
+ memset(&back, 0, sizeof back);
+ back.compareMask = ~0;
+ back.writeMask = ~0;
+ back.reference = 0;
+
+ /* VkPipelineDepthStencilStateCreateInfo */
+ memset(&ds_info, 0, sizeof ds_info);
+ ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+ ds_info.front = front;
+ ds_info.back = back;
+ /* defaults in OpenGL ES 3.1 */
+ ds_info.minDepthBounds = 0;
+ ds_info.maxDepthBounds = 1;
+ /* z buffer, stencil buffer */
+ if (enable_depth) {
+ ds_info.depthTestEnable = VK_TRUE;
+ ds_info.depthWriteEnable = VK_TRUE;
+ ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
+ }
+ if (enable_stencil) {
+ ds_info.stencilTestEnable = VK_TRUE;
+ ds_info.depthTestEnable = VK_FALSE;
+ ds_info.depthWriteEnable = VK_TRUE;
+ }
+
+ /* we only care about the passOp here */
+ ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
+ ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
+ ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
+ ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
+ ds_info.back.compareMask = 0xffffffff;
+ ds_info.back.writeMask = 0xffffffff;
+ ds_info.back.reference = 1;
+ ds_info.front = ds_info.back;
+
+ /* VkPipelineColorBlendAttachmentState */
+ cb_att_state = malloc(num_color_atts * sizeof cb_att_state[0]);
+ if (!cb_att_state) {
+ fprintf(stderr, "Failed to allocate color blend attachment state for each attachment.\n");
+ goto fail;
+ }
+ memset(cb_att_state, 0, num_color_atts * sizeof cb_att_state[0]);
+ for (i = 0; i < num_color_atts; i++) {
+ cb_att_state[i].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
+ VK_COLOR_COMPONENT_G_BIT |
+ VK_COLOR_COMPONENT_B_BIT |
+ VK_COLOR_COMPONENT_A_BIT);
+ }
+
+ /* VkPipelineColorBlendStateCreateInfo */
+ memset(&cb_info, 0, sizeof cb_info);
+ cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ cb_info.attachmentCount = num_color_atts;
+ cb_info.pAttachments = cb_att_state;
+ /* default in ES 3.1 */
+ for (i = 0; i < 4; i++) {
+ cb_info.blendConstants[i] = 0.0f;
+ }
+
+ /* VkPipelineShaderStageCreateInfo */
+ memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
+
+ sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
+ sdr_stages[0].module = renderer->vs;
+ sdr_stages[0].pName = "main";
+
+ sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ sdr_stages[1].module = renderer->fs;
+ sdr_stages[1].pName = "main";
+
+ /* VkPushConstantRange */
+ memset(pc_range, 0, sizeof pc_range[0]);
+ pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+ pc_range[0].size = sizeof (struct vk_dims); /* w, h */
+
+ /* VkPipelineLayoutCreateInfo */
+ memset(&layout_info, 0, sizeof layout_info);
+ layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ layout_info.pushConstantRangeCount = 1;
+ layout_info.pPushConstantRanges = pc_range;
+
+ if (vkCreatePipelineLayout(ctx->dev, &layout_info,
+ 0, &pipeline_layout) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create pipeline layout\n");
+ renderer->pipeline = VK_NULL_HANDLE;
+ goto fail;
+ }
+
+ renderer->pipeline_layout = pipeline_layout;
+
+ /* VkGraphicsPipelineCreateInfo */
+ memset(&pipeline_info, 0, sizeof pipeline_info);
+ pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipeline_info.layout = pipeline_layout;
+ pipeline_info.renderPass = renderer->renderpass;
+ pipeline_info.pVertexInputState = &vert_input_info;
+ pipeline_info.pInputAssemblyState = &asm_info;
+ pipeline_info.pViewportState = &viewport_info;
+ pipeline_info.pRasterizationState = &rs_info;
+ pipeline_info.pMultisampleState = &ms_info;
+ pipeline_info.pDepthStencilState = &ds_info;
+ pipeline_info.pColorBlendState = &cb_info;
+ pipeline_info.stageCount = 2;
+ pipeline_info.pStages = sdr_stages;
+
+ if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
+ &pipeline_info, 0,
+ &renderer->pipeline) != VK_SUCCESS) {
+ fprintf(stderr, "Failed to create graphics pipeline.\n");
+ renderer->pipeline = VK_NULL_HANDLE;
+ goto fail;
+ }