我正试图将一个向量向量传递给SSB0,但在使用glBufferData
传递时,我遇到了segfault。C++中的结构是:
const uint16_t MAX_NODE_POOLS = 1927;
union Node
{
uint32_t childDescriptor;
uint32_t material;
};
struct NodePool
{
NodePool() : mNodes({0}) {}
std::array<Node, 8> mNodes;
};
struct Block
{
Block(): ID(0) {}
uint16_t ID;
std::vector<NodePool> mNodePools;
std::vector<uint16_t> mNodeMasks;
};
class Octree
{
public:
...
void registerSSBO(GLuint &octreeSSBO) const;
void generate();
[[nodiscard]] inline uint64_t getMem() const { return mBlocks.size() *
(
sizeof(uint16_t) + // ID
(sizeof(NodePool)*MAX_NODE_POOLS) + // NodePools
(sizeof(uint16_t)*MAX_NODE_POOLS) // NodeMasks
); }
private:
...
std::vector<Block> mBlocks;
};
...
void Octree::Octree::registerSSBO(GLuint &octreeSSBO) const
{
glGenBuffers(1, &octreeSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, octreeSSBO);
std::cout << getMem() << std::endl;
glBufferData(GL_SHADER_STORAGE_BUFFER, getMem(), mBlocks.data(), GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, octreeSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}
我用数据填充块,然后像一样进入SSBO
...
octree.generate();
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
octree.registerSSBO(octreeSSBO);
glBindVertexArray(0);
...
在我的着色器中,我有类似的SSBO结构
#version 430 core
// To use 16 bit integers
#extension GL_NV_gpu_shader5 : enable
#define MAX_NODE_POOLS 1927
struct Node
{
// Either a child descriptor or material depending on mNodeMasks
int data;
};
struct NodePool
{
Node mNodes[8];
};
struct Block
{
uint16_t ID;
NodePool mNodePools[MAX_NODE_POOLS];
uint16_t mNodeMasks[MAX_NODE_POOLS];
};
layout (std430, binding=2) buffer octreeData
{
Block blocks[];
};
每次在registerSSBO
内的glBufferData
上发生故障
glBufferData(GL_SHADER_STORAGE_BUFFER, getMem(), mBlocks.data(), GL_DYNAMIC_DRAW);
在这种情况下,getMem()
返回35773920
字节的大小,这是我期望的值。我算错了吗?较小的值(如mBlocks.size()*sizeof(mBlocks)
或mBlocks.size()*sizeof(Block)
(不会导致应用程序分段故障(但应用程序的行为不符合要求(
使用valgrind运行可以防止segfault的发生,但是在glBufferData
调用上会给我20个警告Invalid read of size 16
,但我很难弄清楚这到底意味着什么?
在每一个单独的警告中,它都会给我这样的问题:
Invalid read of size 16
...
Address 0x4cd830b0 is 16 bytes before a block of size 61,664 alloc'd
Invalid read of size 16
...
Address 0x4cd83080 is 0 bytes after a block of size 57,344 alloc'd
Invalid read of size 16
...
Address 0x4cd830a0 is 32 bytes before a block of size 61,664 in arena "client"
etc
这是多余的锅炉板还是我遗漏了什么?
编辑:
为了表明矢量大小合适,我将getMem()
更改为以下函数,结果与相同
inline uint64_t getMem() const
{
uint64_t sum = 0;
for(const auto& b: mBlocks)
{
for(const auto& np: b.mNodePools)
sum += sizeof(np);
for(const auto& nm: b.mNodeMasks)
sum += sizeof(nm);
sum += sizeof(b.ID);
}
return sum;
}
uint16_t ID; std::vector<NodePool> mNodePools; std::vector<uint16_t> mNodeMasks; ... glBufferData(GL_SHADER_STORAGE_BUFFER, getMem(), mBlocks.data(), GL_DYNAMIC_DRAW);
您不能这样做。您无法将大多数C++标准库类型按字节复制到OpenGL中(或其他任何方面(。一般来说,如果一个类型不是可复制的(并且vector
肯定是而不是(,那么它绝对不能像这样被抛出到OpenGL(注意:这并不意味着你可以向OpenGL抛出任何可复制的类型。简单的可复制性是必要的,但还不够(。
您对std::array
的使用是有效的(也许吧。C++标准不能保证您认为它对array
的布局做了什么(,因为array<T>
是在没有显式构造函数的情况下定义的。因此,它将在T
的可复制性的范围内具有可复制性。
如果要将C++对象复制到GLSL,则C++类型和布局必须与GLSL定义的相匹配。CCD_ 16与任何GLSL阵列的布局都不匹配。如果你的GLSL定义了一个X项的数组,那么唯一肯定会匹配的C++类型就是一个实际的X项数组(同样,是必要的,但不是足够的(。
不多不少。