有没有一种方法可以在不使用暂存缓冲区的情况下更新纹理?

2024-01-08

我正在与https://vulkan-tutorial.com/ https://vulkan-tutorial.com/深度缓冲代码作为基础。进行了一些更改以每帧更新命令缓冲区。

我正在使用一种粗略的方法来检查 fps。不确定它到底有多准确,但我正在对 fps 使用此检查。

            static auto startTime = std::chrono::high_resolution_clock::now();

            auto currentTime = std::chrono::high_resolution_clock::now();
            float time = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - startTime).count();

            if (time < 1)
            {
                counter++;
            }
            else
            {
                int a = 34; //breakpoint put here to check the counter fps.
            }

任何没有每帧纹理的方式(命令缓冲区仍在每帧更新。) fps 约为 3500 fps。如果我尝试更新每帧的纹理,fps 会下降到 350 fps。

这只是带有空白纹理的测试代码,但这是我第一次使用上传纹理并更新它的过程。

void createTextureImage()
{
    int Width = 1024;
    int Height = 1024;

    VkDeviceSize imageSize = Width * Height * sizeof(Pixel);
    PixelImage.resize(Width * Height, Pixel(0xFF, 0x00, 0x00));

    VkBuffer stagingBuffer;
    VkDeviceMemory stagingBufferMemory;
    createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);

    void* data;
    vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
    memcpy(data, PixelImage.data(), static_cast<size_t>(imageSize));
    vkUnmapMemory(device, stagingBufferMemory);

    createImage(Width, Height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);

    transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
    copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(Width), static_cast<uint32_t>(Height));
    transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);

    vkDestroyBuffer(device, stagingBuffer, nullptr);
    vkFreeMemory(device, stagingBufferMemory, nullptr);
}

void UpdateTexture()
{
    VkDeviceSize imageSize = 1024 * 1024 * sizeof(Pixel);
    memset(&PixelImage[0], 0xFF, imageSize);

    VkBuffer stagingBuffer;
    VkDeviceMemory stagingBufferMemory;
    createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);

    void* data;
    vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
    memcpy(data, PixelImage.data(), static_cast<size_t>(imageSize));
    vkUnmapMemory(device, stagingBufferMemory);

    transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
    copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(1024), static_cast<uint32_t>(1024));
    transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);

    vkDestroyBuffer(device, stagingBuffer, nullptr);
    vkFreeMemory(device, stagingBufferMemory, nullptr);

    vkDestroyImageView(device, textureImageView, nullptr);
    CreateImageView();
}

我已经尝试了一下,似乎所有写入缓冲区并多次转换布局的操作都真正减慢了速度。

对于更多上下文,这是更新纹理过程的其余部分。

        UpdateTexture();
    for (size_t i = 0; i < vulkanFrame.size(); i++)
    {
        VkDescriptorBufferInfo bufferInfo = {};
        bufferInfo.buffer = uniformBuffers[i];
        bufferInfo.offset = 0;
        bufferInfo.range = sizeof(UniformBufferObject);

        VkDescriptorImageInfo imageInfo = {};
        imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
        imageInfo.imageView = textureImageView;
        imageInfo.sampler = textureSampler;

        std::array<VkWriteDescriptorSet, 2> descriptorWrites = {};

        descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
        descriptorWrites[0].dstSet = descriptorSets[i];
        descriptorWrites[0].dstBinding = 0;
        descriptorWrites[0].dstArrayElement = 0;
        descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        descriptorWrites[0].descriptorCount = 1;
        descriptorWrites[0].pBufferInfo = &bufferInfo;

        descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
        descriptorWrites[1].dstSet = descriptorSets[i];
        descriptorWrites[1].dstBinding = 1;
        descriptorWrites[1].dstArrayElement = 0;
        descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
        descriptorWrites[1].descriptorCount = 1;
        descriptorWrites[1].pImageInfo = &imageInfo;

        vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
    }

另外,对于 2D 游戏的空白更新屏幕来说,良好的基本 fps 是多少。我还使用 vulkan 进行 3d 制作,但我也想用它来做复古 2d 的东西。


每帧从 CPU 向 GPU 发送 4MB 的数据。在 350 fps 下,数据传输速度约为 1.4GB/秒。考虑到所有因素,这相当不错。

