Vulkan学习--9.创建图像管线

在进行管线创建之前,我们还需要设置用于渲染的帧缓冲附着。渲染流程对象

创建图像管线

可编程阶段:

1.载入着色器
2.创建着色器模块
3.创建着色器阶段

固定功能阶段:

在 Vulkan 不存在默认状态,所有状态必须被显式地设置,无论是视口大小,还是使用的
颜色混合函数都需要显式地指定。
1.顶点输入
2.输入装配
3.视口和剪裁
4.光栅化
5.多重采样
6.深度和模版测试
7.颜色混合
8.动态状态
9.管线布局

示例Demo:

//读取编译的二进制着色器文件--9
static std::vector<char> readFile(const std::string& filename){
    //ate:从文件尾部开始读取,可以根据读取位置确定文件的大小,分配足够的数组空间来容纳数据
    //binary:以二进制的形式读取文件 (避免进行诸如行末格式是 \n 还是\r\n 的转换)
    std::ifstream file(filename,std::ios::ate | std::ios::binary);
    if(!file.is_open()){
        throw std::runtime_error("failed to open file!");
    }
    //获取文件大小
    size_t fileSize = (size_t)file.tellg();
    std::vector<char> buffer(fileSize);
    file.seekg(0);
    file.read(buffer.data(),fileSize);
    file.close();
    return buffer;
}

    VkRenderPass renderPass;//渲染流程对象--9
    VkPipelineLayout pipelineLayout;//管线布局--9
    VkPipeline graphicsPipeline;//管线对象--9

    //使用我们读取的着色器字节码数组作为参数来创建 VkShaderModule 对象--9
    VkShaderModule createShaderModule(const std::vector<char>& code){
        VkShaderModuleCreateInfo createInfo = {};
        createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
        /**
        指定存储字节码的数组和数组长度
        需要先将存储字节码的数组指针转换为 const uint32_t* 变量类型,
        来匹配结构体中的字节码指针的变量类型。
        我们指定的指针指向的地址应该符合 uint32_t变量类型的内存对齐方式.
        使用的 std::vector,它的默认分配器分配的内存的地址符合这一要求.
        */
        createInfo.codeSize = code.size();
        createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
        VkShaderModule shaderModule;
        //创建 VkShaderModule对象
        if(vkCreateShaderModule(device,&createInfo,nullptr,
                                &shaderModule) != VK_SUCCESS){
            throw std::runtime_error("failed to create shader module!");
        }
        return shaderModule;
    }


    //创建图形管线--9
    void createGraphicsPipeline(){
        //着色器字节码的读取
        auto vertShaderCode = readFile(
                    "E:/workspace/Qt5.6/VulkanLearn/shaders/vert.spv");
        auto fragShaderCode = readFile(
                    "E:/workspace/Qt5.6/VulkanLearn/shaders/frag.spv");
        //VkShaderModule是一个对着色器字节码的包装
        VkShaderModule vertShaderModule;
        VkShaderModule fragShaderModule;
        vertShaderModule = createShaderModule(vertShaderCode);
        fragShaderModule = createShaderModule(fragShaderCode);
        //VkPipelineShaderStageCreateInfo指定着色器哪一阶段被使用
        //点着色器
        VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
        vertShaderStageInfo.sType =
                VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        /**
        指定了着色器在管线的哪一阶段被使用。每个可编程阶段都有一个对应这一阶段的枚举值,
        我们使用这一枚举值指定着色器被使用的阶段
          */
        vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
        //指定阶段使用的着色器模块对象
        vertShaderStageInfo.module = vertShaderModule;
        //指定阶段调用的着色器函数
        vertShaderStageInfo.pName = "main";
        //片段着色器
        VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
        fragShaderStageInfo.sType =
                VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
        fragShaderStageInfo.module = fragShaderModule;
        fragShaderStageInfo.pName = "main";
        /**
          pSpecializationInfo--指定着色器用到的常量,
        我们可以对同一个着色器模块对象指定不同的着色器常量用于管线创建,这
        使得编译器可以根据指定的着色器常量来消除一些条件分支,这比在渲染
        时,使用变量配置着色器带来的效率要高得多。如果不使用着色器常量,
        可以将 pSpecializationInfo 成员变量设置为 nullptr。
          */
        VkPipelineShaderStageCreateInfo shaderStages [] = {
            vertShaderStageInfo , fragShaderStageInfo
        };

        /**
          描述内容主要包括下面两个方面:
        绑定:数据之间的间距和数据是按逐顶点的方式还是按逐实例的方式进行组织
        属性描述:传递给顶点着色器的属性类型,用于将属性绑定到顶点着色器中的变量
        由于我们直接在顶点着色器中硬编码顶点数据,so这里不载入任何顶点数据
          */
        //描述传递给顶点着色器的顶点数据格式--顶点输入
        VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
        vertexInputInfo.sType =
                VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
        vertexInputInfo.vertexBindingDescriptionCount=0;
        //用于指向描述顶点数据组织信息地结构体数组
        vertexInputInfo.pVertexBindingDescriptions=nullptr;
        vertexInputInfo.vertexAttributeDescriptionCount = 0;
        vertexInputInfo.pVertexAttributeDescriptions = nullptr;
        /**
        VkPipelineInputAssemblyStateCreateInfo 结构体用于描述两个信息:
        1.顶点数据定义了哪种类型的几何图元,通过 topology 成员变量指定:如下值
        VK_PRIMITIVE_TOPOLOGY_POINT_LIST:点图元
        VK_PRIMITIVE_TOPOLOGY_LINE_LIST:每两个顶点构成一个线段图元
        VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:每两个顶点构成一个线段图元,
        除第一个线段图元外,每个线段图元使用上一个线段图元的一个顶点
        VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:每三个顶点构成一个三角形图元
        VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
        每个三角形的第二个和第三个顶点被下一个三角形作为第一和第二个顶点使用
        2.是否启用几何图元重启

        一般我们会通过索引缓冲来更好地复用顶点缓冲中的顶点数据。
          */
        //输入装配
        VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
        inputAssembly.sType =
                VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
        inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
        inputAssembly.primitiveRestartEnable = VK_FALSE;
        /**
        需要注意,交换链图像的大小可能与窗口大小不同。交换链图像在之
        后会被用作帧缓冲,所以这里我们设置视口大小为交换链图像的大小。

        视口定义了图像到帧缓冲的映射关系,裁剪矩形定义了哪一区域的像
        素实际被存储在帧缓存。任何位于裁剪矩形外的像素都会被光栅化程序丢弃.
          */
        //视口和裁剪
        VkViewport viewport = {};
        viewport.x = 0.0f;
        viewport.y = 0.0f;
        viewport.width = (float)swapChainExtent.width;
        viewport.height = (float)swapChainExtent.height;
        //用于指定帧缓冲使用的深度值的范围
        viewport.minDepth = 0.0f;
        viewport.maxDepth = 1.0f;
        //裁剪范围设置
        //这里我们在整个帧缓冲上进行绘制操作,所以将裁剪范围设置为和帧缓冲大小一样
        VkRect2D scissor = {};
        scissor.offset = {0,0};
        scissor.extent = swapChainExtent;
        /**
        许多显卡可以使用多个视口和裁剪矩形,所以指定视口和裁剪矩形的成员变量
        是一个指向视口和裁剪矩形的结构体数组指针。
        使用多个视口和裁剪矩形需要启用相应的特性支持。
          */
        //将视口和裁剪矩形需要组合在一起
        VkPipelineViewportStateCreateInfo viewportState = {};
        viewportState.sType =
                VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
        viewportState.viewportCount = 1;
        viewportState.pViewports = &viewport;
        viewportState.scissorCount = 1;
        viewportState.pScissors = &scissor;
        /**
        光栅化程序将来自顶点着色器的顶点构成的几何图元转换为片段交由片段着色器着色。
        深度测试,背面剔除和裁剪测试如何开启了,也由光栅化程序执行。
        我们可以配置光栅化程序输出整个几何图元作为片段,
        还是只输出几何图元的边作为片段 (也就是线框模式)。
          */
        //配置光栅化程序
        VkPipelineRasterizationStateCreateInfo rasterizer = {};
        rasterizer.sType =
                VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
        /**
          为True表示在近平面和远平面外的片段会被截断为在近平面和远平面上,
          而不是直接丢弃这些片段,这对于阴影贴图的生成很有用。
          使用这一设置需要开启相应的 GPU 特性
          */
        rasterizer.depthClampEnable = VK_FALSE;
        /**
        为True表示所有几何图元都不能通过光栅化阶段.这一设置会禁止一切片段输出到帧缓冲
          */
        rasterizer.rasterizerDiscardEnable = VK_FALSE;
        /**
          指定几何图元生成片段的方式,可以如下:
        VK_POLYGON_MODE_FILL:整个多边形,包括多边形内部都产生片段
        VK_POLYGON_MODE_LINE:只有多边形的边会产生片段
        VK_POLYGON_MODE_POINT:只有多边形的顶点会产生片段
        使用除了 VK_POLYGON_MODE_FILL 外的模式,需要启用相应的 GPU 特性
          */
        rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
        /**
        指定光栅化后的线段宽度,它以线宽所占的片段数目为单位。
        线宽的最大值依赖于硬件,使用大于 1.0f 的线宽,需要启用相应的 GPU 特性
          */
        rasterizer.lineWidth = 1.0f;
        //指定使用的表面剔除类型.我们可以通过它禁用表面剔除,剔除背面,剔除正面,以及剔除双面
        rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
        //指定顺时针的顶点序是正面,还是逆时针的顶点序是正面
        rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
        /**
        光栅化程序可以添加一个常量值或是一个基于片段所处线段的斜率得到的变量值到深度值上。
        这对于阴影贴图会很有用,这里我们不使用,so将depthBiasEnable设为false
          */
        rasterizer.depthBiasEnable = VK_FALSE;
        rasterizer.depthBiasConstantFactor = 0.0f;
        rasterizer.depthBiasClamp = 0.0f;
        rasterizer.depthBiasSlopeFactor = 0.0f;
        /**
        多重采样是一种组合多个不同多边形产生的片段的颜色来决定
        最终的像素颜色的技术,它可以一定程度上减少多边形边缘的走样现象。
        对于一个像素只被一个多边形产生的片段覆盖,只会对覆盖它的这个片段
        执行一次片段着色器,使用多重采样进行反走样的代价要比使用更高的分
        辨率渲染,然后缩小图像达到反走样的代价小得多。使用多重采样需要启
        用相应的 GPU 特性。
          */
        //对多重采样进行配置
        VkPipelineMultisampleStateCreateInfo multisampling = {};
        multisampling.sType =
                VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
        multisampling.sampleShadingEnable = VK_FALSE;
        multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
        //multisampling.minSampleShading = 1.0f;
        multisampling.pSampleMask = nullptr;//进行深度测试和模板测试
        multisampling.alphaToCoverageEnable = VK_FALSE;
        multisampling.alphaToOneEnable = VK_FALSE;
        /**
        片段着色器返回的片段颜色需要和原来帧缓冲中对应像素的颜色进行混合。
        混合的方式有下面两种:
        1.混合旧值和新值产生最终的颜色
        2.使用位运算组合旧值和新值
        有两个用于配置颜色混合的结构体:
        1.VkPipelineColorBlendAttachmentState --
            对每个绑定的帧缓冲进行单独的颜色混合配置
        2.VkPipelineColorBlendStateCreateInfo --
            进行全局的颜色混合配置
          */
        //颜色混合
        VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
        colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
                VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
                VK_COLOR_COMPONENT_A_BIT;
        /**
        blendEnable为false则不会进行混合操作,否则,就会执行指定的混合操作计算新的颜色值.
        计算出的新的颜色值会按照 colorWriteMask 的设置决定写入到帧缓冲的颜色通道
        */
        colorBlendAttachment.blendEnable = VK_FALSE;
        colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
        colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
        colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
        colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
        colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
        colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
        //用于设置全局混合常量
        VkPipelineColorBlendStateCreateInfo colorBlending = {};
        colorBlending.sType =
                VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
        colorBlending.logicOpEnable = VK_FALSE;
        colorBlending.logicOp = VK_LOGIC_OP_COPY;
        colorBlending.attachmentCount = 1;
        //指定每个帧缓冲的颜色混合设置
        colorBlending.pAttachments = &colorBlendAttachment;
        colorBlending.blendConstants[0] = 0.0f;
        colorBlending.blendConstants[1] = 0.0f;
        colorBlending.blendConstants[2] = 0.0f;
        colorBlending.blendConstants[3] = 0.0f;
#if 0
        //动态状态
        //只有非常有限的管线状态可以在不重建管线的情况下进行动态修改。
        //这包括视口大小,线宽和混合常量
        VkDynamicState dynamicStates[] ={
            VK_DYNAMIC_STATE_VIEWPORT,VK_DYNAMIC_STATE_LINE_WIDTH
        };
        //指定需要动态修改的状态
        VkPipelineDynamicStateCreateInfo dynamicState = {};
        dynamicState.sType =
                VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
        dynamicState.dynamicStateCount = 2;
        dynamicState.pDynamicStates = dynamicStates;
#endif
        /**
        我们可以在着色器中使用 uniform 变量,它可以在管线建立后动态地
        被应用程序修改,实现对着色器进行一定程度的动态配置。uniform 变量经
        常被用来传递变换矩阵给顶点着色器,以及传递纹理采样器句柄给片段着色器。
        我们在着色器中使用的uniform变量需要在管线创建时使用VkPipelineLayout对象定义。
        这里暂不使用uniform 变量
          */
        //创建pipelinelayout对象
        VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
        pipelineLayoutInfo.sType =
                VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
        pipelineLayoutInfo.setLayoutCount = 0;
        pipelineLayoutInfo.pSetLayouts = nullptr;
        pipelineLayoutInfo.pushConstantRangeCount = 0;
        pipelineLayoutInfo.pPushConstantRanges = nullptr;
        //VkPipelineLayout 结构体指定可以在着色器中使用的常量值
        if(vkCreatePipelineLayout(device,&pipelineLayoutInfo,nullptr,
                                  &pipelineLayout) != VK_SUCCESS){
            throw std::runtime_error("failed to create pipeline layout!");
        }
        //创建图像管线相关信息
        VkGraphicsPipelineCreateInfo pipelineInfo = {};
        pipelineInfo.sType =
                VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
        //引用之前我们创建的两个着色器阶段
        pipelineInfo.stageCount = 2;
        pipelineInfo.pStages = shaderStages;
        //引用了之前设置的固定功能阶段信息
        pipelineInfo.pVertexInputState = &vertexInputInfo;
        pipelineInfo.pInputAssemblyState = &inputAssembly;
        pipelineInfo.pViewportState = &viewportState;
        pipelineInfo.pRasterizationState = &rasterizer;
        pipelineInfo.pMultisampleState = &multisampling;
        pipelineInfo.pDepthStencilState = nullptr;
        pipelineInfo.pColorBlendState = &colorBlending;
        pipelineInfo.pDynamicState = nullptr;
        //指定之前创建的管线布局
        pipelineInfo.layout = pipelineLayout;
        //引用之前创建的渲染流程对象和图形管线使用的子流程在子流程数组中的索引
        //在之后的渲染过程中,仍然可以使用其它与这个设置的渲染流程对象相兼容的渲染流程。
        pipelineInfo.renderPass = renderPass;
        pipelineInfo.subpass = 0;
        /**
        basePipelineHandle 和 basePipelineIndex 成员变量用于以一个创建好
        的图形管线为基础创建一个新的图形管线。当要创建一个和已有管线大量
        设置相同的管线时,使用它的代价要比直接创建小,并且,对于从同一个
        管线衍生出的两个管线,在它们之间进行管线切换操作的效率也要高很
        多。我们可以使用 basePipelineHandle 来指定已经创建好的管线,或是使
        用 basePipelineIndex 来指定将要创建的管线作为基础管线,用于衍生新
        的管线。目前,我们只使用一个管线,所以将这两个成员变量分别设置为
        VK_NULL_HANDLE 和 -1,不使用基础管线衍生新的管线。这两个成员
        变量的设置只有在 VkGraphicsPipelineCreateInfo 结构体的 flags 成员变量
        使用了 VK_PIPELINE_CREATE_DERIVATIVE_BIT 标记的情况下才会起效。
          */
        pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
        pipelineInfo.basePipelineIndex = -1;
        /**
        这里可以调用可以通过多个 VkGraphicsPipelineCreateInfo
        结构体数据创建多个 VkPipeline 对象.
        第二个参数可以用来引用一个可选的VkPipelineCache 对象。
        通过它可以将管线创建相关的数据进行缓存在多
        个 vkCreateGraphicsPipelines 函数调用中使用,甚至可以将缓存存入文件,
        在多个程序间使用。使用它可以加速之后的管线创建.
          */
        //创建管线对象
        if(vkCreateGraphicsPipelines(device,VK_NULL_HANDLE,1,
                                     &pipelineInfo,nullptr,
                                     &graphicsPipeline) != VK_SUCCESS){
            throw std::runtime_error("failed to create graphics pipeline!");
        }
        vkDestroyShaderModule(device,fragShaderModule,nullptr);
        vkDestroyShaderModule(device,vertShaderModule,nullptr);
    }
    /**
      渲染流程对象包含:
        指定使用的颜色和深度缓冲,以及采样数,渲染操作如何处理缓冲的内容
      */
    //创建渲染流程对象--9
    void createRenderPass(){
        //代表交换链图像的颜色缓冲附着
        VkAttachmentDescription colorAttachment = {};
        //format指定颜色缓冲附着的格式
        colorAttachment.format = swapChainImageFormat;
        //samples指定采样数,这里我们没有使用多重采样,所以将采样数设置为 1。
        colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
        /**
        loadOp 和 storeOp 成员变量用于指定在渲染之前和渲染之后对附着中的数据进行的操作.
        loadOp可以设置为下面这些值:
        VK_ATTACHMENT_LOAD_OP_LOAD:保持附着的现有内容
        VK_ATTACHMENT_LOAD_OP_CLEAR:使用一个常量值来清除附着的内容
        VK_ATTACHMENT_LOAD_OP_DONT_CARE:不关心附着现存的内容
        storeOp 可以设置为下面这些值:
        VK_ATTACHMENT_STORE_OP_STORE:渲染的内容会被存储起来,以便之后读取
        VK_ATTACHMENT_STORE_OP_DONT_CARE:渲染后,不会读取帧缓冲的内容

        loadOp 和 storeOp 成员变量的设置会对颜色和深度缓冲起效
          */
        //每次渲染新的一帧前使用黑色清除帧缓冲
        colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
        colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
        //stencilLoadOp成员变量和stencilStoreOp成员变量会对模板缓冲起效,这里未使用
        colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
        colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
        /**
        Vulkan 中的纹理和帧缓冲由特定像素格式的 VkImage 对象来表示。
        图像的像素数据在内存中的分布取决于我们要对图像进行的操作.
        下面是一些常用的图形内存布局设置:
        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:图像被用作颜色附着
        VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:图像被用在交换链中进行呈现操作
        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:图像被用作复制操作的目的图像
          */
        //指定渲染流程开始前的图像布局方式,这里了表示不关心之前的图像布局方式
        //使用这一值后,图像的内容不保证会被保留,但对于我们的应用程序,每次渲染前都要清除图像
        colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
        //于指定渲染流程结束后的图像布局方式
        //这里设置使得渲染后的图像可以被交换链呈现。
        colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
        /**
        一个渲染流程可以包含多个子流程。子流程依赖于上一流程处理后的
        帧缓冲内容。比如,许多叠加的后期处理效果就是在上一次的处理结果上
        进行的。我们将多个子流程组成一个渲染流程后,Vulkan 可以对其进行一
        定程度的优化。对于我们这个渲染三角形的程序,我们只使用了一个子流程.

        每个子流程可以引用一个或多个附着
          */
        //指定引用的附着
        VkAttachmentReference colorAttachmentRef = {};
        //指定要引用的附着在附着描述结构体数组中的索引
        colorAttachmentRef.attachment = 0;
        /**
        指定进行子流程时引用的附着使用的布局方式,Vulkan 会在子流程开始时自动将引用
        的附着转换到 layout 成员变量指定的图像布局.
        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL性能表现最佳
        */
        colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        //描述子流程
        VkSubpassDescription subpass = {};
        //显式地指定这是一个图形渲染的子流程
        subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
        /**
        这里设置的颜色附着在数组中的索引会被片段着色器使用,对应我们
        在片段着色器中使用的 layout(location = 0) out vec4 outColor 语句。
        下面是其它一些可以被子流程引用的附着类型:
        pInputAttachments:被着色器读取的附着
        pResolveAttachments:用于多重采样的颜色附着
        pDepthStencilAttachment:用于深度和模板数据的附着
        pPreserveAttachments:没有被这一子流程使用,但需要保留数据的附着
          */
        //们指定引用的颜色附着个数和地址
        subpass.colorAttachmentCount = 1;
        subpass.pColorAttachments = &colorAttachmentRef;

        VkSubpassDependency dependency = {};
        dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
        dependency.dstSubpass = 0;
        dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
        dependency.srcAccessMask = 0;
        dependency.dstStageMask =
                VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
        dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
                | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;

        //创建渲染流程对象相关信息
        VkRenderPassCreateInfo renderPassInfo = {};
        renderPassInfo.sType =
                VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
        renderPassInfo.attachmentCount = 1;
        renderPassInfo.pAttachments = &colorAttachment;
        renderPassInfo.subpassCount = 1;
        renderPassInfo.pSubpasses = &subpass;
        renderPassInfo.dependencyCount = 1;
        renderPassInfo.pDependencies = &dependency;
        //创建渲染流程对象
        if(vkCreateRenderPass(device,&renderPassInfo,nullptr,
                              &renderPass) != VK_SUCCESS){
            throw std::runtime_error("failed to create render pass!");
        }

    }
        //销毁管线对象--9
        vkDestroyPipeline ( device , graphicsPipeline , nullptr );
        //销毁管线布局对象--9
        vkDestroyPipelineLayout ( device , pipelineLayout , nullptr);
        //销毁渲染流程对象--9
        vkDestroyRenderPass ( device , renderPass , nullptr );

创建图形管线而创建的对象:
• 着色器阶段:定义了着色器模块用于图形管线哪一可编程阶段
• 固定功能状态:定义了图形管线的固定功能阶段使用的状态信息,比如输入装配,视口,光栅化,颜色混合
• 管线布局:定义了被着色器使用,在渲染时可以被动态修改的 uniform 变量
• 渲染流程:定义了被管线使用的附着附着的用途

猜你喜欢

转载自blog.csdn.net/yuxing55555/article/details/88989042
今日推荐