Пример #1
0
void Image::cmdPipelineBarrier(const VkCommandBuffer cmdBuffer, const VkAccessFlags dstAccessMask, const VkImageLayout newLayout, const VkImageSubresourceRange& subresourceRange)
{
	if (newLayout == VK_IMAGE_LAYOUT_UNDEFINED || newLayout == VK_IMAGE_LAYOUT_PREINITIALIZED)
	{
		logPrint(VKTS_LOG_WARNING, "Image: New layout not allowed: %d", newLayout);

		return;
	}

	VkImageMemoryBarrier imageMemoryBarrier;

	memset(&imageMemoryBarrier, 0, sizeof(VkImageMemoryBarrier));

	imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;

	imageMemoryBarrier.dstAccessMask = dstAccessMask;
	imageMemoryBarrier.newLayout = newLayout;
	imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
	imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
	imageMemoryBarrier.image = image;
	imageMemoryBarrier.subresourceRange = subresourceRange;

	// It is allowed, that each mip level can have different layouts.
	for (uint32_t arrayLayer = subresourceRange.baseArrayLayer; arrayLayer < subresourceRange.baseArrayLayer + subresourceRange.layerCount; arrayLayer++)
	{
		for (uint32_t mipLevel = subresourceRange.baseMipLevel; mipLevel < subresourceRange.baseMipLevel + subresourceRange.levelCount; mipLevel++)
		{
			if (accessMask[arrayLayer * getMipLevels() + mipLevel] == dstAccessMask && imageLayout[arrayLayer * getMipLevels() + mipLevel] == newLayout)
			{
				continue;
			}

			imageMemoryBarrier.srcAccessMask = accessMask[arrayLayer * getMipLevels() + mipLevel];
			imageMemoryBarrier.oldLayout = imageLayout[arrayLayer * getMipLevels() + mipLevel];
			imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevel;
			imageMemoryBarrier.subresourceRange.levelCount = 1;
			imageMemoryBarrier.subresourceRange.baseArrayLayer = arrayLayer;
			imageMemoryBarrier.subresourceRange.layerCount = 1;

			vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);

			accessMask[arrayLayer * getMipLevels() + mipLevel] = dstAccessMask;
			imageLayout[arrayLayer * getMipLevels() + mipLevel] = newLayout;
		}
	}
}
Пример #2
0
	ErrorCode DXTexture2D::setData( int xOffset, int yOffset, int width, int height, void* data, TextureFormat::Format format ) {
		// update if already valid
		if( _shaderResourceView != nullptr ) {
			// format must be the same
			if( format != _format ) {
				return ErrorCode::CIRI_INVALID_ARGUMENT;
			}

			// for now, the enture texture must be updated, and it must therefore be of the same size
			if( width != _width || height != _height || xOffset != 0 || yOffset != 0 ) {
				return ErrorCode::CIRI_NOT_IMPLEMENTED;
			}

			// todo: support editing (also change below to dynamic)
			return ErrorCode::CIRI_NOT_IMPLEMENTED;
		}

		// offsets must be zero when initializing the texture
		if( xOffset != 0 || yOffset != 0 ) {
			return ErrorCode::CIRI_INVALID_ARGUMENT;
		}

		// width and height must be positive
		if( width <= 0 || height <= 0 ) {
			return ErrorCode::CIRI_INVALID_ARGUMENT;
		}

		_width = width;
		_height = height;
		_format = format;

		D3D11_TEXTURE2D_DESC texDesc;
		ZeroMemory(&texDesc, sizeof(texDesc));
		texDesc.Width = width;
		texDesc.Height = height;
		texDesc.MipLevels = getMipLevels();
		texDesc.ArraySize = 1; // todo: arraySize (for cube textures and whatnot)
		texDesc.Format = ciriToDxTextureFormat(format);
		texDesc.SampleDesc.Count = 1;
		texDesc.SampleDesc.Quality = 0;
		texDesc.Usage = getUsage();
		texDesc.BindFlags = getBindFlags();
		texDesc.CPUAccessFlags = getCpuFlags();
		texDesc.MiscFlags = getMiscFlags();

		// multisampled textures require initialization with nullptr first, so just do it this way for everything for simplicity
		if( FAILED(_device->getDevice()->CreateTexture2D(&texDesc, nullptr, &_texture2D)) ) {
			destroy();
			return ErrorCode::CIRI_UNKNOWN_ERROR; // todo: texture create failure
		}

		// update the subresource (a.k.a set pixel data) if there is any
		if( data != nullptr ) {
			const UINT pitch = width * TextureFormat::bytesPerPixel(format);
			_device->getContext()->UpdateSubresource(_texture2D, 0, nullptr, data, pitch, 0);
		}

		// create actual shader resource view
		if( FAILED(_device->getDevice()->CreateShaderResourceView(_texture2D, nullptr, &_shaderResourceView)) ) {
			destroy();
			return ErrorCode::CIRI_UNKNOWN_ERROR; // todo: texture create failure
		}

		// generate mipmaps
		if( _flags & TextureFlags::Mipmaps ) {
			_device->getContext()->GenerateMips(_shaderResourceView);
		}

		return ErrorCode::CIRI_OK;
	}
