我有一些顶点数据.位置,法线,纹理坐标.我可能从.obj文件或其他格式加载它.也许我正在画一个立方体.但是每个顶点数据都有自己的索引.我可以使用OpenGL/Direct3D渲染这个网格数据吗?
该vec3类型是一个非常好的类型.它只需要3个浮点数,我的数据只需要3个浮点数.我想在UBO和/或SSBO的结构中使用一个:
layout(std140) uniform UBO
{
vec4 data1;
vec3 data2;
float data3;
};
layout(std430) buffer SSBO
{
vec4 data1;
vec3 data2;
float data3;
};
Run Code Online (Sandbox Code Playgroud)
然后,在我的C或C++代码中,我可以这样做来创建匹配的数据结构:
struct UBO
{
vector4 data1;
vector3 data2;
float data3;
};
struct SSBO
{
vector4 data1;
vector3 data2;
float data3;
};
Run Code Online (Sandbox Code Playgroud)
这是一个好主意吗?
我试图了解OpenCL生态系统以及vulkan如何发挥作用.
鉴于:
OpenCL如何与vulkan相关?我知道OpenCL是更高级别并抽象设备,但是它(或可能)内部使用Vulkan吗?(而不是依赖供应商特定的驱动程序)
Vulkan被宣传为计算和图形API,但是我发现计算部分的资源非常少 - 为什么呢?
Vulkan比OpenGL具有性能优势.Vulkan与OpenCl的情况是否相同?(OpenCL因为比CUDA慢而臭名昭着)
SYCL内部使用OpenCL还是使用vulkan?或者它既不使用,而是依赖于低级别,供应商特定的apis来实现?
在vk*CreateInfo新的Vulkan API中的所有create info structs()中,总有一个.sType成员.如果价值只能是一件事,为什么会这样?此外,Vulkan规范非常明确,您只能将vk*CreateInfo结构用作其相应vkCreate*函数的参数.这似乎有点多余.我可以看到,如果驱动程序将此结构直接传递给GPU,您可能需要它(我确实注意到它始终是第一个成员).但对于应用程序而言,这似乎是一个非常糟糕的想法,因为如果驱动程序这样做,应用程序将更不容易出错,并且在结构中添加int似乎不是一个计算效率极低的操作.我只是不明白为什么它存在.
TL; DR
为什么vk*CreateInfo结构有.sType成员?
有几种方法可以处理Vulkan中的同步.这就是我理解的方式:
在我的情况下,我有两个命令缓冲区.我希望第二个命令缓冲区在第一个命令缓冲区之后执行.
submitInfo.pCommandBuffers = &firstCommandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
// wait for first command buffer to finish
submitInfo.pCommandBuffers = &secondCommandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);
Run Code Online (Sandbox Code Playgroud)
什么样的同步最适合这个?如果我使用的vkQueueWaitIdle(queue)),是与使用栅栏相同的东西,或者我应该使用事件或信号量?
如果我同时向队列发送多个命令缓冲区:
std::vector<VkCommandBuffer> submitCmdBuffers = {
firstCommandBuffer,
secondCommandBuffer
};
submitInfo.commandBufferCount = submitCmdBuffers.size();
submitInfo.pCommandBuffers = submitCmdBuffers.data();
Run Code Online (Sandbox Code Playgroud)
还有一种方法可以在第一个和第二个之间同步吗?
我正在使用交换链的3个图像和VkCommandBuffer每个交换链图像的一个(CB).GPU同步由两个信号量完成,一个用于presentation_finished,一个用于rendering_finished.目前的模式是VK_PRESENT_MODE_MAILBOX_KHR(快速概述).
现在,当我在不等待任何CB围栏的情况下运行我的示例时,验证层会在第二次使用任何交换链图像时立即报告此错误:
vkBeginCommandBuffer()在活动CB完成之前调用它.您必须在此电话前检查CB围栏.
乍一看,这对我来说似乎是合理的,因为处理来自CB的命令可能还没有完成.但我想的越多,我就会得出结论,这根本不应该发生.
我目前的理解是,当vkAcquireImageKHR返回特定的图像索引时,它意味着返回的图像必须通过渲染完成.
那是因为我在渲染结束时将rendering_finished信号量传递vkQueueSubmit给要发信号,并vkQueuePresentKHR在呈现图像之前等待它发出信号.
规格VkQueuePresentInfoKHR说:
pWaitSemaphores,如果不是VK_NULL_HANDLE,则是VkSemaphore带有waitSemaphoreCount条目的对象数组,并指定在发出当前请求之前要等待的信号量
含义:我永远不会出现任何没有渲染渲染的图像,因此一旦图像出现,相关的CB就不能再使用了.
第二个信号量presentation_finished由信号通知vkAqcuireImageKHR并传递给它vkQueueSubmit(开始渲染).这意味着任何图像的渲染都不会早于演示引擎允许的开始.
总结:vkQueuePresentKHR在完成图像渲染之前不会发出当前请求,并且vkAcquireImageKHR阻止直到图像可用并且永远不会返回当前获取的图像.
我错过了什么使围栏成为必要?
我已经包含了一个最小的代码示例,其中仅包含概念上重要的部分来说明问题.
VkImage[] swapchain_images;
VkCommandBuffer[] command_buffers;
VkSemaphore rendering_finished;
VkSemaphore presentation_finished;
void RenderLoop()
{
/* Acquire an image from the swapchain. Block until one is available.
Signal presentation_finished when we are allowed to render …Run Code Online (Sandbox Code Playgroud) 我查看了一堆关于推送常量的教程,暗示可能的好处,但我从未见过,即使在Vulkan文档中,实际上是什么"推动常数"......我不明白他们应该是什么,以及推动常数的目的是什么.我能找到的最接近的是这篇文章,遗憾的是它不会问它们是什么,但是它们和另一个概念之间有什么不同,并没有帮助我.
什么是推动常数,它为什么存在以及它用于什么?它的名字来自哪里?
在Vulkan中使用多GPU会不会像制作许多命令队列那样在它们之间划分命令缓冲区?
有两个问题:
OpenGL 和 Vulkan 都允许分别使用glMapBuffer和获取指向部分 GPU 内存的指针vkMapMemory。他们都给void*映射的内存一个。要将其内容解释为某些数据,必须将其强制转换为适当的类型。最简单的示例可能是转换为 afloat*以将内存解释为浮点数或向量或类似数组。
似乎任何类型的内存映射在 C++ 中都是未定义的行为,因为它没有内存映射的概念。但是,这并不是真正的问题,因为该主题超出了 C++ 标准的范围。但是,仍然存在一个问题volatile。
在链接的问题中,指针被额外标记为volatile因为它指向的内存内容可以以编译器在编译期间无法预料的方式进行修改。这似乎是合理的,尽管我很少看到人们volatile在这种情况下使用(更广泛地说,这个关键字现在似乎很少使用)。
同时在这个问题中,答案似乎是使用volatile是不必要的。这是因为他们所说的内存是映射使用的mmap,然后msync可以被视为修改内存,这类似于在 Vulkan 或 OpenGL 中显式刷新它。恐怕这不适用于 OpenGL 和 Vulkan。
如果内存被映射为未映射GL_MAP_FLUSH_EXPLICIT_BIT或根本VK_MEMORY_PROPERTY_HOST_COHERENT_BIT不需要刷新,则内存内容会自动更新。即使通过使用手动刷新内存,vkFlushMappedMemoryRanges或者glFlushMappedBufferRange这些函数实际上都没有将映射指针作为参数,因此编译器也不可能知道它们修改了映射内存的内容。
因此,是否有必要将指向映射 GPU 内存的指针标记为volatile?我知道从技术上讲这都是未定义的行为,但我问的是在实际硬件中实际需要什么。
顺便说一下,无论是Vulkan 规范还是OpenGL 规范都没有提到volatile限定符。
编辑:将内存标记为volatile会导致性能开销吗?