我一直试图弄清楚如何从C++ 17访问映射缓冲区而不调用未定义的行为.对于这个例子,我将使用Vulkan的返回缓冲区vkMapMemory.
因此,根据N4659(最终的C++ 17工作草案),[intro.object]部分(重点补充):
C++程序中的构造创建,销毁,引用,访问和操作对象.一个目的是通过一种创建定义(6.1),通过一个 新的表达式 (8.3.4)中,当隐式地改变所述一个联合的活性部件(12.3),或当一个临时对象被创建(7.4,15.2).
显然,这些是创建C++对象的唯一有效方法.因此,假设我们得到一个void*指向主机可见(和相干)设备内存的映射区域的指针(当然,假设所有必需的参数都有有效值并且调用成功,并且返回的内存块足够大)并正确对齐):
void* ptr{};
vkMapMemory(device, memory, offset, size, flags, &ptr);
assert(ptr != nullptr);
Run Code Online (Sandbox Code Playgroud)
现在,我希望将此内存作为float数组访问.显而易见的事情static_cast是指针并按照我的快乐方式继续如下:
volatile float* float_array = static_cast<volatile float*>(ptr);
Run Code Online (Sandbox Code Playgroud)
(volatile包含它因为它被映射为相干存储器,因此可以在任何时候由GPU写入).然而,在该存储器位置中技术上float不存在阵列,至少不是在引用的摘录的意义上,因此通过这样的指针访问存储器将是未定义的行为.因此,根据我的理解,我有两种选择:
memcpy数据它应该总是能够使用本地缓存,将它转换为std::byte*和memcpy的表示到映射区域.GPU将按照着色器中的指示解释它(在这种情况下,作为32位数组float),从而解决了问题.但是,这需要额外的内存和额外的副本,所以我宁愿避免这种情况.
new阵列看来,[new.delete.placement]部分没有对如何获得放置地址施加任何限制(无论实现的指针安全性如何,它都不必是安全派生的指针).因此,可以通过放置创建有效的浮点数组new,如下所示:
volatile …Run Code Online (Sandbox Code Playgroud) 我正在考虑在 GPU 上处理数据的可能性,这对于 GPU 内存来说太大了,我有几个问题。
如果我理解正确的话,使用映射内存,数据驻留在主内存中,并且仅在访问时才传输到 GPU,因此分配超出 GPU 内存的数据应该不成问题。
UVA与映射内存类似,但数据可以存储在CPU和GPU内存中。但是 GPU 是否有可能在充满自己的数据的情况下访问主内存(与映射内存一样)?这种情况下会不会发生内存溢出呢?我读到,使用映射内存,数据直接进入本地内存,而无需先传输到全局内存,在这种情况下,不应该有任何溢出。这是真的吗?如果是的话,UVA 也是如此吗?
在 CUDA 6.0 中,UM 不允许超额订阅 GPU 内存(并且通常不允许分配比 GPU 多的内存,即使在主内存中也是如此),但在 CUDA 8.0 中这成为可能(https://devblogs .nvidia.com/parallelforall/beyond-gpu-memory-limits-unified-memory-pascal/)。我做对了吗?