Я получаю очень странный сбой (только в режиме отладки) при использовании оператора присваивания перемещения со значением r:
Очистка и повторная компиляция кода в режиме отладки не помогают.Сбой происходит до вызова VulkanBuffer :: operator = ().
// ok
//VulkanBuffer myBuffer(logicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE);
//buffer_ = std::move(myBuffer);
// ok
//VulkanBuffer myBuffer = VulkanBuffer(logicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE);
//buffer_ = std::move(myBuffer);
// crash in debug mode, release mode works fine
//buffer_ = std::move( VulkanBuffer(logicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE) );
// crash in debug mode, release mode works fine
buffer_ = VulkanBuffer(logicalDevice, bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE);
Я получаю это исключение:
Исключение, выданное в 0x0000000059F95E35 (nvoglv64.dll) в Vulkan.exe: 0xC0000005:Место чтения нарушения доступа 0xFFFFFFFFFFFFFFFF.
Это исключение возникает в конструкторе VulkanBuffer, который не является стандартным
Может кто-нибудь пролить свет на это?Мне кажется, что код должен быть эквивалентным.
Фактический код выглядит следующим образом:
Декларация VulkanBuffer
#pragma once
#include "VulkanLogicalDevice.h"
#include "Vertex.h"
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <memory>
#include <vector>
class VulkanCommandPool;
class VulkanBuffer
{
public:
VulkanBuffer();
VulkanBuffer(const std::shared_ptr<VulkanLogicalDevice>& logicalDevice, VkDeviceSize deviceSizeInbytes, VkBufferUsageFlags bufferUsageFlags, VkSharingMode sharingMode);
~VulkanBuffer();
VulkanBuffer(const VulkanBuffer &rhs) = delete;
VulkanBuffer & operator=(const VulkanBuffer &rhs) = delete;
VulkanBuffer(VulkanBuffer &&rhs) = delete;
VulkanBuffer & operator=(VulkanBuffer &&rhs);
VkBuffer & handle() { return buffer_; }
const VkBuffer & handle() const { return buffer_; }
const VkBufferCreateInfo & getBufferInfo() const { return createInfo_; }
void copyDataFrom(const VulkanBuffer & rhs, const VulkanCommandPool &commandPool, VkDeviceSize dataSizeInBytes);
friend void swap(VulkanBuffer &lhs, VulkanBuffer &rhs);
private:
std::shared_ptr<VulkanLogicalDevice> logicalDevice_;
VkBufferCreateInfo createInfo_;
VkBuffer buffer_;
};
Определение VulkanBuffer
#include "VulkanBuffer.h"
#include "VulkanCommandPool.h"
#include "Vertex.h"
#include <iostream>
void swap(VulkanBuffer &lhs, VulkanBuffer &rhs)
{
std::swap(lhs.logicalDevice_, rhs.logicalDevice_);
std::swap(lhs.buffer_, rhs.buffer_);
std::swap(lhs.createInfo_, rhs.createInfo_);
}
VulkanBuffer::VulkanBuffer()
: buffer_(VK_NULL_HANDLE)
{}
/// \param logicalDevice Vulkan device
/// \param deviceSizeInbytes number of bytes of the vertices to be stored in this vertex buffer
/// \param bufferUsageFlags what will the buffer be used for, eg VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
/// \param sharingMode is the buffer used by more than one queue family, eg: VK_SHARING_MODE_EXCLUSIVE, VK_SHARING_MODE_CONCURRENT
VulkanBuffer::VulkanBuffer(const std::shared_ptr<VulkanLogicalDevice>& logicalDevice, VkDeviceSize deviceSizeInbytes, VkBufferUsageFlags bufferUsageFlags, VkSharingMode sharingMode)
: logicalDevice_(logicalDevice), buffer_(VK_NULL_HANDLE)
{
createInfo_.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo_.size = deviceSizeInbytes;
createInfo_.usage = bufferUsageFlags; // indicates this data is for a vertex buffer.
createInfo_.sharingMode = sharingMode; // ownership by one queue family or multiple
if (vkCreateBuffer(logicalDevice->handle(), &createInfo_, nullptr, &buffer_) != VK_SUCCESS) {
throw std::runtime_error("failed to create buffer!");
}
}
VulkanBuffer::~VulkanBuffer()
{
if (buffer_ != VK_NULL_HANDLE)
vkDestroyBuffer(logicalDevice_->handle(), buffer_, nullptr);
}
VulkanBuffer & VulkanBuffer::operator=(VulkanBuffer &&rhs)
{
swap(*this, rhs);
return *this;
}
void VulkanBuffer::copyDataFrom(const VulkanBuffer & rhs, const VulkanCommandPool &commandPool, VkDeviceSize dataSizeInBytes)
{
if (buffer_ == VK_NULL_HANDLE || rhs.buffer_ == VK_NULL_HANDLE)
{
std::cout << "Illegal VulkanBuffer::copyDataFrom(), one or more buffers not initialized.\n";
return;
}
VkCommandBufferAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool.handle();
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(logicalDevice_->handle(), &allocInfo, &commandBuffer);
VkCommandBufferBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
VkBufferCopy copyRegion = {};
copyRegion.size = dataSizeInBytes;
vkCmdCopyBuffer(commandBuffer, rhs.handle(), buffer_, 1, ©Region);
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(logicalDevice_->getGraphicsQueue(), 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(logicalDevice_->getGraphicsQueue());
vkFreeCommandBuffers(logicalDevice_->handle(), commandPool.handle(), 1, &commandBuffer);
}
edit: добавлено это как часть предложения Джерико: Когда класс падает, из функций класса выводится следующее:
handle: 0000000000000000 VulkanBuffer: default ctor()
handle: 0000000000000000 VulkanBuffer: non default ctor() start
handle: 000001B2A00C84E0 VulkanBuffer: non default ctor() end
handle: 0000000000000000 VulkanBuffer: non default ctor() start
, когда не происходит сбой, выводится следующее
handle: 0000000000000000 VulkanBuffer: default ctor()
handle: 0000000000000000 VulkanBuffer: non default ctor() start
handle: 000001989ADB56E0 VulkanBuffer: non default ctor() end
handle: 0000000000000000 VulkanBuffer: non default ctor() start
handle: 000001989ADB6310 VulkanBuffer: non default ctor() end
handle: 0000000000000000 VulkanBuffer: operator=()
handle lhs: 0000000000000000 handle rhs: 000001989ADB6310 VulkanBuffer: Swap() start
handle lhs: 000001989ADB6310 handle rhs: 0000000000000000 VulkanBuffer: Swap() end
handle: 000001989ADB6310 VulkanBuffer: copyDataFrom()
handle: 0000000000000000 VulkanBuffer: dtor() // instruction re-ordered here?
handle: 000001989ADB56E0 VulkanBuffer: dtor()