【发布时间】:2022-01-16 03:52:03
【问题描述】:
我正在尝试将向量的向量传递给 SSB0,但是在使用 glBufferData 传递它时出现段错误。 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[];
};
每次在glBufferData 内部registerSSBO 出现段错误
glBufferData(GL_SHADER_STORAGE_BUFFER, getMem(), mBlocks.data(), GL_DYNAMIC_DRAW);
getMem() 在这种情况下返回35773920 字节的大小,这是我期望的值。我计算不正确吗? mBlocks.size()*sizeof(mBlocks) 或 mBlocks.size()*sizeof(Block) 等较小的值不会导致应用程序出现段错误(但应用程序的行为不符合预期)
使用 valgrind 运行可防止发生段错误,但在 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"
等
这是多余的样板还是我遗漏了什么?
编辑:
为了显示向量的大小合适,我将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;
}
【问题讨论】:
-
sizeof(mBlocks.data())-- 你知道这个值代表什么吗?它不会告诉您mBlocks.data()拥有的字节数。事实上,它不会告诉你任何对你的程序运行重要的事情。 -
是的,我知道,我不会将它用于任何有用的东西,只是在我出于好奇进行探索时打印在那里。已删除以免进一步分散注意力
-
您可能想要并且更相关的是输出
mBlocks.size()。打印sizeof向量不会给您元素的数量。第二件事是向量向量的布局是否与您正在与之通信的 API 兼容。如果不是,那么您不能使用向量的向量。 -
您的代码没有显示您如何调整向量的大小。很可能您从不这样做,因此您访问的是空向量的元素。
-
感谢您的回复,但我只是出于好奇才将其打印出来,我确实知道其中的区别,正如您在我的内存计算中看到的那样。我已经能够将矢量发送到 OpenGL。我不确定我是否能够发送向量向量,因此这里的问题。
标签: c++ opengl memory segmentation-fault