Как решить проблему повреждения сетки с помощью промежуточного буфера на Vulkan Api - PullRequest
1 голос
/ 03 мая 2019

В моем коде обнаружена ошибка, приводящая к повреждению данных сетки в определенной ситуации при использовании промежуточного буфера.У меня есть:

  1. временные данные сетки

  2. промежуточный буфер с определенным размером, который используется одновременно буфером команд и memcpy, но не одним и тем же сегментом ввремя.

  3. Распределитель буфера, который дает часть подходящего буфера индекса вершины, где данные сетки переносятся из промежуточной обработки с помощью vkCmdCopyBuffer.Буфер содержит множество сегментов, заданных для разных сеток.

Проблема в том, что когда я использую промежуточный буфер одновременно с помощью буфера команд и memcpy, данные сетки записывают неправильно (становятся перезаписанными / поврежденными) идаже плохо может вызвать VK_ERROR_DEVICE_LOST.

https://imgur.com/8p53SUW «правильная сетка»

https://imgur.com/plJ8V0v «битая сетка»

    [[nodiscard]] static Result writeMeshBuffer(TransferData &data, GpuMesh &buffer)
    {
        Result result; using namespace vkw;

        auto &mesh = buffer.source;

        size_t vSize = mesh.vertices_count * mesh.vertex_size;
        size_t iSize = mesh.indices_count  * mesh.index_size;
        size_t mesh_size = vSize + iSize;

        auto &staging_offset = data.stagingData.buffer_offset_unused;

        // write data to staging buffer
        {
            // guaranteed that mesh_size will less or equal than staging buffer size
            //FIXME false condition generate broken meshes somehow
            bool is_wait_before = mesh_size > TransferStagingData::BUFFER_SIZE - staging_offset;
            //will work correctly:
            //bool is_wait_before = true;

            if (is_wait_before) // if we need more memory on staging buffer than not used already
            {
                result = data.wait_transfer();
                if (result != VK_SUCCESS)
                    return result;
                staging_offset = 0;
            }

            uint8_t *pMemory = static_cast<uint8_t*>(data.stagingData.pMemory) + staging_offset;

            memcpy(pMemory,         mesh.vertices.pX, vSize);
            memcpy(pMemory + vSize, mesh.indices.pXX, iSize);

            if (not is_wait_before)
            {
                result = data.wait_transfer();
                if (result != VK_SUCCESS)
                    return result;
            }
        }

        // write data from staging buffer to mesh buffer
        {
            auto cmd_cpy_buff = [](CommandBuffer cmd, BufferCopy copy, Offsets offsets, DeviceSizeT size)
            {
                cmd.cmd_copy_buffer(copy, offsets, size);
            };

                                       //       SRC                                 DST
            BufferCopy copy = { data.stagingData.buffer, buffer.info.buffer        };
            Offsets offsets = { staging_offset,          buffer.info.region.offset };
            result = data.transfer.prepare(cmd_cpy_buff, data.transfer.cmd_buffer, copy, offsets, mesh_size);
            if (result != VK_SUCCESS)
                return result;

            data.reset_fence();

            result = data.transfer.submit({&data.transfer.cmd_buffer,1},{}, {}, {}, data.transferFence);
            if (result != VK_SUCCESS)
                return result;
        }

        // save usused offset to  data.stagingData.buffer_offset_unused;
        staging_offset = staging_offset == 0 ? mesh_size : 0;

        return result;
    }

Если я могуНе используйте такой промежуточный буфер, чем почему.

Если у меня есть ошибка, idk где.

1 Ответ

1 голос
/ 03 мая 2019

Проблема была

staging_offset = staging_offset == 0 ? mesh_size : 0;

Нужно изменить

staging_offset = staging_offset == 0 ? TransferStagingData::BUFFER_SIZE - mesh_size : 0;

А после смены все работает правильно.

...