暂存缓冲区并不是真正的问题。一旦您决定将数据从 CPU 发送到 GPU,那么您就会丧失一定的性能。

如果您确实坚持要避免分段,则可以检查您的实现是否允许着色器对线性纹理进行采样。在这种情况下,您可以将数据直接写入纹理的内存中。但是,您需要对纹理进行双缓冲,这样您就不会写入 GPU 当前正在使用的纹理。但无论如何,即使有分期,你也需要这样做。

你可以做的更有效的事情就是停止做毫无意义的事情。你需要停止:

  1. 为暂存缓冲区分配和释放空间每次上传。在应用程序启动时创建足够的暂存内存和缓冲区空间并保留它。
  2. 取消内存映射;在 Vulkan 中,这几乎没有任何意义,除非你要删除所述内存。这又不是你应该做的事情。
  3. 构建完成后立即提交传输操作。我没有看到你的 CB/队列工作,所以我想transitionImageLayout and copyBufferToImage不仅构建 CB 信息,还提交信息。这就是杀人表演(尤其 if transitionImageLayout还提交作业)。您希望每帧的提交次数尽可能少,理想情况下您实际使用的每个队列只有一个提交。

所有这些都会损害代码的 CPU 性能。它们不会改变 GPU 传输的实际时间,但会使导致传输的代码运行速度变慢。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有一种方法可以在不使用暂存缓冲区的情况下更新纹理? 的相关文章

  • 静态只读字符串数组

    我在我的 Web 应用程序中使用静态只读字符串数组 基本上数组有错误代码 我将所有类似的错误代码保存在一个数组中并检查该数组 而不是检查不同常量字符串中的每个错误代码 like public static readonly string m
  • CLR 2.0 与 4.0 性能比较?

    如果在 CLR 4 0 下运行 为 CLR 2 0 编译的 NET 程序会运行得更快吗 应用程序配置
  • 适合初学者的良好调试器教程[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有谁知道一个好的初学者教程 在 C 中使用调试器 我感觉自己好像错过了很多 我知道怎么做 单步执行代码并查看局部变量 虽然这常常给我带来问
  • IdentityServer 4 对它的工作原理感到困惑

    我阅读和观看了很多有关 Identity Server 4 的内容 但我仍然对它有点困惑 因为似乎有很多移动部件 我现在明白这是一个单独的项目 它处理用户身份验证 我仍然不明白的是用户如何注册它 谁存储用户名 密码 我打算进行此设置 Rea
  • 从同一个类中的另一个构造函数调用构造函数

    我有一个带有两个构造函数的类 C 这是代码片段 public class FooBar public FooBar string s constructor 1 some functionality public FooBar int i
  • 从客户端访问 DomainService 中的自定义对象

    我正在使用域服务从 Silverlight 客户端的数据库中获取数据 在DomainService1 cs中 我添加了以下内容 EnableClientAccess public class Product public int produ
  • unordered_map 中字符串的 C++ 哈希函数

    看起来 C 标准库中没有字符串的哈希函数 这是真的 在任何 c 编译器上使用字符串作为 unordered map 中的键的工作示例是什么 C STL提供模板专业化 http en cppreference com w cpp string
  • 使用 GCP 的数据存储区时如何区分代码是在模拟器中运行还是在 GKE 中运行

    按照中给出的说明进行操作后 我不确定是否遗漏了任何内容https cloud google com datastore docs tools datastore emulator https cloud google com datasto
  • 对 std::vector 进行排序但忽略某个数字

    我有一个std vector
  • 在视口中查找 WPF 控件

    Updated 这可能是一个简单或复杂的问题 但在 wpf 中 我有一个列表框 我用一个填充数据模板从列表中 有没有办法找出特定的数据模板项位于视口中 即我已滚动到其位置并且可以查看 目前我连接到了 listbox ScrollChange
  • 高效列出目录中的所有子目录

    请参阅迄今为止所采取的建议的编辑 我正在尝试使用 WinAPI 和 C 列出给定目录中的所有目录 文件夹 现在我的算法又慢又低效 使用 FindFirstFileEx 打开我正在搜索的文件夹 然后我查看目录中的每个文件 使用 FindNex
  • 等待 IAsyncResult 函数直至完成

    我需要创建等待 IAsyncResult 方法完成的机制 我怎样才能做到这一点 IAsyncResult result contactGroupServices BeginDeleteContact contactToRemove Uri
  • 检测到严重错误 c0000374 - C++ dll 将已分配内存的指针返回到 C#

    我有一个 c dll 它为我的主 c 应用程序提供一些功能 在这里 我尝试读取一个文件 将其加载到内存 然后返回一些信息 例如加载数据的指针和内存块的计数到 c Dll 成功将文件读取到内存 但在返回主应用程序时 程序由于堆损坏而崩溃 检测
  • 打印大型 WPF 用户控件

    我有一个巨大的数据 我想使用 WPF 打印 我发现WPF提供了一个PrintDialog PrintVisual用于打印派生的任何 WPF 控件的方法Visual class PrintVisual只会打印一页 因此我需要缩放控件以适合页面
  • Unity:通过拦截将两个接口注册为一个单例

    我有一个实现两个接口的类 我想对该类的方法应用拦截 我正在遵循中的建议Unity 将两个接口注册为一个单例 https stackoverflow com questions 1394650 unity register two inter
  • OpenGL:仅获取模板缓冲区而没有深度缓冲区?

    我想获取一个模板缓冲区 但如果可能的话 不要承受附加深度缓冲区的开销 因为我不会使用它 我发现的大多数资源表明 虽然模板缓冲区是可选的 例如 排除它以利于获得更高的深度缓冲区精度 但我还没有看到任何请求并成功获取仅 8 位模板缓冲区的代码
  • 可访问性不一致:参数类型的可访问性低于方法

    我试图在两个表单之间传递一个对象 基本上是对当前登录用户的引用 目前 我在登录表单中有一些类似的内容 private ACTInterface oActInterface public void button1 Click object s
  • 堆栈是向上增长还是向下增长?

    我在 C 中有这段代码 int q 10 int s 5 int a 3 printf Address of a d n int a printf Address of a 1 d n int a 1 printf Address of a
  • 使用 C 在 OS X 中获取其他进程的 argv

    我想获得其他进程的argv 例如ps 我使用的是在 Intel 或 PowerPC 上运行的 Mac OS X 10 4 11 首先 我阅读了 ps 和 man kvm 的代码 然后编写了一些 C 代码 include
  • OpenCV SIFT 描述符关键点半径

    我正在深入研究OpenCV的SIFT描述符提取的实现 https github com Itseez opencv blob master modules nonfree src sift cpp 我发现了一些令人费解的代码来获取兴趣点邻域

随机推荐

  • 捕获 bash 命令的输出,解析它并存储到不同的 bash 变量中

    解释 我有一个小bash只需运行的脚本anyLinux 命令 例如说ifconfig 典型输出为ifconfig是这样的 eth0 Link encap Ethernet HWaddr 30 F7 0D 6D 34 CA inet addr
  • 在 EmberJS 中进行 AJAX GET 和 POST 调用的正确方法

    我已经开始研究 EmberJS 并且非常喜欢它 它确实有一个学习曲线 但我相信它具有从根本上非常有意义的原则 我的问题是如何在 Ember JS 中进行 GET 和 POST 调用 我知道有模型 商店 但模型 在我看来 仅适用于特定实体的属
  • 如何在 IL 中实现 C# foreach 优化

    In this answer https stackoverflow com a 3168435 801189和这个GitHub问题 https github com dotnet roslyn issues 426 顶部项目 有一个描述f
  • gradle - 无法从 Maven 存储库中找到依赖项

    我在使用以下 build gradle 时遇到构建错误 apply plugin java apply plugin idea sourceCompatibility 1 7 version 1 0 repositories mavenLo
  • Magento - 数据未插入数据库,但id自动递增

    我正在为 Magento 开发一个新的支付模块 并且遇到了一个我无法解释的问题 验证信用卡后运行以下代码 table prefix Mage getConfig gt getTablePrefix tableName table prefi
  • cURL 错误 1:不支持的协议:https

    All 我尝试通过 PHP 的 cURL 包装器方法 HTTPS POST SOAP 请求 但不断收到以下 cURL 错误 错误 1 不支持的协议 https 有什么想法为什么会发生这种情况吗 目标 URL 很好 我可以通过命令行访问它 c
  • 如何从另一个 ViewController 修改 UITableView 的单元格

    在 VC 1 中 我有一个 UITableView 当我点击一个单元格时 我会进入 VC 2 其中显示有关该单元格的信息 我希望能够在 VC 2 中按下一个按钮 从而更改它在 VC 1 中对应的单元格的标题 但我对如何执行此操作感到困惑 我
  • 将请求参数作为 UTF-8 编码字符串传递[重复]

    这个问题在这里已经有答案了 我正在创建一个简单的登录页面 我想将登录名和密码参数作为 UTF 8 编码字符串传递 正如您在下面的代码中看到的 第一行是我将编码设置为 UTF 8 的地方 但这似乎毫无意义 因为它不起作用 当我使用带有重音符号
  • 交换活动后如何保持倒计时计时器计数?

    当我在活动之间交换时 我需要一个 countDownTimer 继续运行 我有多个活动 我将 countDownTimer 放在主活动中 但是当我交换到另一个活动并返回到主活动时 它又会从头开始重新计数 我相信是因为 countDownTi
  • 使用 pysftp 或 Paramiko,如何获得包含属性的完整目录列表?

    正如标题所示 我正在尝试获取目录中所有文件和目录的列表 包括它们的属性 我正在寻找至少名称 大小 上次修改时间 以及它是文件还是文件夹 我在 Windows 上使用 Python 3 我试过了listdir 我得到了一个没有属性的文件列表
  • java.lang.Long 和 scala.Long

    我不知道我的代码中发生了什么 日志在这里 error blahblah SampleApp scala 22 53 overloaded method value reduce with alternatives error func or
  • Oracle“总”计划成本确实低于其某些要素

    我不明白为什么有时一个计划的总成本可能很小 但查看计划内部我们会发现巨大的成本 确实查询速度很慢 有人能给我解释一下吗 这是一个例子 显然 成本较高的部分来自主选择中的一个字段 该字段在子视图上执行 listagg 并且该子视图的连接条件包
  • 在运行时创建XmlRpcUrl接口

    目前 我正在使用 xml rpc net 接口通过以下语句静态创建 XML RPC XmlRpcUrl http dillieodigital wordpress com xmlrpc php public interface ICSBlo
  • DLLImport 在哪里查找非托管 DLL?

    一个简单的问题 在 Net 中声明 DLLImport 属性时 运行时在哪里寻找解决该 DLL 依赖关系的方法 我是否必须转储 DLL 和所有itsbin 文件夹中的依赖项 我认为它的工作方式与 LoadLibrary 类似 Maybe 使
  • 如何比较 PHAsset 和 UIImage

    我已经转换了一些PHAsset to UIImage PHImageManager manager PHImageManager defaultManager manager requestImageForAsset asset targe
  • 隐藏页面中的div并使其仅在打印引导程序3 MVC 5上可见

    有一个网页向用户显示信息 如果用户决定打印它 我想包含屏幕上不需要的附加信息 但在打印时会很有帮助 为了实现这种行为 我试图做一个div仅在打印时可见 但它并没有起作用 div class visible print hidden lg h
  • 如何构建卡方分布表

    我想在 python 中生成一个卡方分布表作为概率水平和自由度的函数 给定已知的卡值和自由度 如何计算概率是这样的 In 44 scipy stats chisqprob 5 991 2 Out 44 0 05001161502657908
  • 在 git rebase -i 中删除提交不会减少 .git 文件夹的大小

    我有一个 git 存储库 其中 git文件夹是7MB 然后我添加并提交了一个 exe 文件 该文件是16MB其次是 git gc aggressive git prune 经过上述我的 git文件夹现在是23MB 接下来我做了一个git r
  • sklearn Kfold 访问单折叠而不是 for 循环

    使用 cross validation KFold n n folds folds 之后 我想访问索引以进行单折叠的训练和测试 而不是遍历所有折叠 那么我们来看一下示例代码 from sklearn import cross validat
  • 有没有一种方法可以在不使用暂存缓冲区的情况下更新纹理?

    我正在与https vulkan tutorial com https vulkan tutorial com 深度缓冲代码作为基础 进行了一些更改以每帧更新命令缓冲区 我正在使用一种粗略的方法来检查 fps 不确定它到底有多准确 但我正在