【问题标题】:Vulkan Uniform data(memory) copy from CPU to GPU error [duplicate]Vulkan Uniform 数据(内存)从 CPU 复制到 GPU 错误 [重复]
【发布时间】:2022-01-26 06:37:14
【问题描述】:

我在将统一缓冲区数据从 CPU 传输到 GPU 端时遇到问题。这似乎与 CPU/GPU 之间的内存对齐有关。我定义了一个统一的缓冲区对象如下:

const int MAX_LIGHTS_NUM = 32;
struct Lights {
    glm::vec3 Position;
    glm::vec3 Color;
    float Linear;
    float Quadratic;
    float intensity;
};
struct UniformBufferObject {
    glm::mat4 mvp;
    glm::mat4 model;
    glm::vec3 camPos;
    int RealLightsNum;
    Lights lights[MAX_LIGHTS_NUM];
};

在着色器代码中,它定义为:

layout(binding = 0) uniform UniformBufferObject {
    mat4 mvp;
    mat4 mMatrix;
    vec3 CameraPosition;
    int RealLightsNum;
    Light lights[MAX_LIGHTS_NUM];
} ubo;

我将 MAX_LIGHTS_NUM 定义为 32。当我从 CPU 端复制内存时,我打印所有 ubo 数据并确认 CPU 端的所有数据都是正确的:

void printUBO(UniformBufferObject &ubo) {
    LOGD("%s:%d Model matrix:%s", __FUNCTION__, __LINE__, glm::to_string(ubo.model).c_str());
    LOGD("%s:%d MVP matrix:%s", __FUNCTION__, __LINE__, glm::to_string(ubo.mvp).c_str());
    LOGD("%s:%d camPos:%s", __FUNCTION__, __LINE__, glm::to_string(ubo.camPos).c_str());
    LOGD("%s:%d ubo size:%d, RealLightsNum:%d", __FUNCTION__, __LINE__, sizeof(ubo), ubo.RealLightsNum);
    for (int i = 0; i < ubo.RealLightsNum; i++) {
        LOGD("%s:%d Light[%d].pos: %s",
             __FUNCTION__, __LINE__, i, glm::to_string(ubo.lights[i].Position).c_str());
        LOGD("%s:%d Light[%d].color: %s",
             __FUNCTION__, __LINE__, i, glm::to_string(ubo.lights[i].Color).c_str());
        LOGD("%s:%d Light[%d].(intensity/linear/quadratic: %f, %f, %f",
             __FUNCTION__, __LINE__, i, ubo.lights[i].intensity, ubo.lights[i].Linear, ubo.lights[i].Quadratic);
    }
}

void VulkanHal::drawPrimitive(int nodeId, unsigned int index, size_t offset, int mode, int count,
                              int type) {
    if (initialized == false) return;
//    LOGD("%s:%d nodeId:%d, index:%u offset:%u, mode:%d, count:%d, type:%d",
//         __FUNCTION__, __LINE__, nodeId, index, offset, mode, count, type);
//    LOGD("%s:%d -", __FUNCTION__, __LINE__);
//    LOGD("%s:%d ubo size:%d, RealLightsNum:%d", __FUNCTION__, __LINE__, sizeof(ubo), ubo.RealLightsNum);
    printUBO(ubo);
    int primIndex = getPrimitiveIndex(nodeId, index);
    void* data;
    vkMapMemory(device, uniformBuffersMemory[imageIndex][primIndex], 0, sizeof(ubo), 0, &data);
    memcpy(data, &ubo, sizeof(ubo));
    vkUnmapMemory(device, uniformBuffersMemory[imageIndex][primIndex]);
}

我捕获renderdoc ubo数据,发现直到RealLightsNum的数据都是正确的,但是Light数据只有第一个是部分正确的,这意味着位置正确,但是颜色第三通道不正确。

我怀疑这是内存对齐问题,但无法正确解决。有人可以帮忙吗,在此先感谢。

日志:

renderdoc 捕获:

【问题讨论】:

    标签: gpu cpu vulkan uniform


    【解决方案1】:

    我在链接Vulkan Memory Alignment for Uniform Buffers 上得到了答案。它说对于 CPU 端的每个元素,我们应该设置对齐方式:

    • int/float 4 对齐
    • vec2 8 对齐
    • 一个 vec3, vec4, mat4 一个 16 的对齐方式

    我设置后就可以了:

    const int MAX_LIGHTS_NUM = 32;
    struct Lights {
        alignas(16) glm::vec3 Position;
        alignas(16) glm::vec3 Color;
        alignas(4) float Linear;
        alignas(4) float Quadratic;
        alignas(4) float intensity;
    };
    
    struct UniformBufferObject {
        alignas(16) glm::mat4 mvp;
        alignas(16) glm::mat4 model;
        alignas(16) glm::vec3 camPos;
        alignas(4) int RealLightsNum;
        Lights lights[MAX_LIGHTS_NUM];
    };
    

    【讨论】:

      猜你喜欢
      • 2012-10-31
      • 1970-01-01
      • 1970-01-01
      • 2012-07-29
      • 1970-01-01
      • 2013-06-06
      • 1970-01-01
      • 2015-10-20
      • 2011-09-14
      相关资源
      最近更新 更多