【Vulkan】Variable Rate Shading(一)【VRS】

Variable Rate Shading

配置

依赖、特性、属性

  • 使能 Device 扩展:
    VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME 或者 “VK_KHR_fragment_shading_rate”

  • 查询 DeviceFeature(依赖 vkGetPhysicalDeviceFeatures2
    VkPhysicalDeviceFragmentShadingRateFeaturesKHR

    • pipelineFragmentShadingRate :per-draw fragment shading rate 基于 drawcall 粒度
    • primitiveFragmentShadingRate :per-triangle fragment shading rate 基于 triangle 粒度
    • attachmentFragmentShadingRate :per-screen-region fragment shading rate 基于屏幕空间区域粒度
  • 查询 DeviceProperties(依赖 vkGetPhysicalDeviceProperties2

typedef struct VkPhysicalDeviceFragmentShadingRatePropertiesKHR {
    VkStructureType          sType;
    void*                    pNext;
    VkExtent2D               minFragmentShadingRateAttachmentTexelSize;
    VkExtent2D               maxFragmentShadingRateAttachmentTexelSize;
    uint32_t                 maxFragmentShadingRateAttachmentTexelSizeAspectRatio;
    VkBool32                 primitiveFragmentShadingRateWithMultipleViewports;
    VkBool32                 layeredShadingRateAttachments;
    VkBool32                 fragmentShadingRateNonTrivialCombinerOps;
    VkExtent2D               maxFragmentSize;
    uint32_t                 maxFragmentSizeAspectRatio;
    uint32_t                 maxFragmentShadingRateCoverageSamples;
    VkSampleCountFlagBits    maxFragmentShadingRateRasterizationSamples;
    VkBool32                 fragmentShadingRateWithShaderDepthStencilWrites;
    VkBool32                 fragmentShadingRateWithSampleMask;
    VkBool32                 fragmentShadingRateWithShaderSampleMask;
    VkBool32                 fragmentShadingRateWithConservativeRasterization;
    VkBool32                 fragmentShadingRateWithFragmentShaderInterlock;
    VkBool32                 fragmentShadingRateWithCustomSampleLocations;
    VkBool32                 fragmentShadingRateStrictMultiplyCombiner;
} VkPhysicalDeviceFragmentShadingRatePropertiesKHR;
  • 查询 FragmentShadingRates
    fragment shading rate 与 MutliSample 密切相关,可通过 vkGetPhysicalDeviceFragmentShadingRatesKHR 返回一组排序后的 Device 支持的 [fragmentSize, multiSample] 配置。

    • width 与 height 必须为 2^N
    • width * height * maxSample <= maxFragmentShadingRateCoverageSamples

    厂商实现必须至少支持:

    samplerCountsfragmentSize
    VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT{2,2}
    VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT{2,1}
    ~0{1,1}

Pipeline Fragment Shading Rate (per draw)

typedef struct VkPipelineFragmentShadingRateStateCreateInfoKHR {
    VkStructureType                       sType;
    const void*                           pNext;
    VkExtent2D                            fragmentSize;
    VkFragmentShadingRateCombinerOpKHR    combinerOps[2];
} VkPipelineFragmentShadingRateStateCreateInfoKHR;

fragmentSize :定义使用当前 pso 绘制区域 pipeline fragment shadeing rate 的大小。
combinerOps[0] :组合 pipeline and primitive
combinerOps[1] :组合 [0] 结果 和 attachment

组合选项:

CombinerOpresult
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHRCombine(A, B) = A
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHRCombine(A, B) = B
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHRCombine(A, B) = min(A, B)
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHRCombine(A, B) = max(A, B)
VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHRCombine(A, B) = A * B

简单的 4 x 4 pipeline perDraw 试验,下图左边三角形关闭 vrs,右边开启

Primitive Fragment Shading Rate (per primitive)

主要在 shader 中进行处理,需要 glsl 扩展 GL_EXT_fragment_shading_rate

新增关键字:

关键字说明
gl_ShadingRateEXTprimitive shading rate 输出
gl_ShadingRateFlag2VerticalPixelsEXTVertical2Pixels,bitValue: 1
gl_ShadingRateFlag4VerticalPixelsEXTVertical4Pixels,bitValue: 2
gl_ShadingRateFlag2HorizontalPixelsEXTHorizontal2Pixels,bitValue: 4
gl_ShadingRateFlag4HorizontalPixelsEXTHorizontal4Pixels,bitValue: 8
gl_PrimitiveShadingRateEXTfragment shader 输入

VS 中处理示例:

void main() {
    gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
    gl_PrimitiveShadingRateEXT = gl_ShadingRateFlag2VerticalPixelsEXT | gl_ShadingRateFlag2HorizontalPixelsEXT;
//    gl_PrimitiveShadingRateEXT = gl_ShadingRateFlag2VerticalPixelsEXT | gl_ShadingRateFlag4HorizontalPixelsEXT;
//    gl_PrimitiveShadingRateEXT = gl_ShadingRateFlag4VerticalPixelsEXT | gl_ShadingRateFlag2HorizontalPixelsEXT;
//    gl_PrimitiveShadingRateEXT = gl_ShadingRateFlag4VerticalPixelsEXT | gl_ShadingRateFlag4HorizontalPixelsEXT;
    outColor = color[gl_VertexIndex];
}

Attachment Fragment Shading Rate (per screen retion)

使用 RenderPass 进行配置,需要 ‘vkCreateRenderPass2’,基于 SubPass 粒度,pNext 添加结构体

typedef struct VkFragmentShadingRateAttachmentInfoKHR {
    VkStructureType                  sType;
    const void*                      pNext;
    const VkAttachmentReference2*    pFragmentShadingRateAttachment;
    VkExtent2D                       shadingRateAttachmentTexelSize;
} VkFragmentShadingRateAttachmentInfoKHR;

shadingRateAttachmentTexelSize 受以下限制

  • minFragmentShadingRateAttachmentTexelSize, 需要 2^N, Spec 保证至少支持(32, 32)
  • maxFragmentShadingRateAttachmentTexelSize, 需要 2^N, Spec 保证至少支持(8, 8)
  • maxFragmentShadingRateAttachmentTexelSizeAspectRatio

添加 ShadingRateAttachment,同时增加

  • Access Flag: VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHRVK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV
  • PipelineStage: VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHRVK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV
  • Image Usage:VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHRVK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV
  • Image Layout:VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHRVK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV

对应的 FrameBuffer 只需要添加对应的 slot 的 ImageView 即可,需要控制 ShadingRate Attachment 大小

  • width:fbWidth / texelWidth
  • height: fbHeight / texelHeight

参考连接:

<think>好的,用户现在想了解如何创建个使用SDL窗口的Vulkan程序。之前他们问过关于vkEnumerateInstanceExtensionProperties的第个参数的作用,现在可能是在进步学习Vulkan和SDL的结合使用。我需要先确定用户的需求,他们可能是在开始学习Vulkan,并希望了解如何将它与SDL窗口系统集成。 首先,我需要回忆SDL和Vulkan结合的基本步骤。SDL可以创建窗口,然后通过Vulkan的扩展来获取表面(Surface),这是连接窗口系统和Vulkan的关键。用户可能需要个从零开始的步骤指南,包括初始化SDL、创建窗口、初始化Vulkan实例、创建表面等步骤。 接下来,我需要考虑用户可能的背景。他们可能对Vulkan定了解,但可能不熟悉与SDL的结合使用。因此,回答需要结构清晰,分步骤说明,并包含代码示例,同时解释关键点,比如启用必要的扩展、创建Surface的过程。 用户可能遇到的问题包括如何正确启用Vulkan的实例扩展,特别是与SDL相关的扩展。需要指出使用SDL的函数(如SDL_Vulkan_GetInstanceExtensions)来获取所需的扩展列表,这可以避免手动管理扩展名称,减少错误。 另外,需要注意不同平台(如Windows、Linux、macOS)可能存在的差异,但使用SDL可以帮助抽象这些差异,简化跨平台开发。因此,在代码示例中展示如何通过SDL获取扩展名称是很重要的。 还需要提醒用户关于Vulkan资源的清理,比如销毁Surface和实例,以及关闭SDL窗口和库。这些是常见的资源管理问题,容易被初学者忽略。 此外,用户可能在整合SDL和Vulkan时遇到编译或链接问题,比如需要正确包含SDL和Vulkan的头文件,链接对应的库文件。虽然回答中可能无法详细说明所有平台的配置,但可以给出个基本的编译命令示例,帮助用户开始。 最后,确保回答符合之前用户提到的格式要求:使用中文,行内公式用$...$,独立公式用$$...$$(虽然这里可能用不上),结构清晰,分步骤说明,代码示例正确,并注意Vulkan函数的使用和错误检查的重要性。</think>以下是使用**SDL**创建窗口并集成Vulkan的**分步指南**,包含关键代码示例和注意事项: --- ### **、环境准备** 1. **安装依赖库** - **SDL2**: 提供窗口管理和跨平台支持 - **Vulkan SDK**: 确保安装并配置环境变量(如`VULKAN_SDK`路径) - **编译器**: 支持C++11及以上(如GCC、MSVC、Clang) 2. **项目配置** - **包含路径**: 添加SDL2和Vulkan头文件目录 - **链接库**: - Windows: `SDL2.lib`, `vulkan-1.lib` - Linux: `-lSDL2 -lvulkan` --- ### **二、代码实现步骤** #### **步骤1:初始化SDL并创建窗口** ```cpp #include <SDL2/SDL.h> #include <SDL2/SDL_vulkan.h> #include <vulkan/vulkan.h> #include <vector> #include <iostream> int main() { // 初始化SDL if (SDL_Init(SDL_INIT_VIDEO) != 0) { std::cerr << "SDL初始化失败: " << SDL_GetError() << std::endl; return -1; } // 创建SDL窗口(支持Vulkan) SDL_Window* window = SDL_CreateWindow( "Vulkan SDL窗口", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN ); if (!window) { std::cerr << "窗口创建失败: " << SDL_GetError() << std::endl; SDL_Quit(); return -1; } ``` #### **步骤2:获取Vulkan实例扩展(通过SDL)** ```cpp // 获取SDL所需的Vulkan实例扩展 uint32_t extensionCount = 0; SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, nullptr); std::vector<const char*> extensions(extensionCount); SDL_Vulkan_GetInstanceExtensions(window, &extensionCount, extensions.data()); ``` #### **步骤3:创建Vulkan实例** ```cpp VkInstance instance = VK_NULL_HANDLE; VkInstanceCreateInfo instanceInfo = {}; instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size()); instanceInfo.ppEnabledExtensionNames = extensions.data(); // 可选:启用校验层(调试用) const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; instanceInfo.enabledLayerCount = 1; instanceInfo.ppEnabledLayerNames = layers; if (vkCreateInstance(&instanceInfo, nullptr, &instance) != VK_SUCCESS) { std::cerr << "Vulkan实例创建失败" << std::endl; SDL_DestroyWindow(window); SDL_Quit(); return -1; } ``` #### **步骤4:创建Vulkan表面(Surface)** ```cpp VkSurfaceKHR surface = VK_NULL_HANDLE; if (!SDL_Vulkan_CreateSurface(window, instance, &surface)) { std::cerr << "Surface创建失败" << std::endl; vkDestroyInstance(instance, nullptr); SDL_DestroyWindow(window); SDL_Quit(); return -1; } ``` #### **步骤5:主循环与清理** ```cpp // 主循环 bool running = true; while (running) { SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { running = false; } } } // 清理资源 vkDestroySurfaceKHR(instance, surface, nullptr); vkDestroyInstance(instance, nullptr); SDL_DestroyWindow(window); SDL_Quit(); return 0; } ``` --- ### **三、关键注意事项** 1. **扩展的自动获取** - 使用`SDL_Vulkan_GetInstanceExtensions`确保获取**平台相关扩展**(如`VK_KHR_surface`、`VK_KHR_win32_surface`等),避免手动管理。 2. **校验层(Validation Layers)** - 调试时启用校验层(如`VK_LAYER_KHRONOS_validation`)可帮助捕获API误用,但需确保已安装Vulkan SDK。 3. **跨平台兼容性** - SDL自动处理不同平台的窗口系统(如Windows的`HWND`、Linux的`xlib`),简化跨平台开发。 4. **后续步骤** - 在Surface基础上继续创建**物理设备(GPU)**、**逻辑设备**、**交换链(Swapchain)**等组件。 --- ### **四、编译与运行** #### **Linux/macOS** ```bash g++ main.cpp -o vulkan_sdl -lSDL2 -lvulkan ``` #### **Windows (Visual Studio)** - 在项目属性中配置SDL2和Vulkan库路径。 --- 通过上述步骤,你可以成功创建个**SDL窗口**并集成Vulkan渲染框架的空白程序。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zach013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值