Пример #3
0
VkAccessFlags Image::getAccessMask(const uint32_t mipLevel, const uint32_t arrayLayer) const
{
	return accessMask[arrayLayer * getMipLevels() + mipLevel];
}
Пример #4
0
VkImageLayout Image::getImageLayout(const uint32_t mipLevel, const uint32_t arrayLayer) const
{
    return imageLayout[arrayLayer * getMipLevels() + mipLevel];
}
Пример #5
0
vkts::IImageDataSP Example::gatherImageData() const
{
	VkResult result;

	auto fence = vkts::fenceCreate(device->getDevice(), 0);

	if (!fence.get())
	{
		vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not create fence.");

		return vkts::IImageDataSP();
	}

	//

	auto imageData = vkts::imageDataCreate(VKTS_IMAGE_NAME, VKTS_IMAGE_LENGTH, VKTS_IMAGE_LENGTH, 1, 1.0f, 0.0f, 0.0f, 1.0f, VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM);

	// Check, if we can use a linear tiled image for staging.
	if (physicalDevice->isImageTilingAvailable(VK_IMAGE_TILING_LINEAR, imageData->getFormat(), imageData->getImageType(), 0, imageData->getExtent3D(), imageData->getMipLevels(), 1, VK_SAMPLE_COUNT_1_BIT, imageData->getSize()))
	{
		vkts::IImageSP stageImage;
		vkts::IDeviceMemorySP stageDeviceMemory;

		if (!createTexture(stageImage, stageDeviceMemory, VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0))
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not create stage image and device memory.");

			return vkts::IImageDataSP();
		}

		//

		cmdBuffer->reset();


		result = cmdBuffer->beginCommandBuffer(0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, VK_FALSE, 0, 0);

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not begin command buffer.");

			return vkts::IImageDataSP();
		}

		VkImageSubresourceRange imageSubresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };

		// Prepare stage image for final layout etc.
		stageImage->cmdPipelineBarrier(cmdBuffer->getCommandBuffer(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageSubresourceRange);

		VkImageCopy imageCopy;

		imageCopy.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
		imageCopy.srcOffset = {0, 0, 0};
		imageCopy.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
		imageCopy.dstOffset = {0, 0, 0};
		imageCopy.extent = { VKTS_IMAGE_LENGTH, VKTS_IMAGE_LENGTH, 1u };

		// Copy form device to host visible image / memory. This command also sets the needed barriers.
		image->copyImage(cmdBuffer->getCommandBuffer(), stageImage, imageCopy);

		stageImage->cmdPipelineBarrier(cmdBuffer->getCommandBuffer(), VK_ACCESS_HOST_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, imageSubresourceRange);

		result = cmdBuffer->endCommandBuffer();

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not end command buffer.");

			return VK_FALSE;
		}


		VkSubmitInfo submitInfo{};

		submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

		submitInfo.waitSemaphoreCount = 0;
		submitInfo.pWaitSemaphores = nullptr;
		submitInfo.commandBufferCount = 1;
		submitInfo.pCommandBuffers = cmdBuffer->getCommandBuffers();
		submitInfo.signalSemaphoreCount = 0;
		submitInfo.pSignalSemaphores = nullptr;

		result = queue->submit(1, &submitInfo, fence->getFence());

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not submit queue.");

			return vkts::IImageDataSP();
		}

		//

		result = fence->waitForFence(UINT64_MAX);

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not wait for fence.");

			return vkts::IImageDataSP();
		}

		//
		// Copy pixel data from device memory into image data memory.
		//

		VkImageSubresource imageSubresource;

		imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
		imageSubresource.mipLevel = 0;
		imageSubresource.arrayLayer = 0;

		VkSubresourceLayout subresourceLayout;

		stageImage->getImageSubresourceLayout(subresourceLayout, imageSubresource);

		//

		result = stageDeviceMemory->mapMemory(0, VK_WHOLE_SIZE, 0);

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not map memory.");

			return vkts::IImageDataSP();
		}

		imageData->upload(stageDeviceMemory->getMemory(), 0, 0, subresourceLayout);

		if (!(stageDeviceMemory->getMemoryPropertyFlags() & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
		{
			result = stageDeviceMemory->invalidateMappedMemoryRanges(0, VK_WHOLE_SIZE);

			if (result != VK_SUCCESS)
			{
				vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not invalidate memory.");

				return VK_FALSE;
			}
		}

		stageDeviceMemory->unmapMemory();

		// Stage image and device memory are automatically destroyed.
	}
	else
	{
		// As an alternative, use the buffer.

		vkts::IBufferSP stageBuffer;
		vkts::IDeviceMemorySP stageDeviceMemory;

		VkBufferCreateInfo bufferCreateInfo{};

        bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
        bufferCreateInfo.size = imageData->getSize();
        bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
        bufferCreateInfo.flags = 0;
        bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
        bufferCreateInfo.queueFamilyIndexCount = 0;
        bufferCreateInfo.pQueueFamilyIndices = nullptr;

        if (!createBuffer(stageBuffer, stageDeviceMemory, bufferCreateInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
        {
    		vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not create buffer.");

			return vkts::IImageDataSP();
        }


		//

		cmdBuffer->reset();


		result = cmdBuffer->beginCommandBuffer(0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, VK_FALSE, 0, 0);

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not begin command buffer.");

			return vkts::IImageDataSP();
		}

		VkBufferImageCopy bufferImageCopy;

		bufferImageCopy.bufferOffset = 0;
		bufferImageCopy.bufferRowLength = VKTS_IMAGE_LENGTH;
		bufferImageCopy.bufferImageHeight = VKTS_IMAGE_LENGTH;
		bufferImageCopy.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
		bufferImageCopy.imageOffset = {0, 0, 0};
		bufferImageCopy.imageExtent = {VKTS_IMAGE_LENGTH, VKTS_IMAGE_LENGTH, 1};

		image->copyImageToBuffer(cmdBuffer->getCommandBuffer(), stageBuffer, bufferImageCopy);


		result = cmdBuffer->endCommandBuffer();

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not end command buffer.");

			return VK_FALSE;
		}


		VkSubmitInfo submitInfo{};

		submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;

		submitInfo.waitSemaphoreCount = 0;
		submitInfo.pWaitSemaphores = nullptr;
		submitInfo.commandBufferCount = 1;
		submitInfo.pCommandBuffers = cmdBuffer->getCommandBuffers();
		submitInfo.signalSemaphoreCount = 0;
		submitInfo.pSignalSemaphores = nullptr;

		result = queue->submit(1, &submitInfo, fence->getFence());

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not submit queue.");

			return vkts::IImageDataSP();
		}

		//

		result = fence->waitForFence(UINT64_MAX);

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not wait for fence.");

			return vkts::IImageDataSP();
		}

		//
		// Copy pixel data from device memory into image data memory.
		//

		VkSubresourceLayout subresourceLayout;

		subresourceLayout.offset = 0;
		subresourceLayout.size = stageBuffer->getSize();
		subresourceLayout.rowPitch = VKTS_IMAGE_LENGTH * 4 * sizeof(uint8_t);
		subresourceLayout.arrayPitch = VKTS_IMAGE_LENGTH * VKTS_IMAGE_LENGTH * 4 * sizeof(uint8_t);
		subresourceLayout.depthPitch = VKTS_IMAGE_LENGTH * VKTS_IMAGE_LENGTH * 4 * sizeof(uint8_t);

		result = stageDeviceMemory->mapMemory(0, VK_WHOLE_SIZE, 0);

		if (result != VK_SUCCESS)
		{
			vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not map memory.");

			return vkts::IImageDataSP();
		}

		imageData->upload(stageDeviceMemory->getMemory(), 0, 0, subresourceLayout);

		if (!(stageDeviceMemory->getMemoryPropertyFlags() & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
		{
			result = stageDeviceMemory->invalidateMappedMemoryRanges(0, VK_WHOLE_SIZE);

			if (result != VK_SUCCESS)
			{
				vkts::logPrint(VKTS_LOG_ERROR, __FILE__, __LINE__, "Could not invalidate memory.");

				return VK_FALSE;
			}
		}

		stageDeviceMemory->unmapMemory();

		// Stage image and device memory are automatically destroyed.
	}

	// Fence is automatically destroyed.

	return imageData;
}