2016-03-17 10:56:43 +00:00
|
|
|
#include "Common/Vulkan/VulkanImage.h"
|
2016-03-27 01:22:21 +00:00
|
|
|
#include "Common/Vulkan/VulkanMemory.h"
|
2017-12-03 09:29:41 +00:00
|
|
|
#include "Common/Log.h"
|
2016-03-17 10:56:43 +00:00
|
|
|
|
|
|
|
VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
|
|
|
|
tex_width = w;
|
|
|
|
tex_height = h;
|
|
|
|
format_ = format;
|
|
|
|
|
|
|
|
VkFormatProperties formatProps;
|
|
|
|
vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
|
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanTexture::CreateMappableImage() {
|
|
|
|
// If we already have a mappableImage, forget it.
|
|
|
|
if (mappableImage) {
|
|
|
|
vulkan_->Delete().QueueDeleteImage(mappableImage);
|
|
|
|
}
|
|
|
|
if (mappableMemory) {
|
|
|
|
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
|
|
|
|
}
|
|
|
|
|
2017-12-18 11:22:12 +00:00
|
|
|
VkImageCreateInfo image_create_info{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
2016-03-17 10:56:43 +00:00
|
|
|
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
|
|
|
image_create_info.format = format_;
|
|
|
|
image_create_info.extent.width = tex_width;
|
|
|
|
image_create_info.extent.height = tex_height;
|
|
|
|
image_create_info.extent.depth = 1;
|
|
|
|
image_create_info.mipLevels = 1;
|
|
|
|
image_create_info.arrayLayers = 1;
|
|
|
|
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
|
2017-10-20 15:19:07 +00:00
|
|
|
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
2016-03-17 10:56:43 +00:00
|
|
|
image_create_info.queueFamilyIndexCount = 0;
|
|
|
|
image_create_info.pQueueFamilyIndices = NULL;
|
|
|
|
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
image_create_info.flags = 0;
|
|
|
|
image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
|
|
|
|
2017-12-18 11:22:12 +00:00
|
|
|
VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
2016-03-17 10:56:43 +00:00
|
|
|
mem_alloc.allocationSize = 0;
|
|
|
|
mem_alloc.memoryTypeIndex = 0;
|
|
|
|
|
|
|
|
// Create a mappable image. It will be the texture if linear images are ok to be textures
|
|
|
|
// or it will be the staging image if they are not.
|
|
|
|
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &mappableImage);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
vkGetImageMemoryRequirements(vulkan_->GetDevice(), mappableImage, &mem_reqs);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
mem_alloc.allocationSize = mem_reqs.size;
|
|
|
|
|
|
|
|
// Find the memory type that is host mappable.
|
2017-12-18 11:22:12 +00:00
|
|
|
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &mem_alloc.memoryTypeIndex);
|
2016-03-17 10:56:43 +00:00
|
|
|
assert(pass);
|
|
|
|
|
|
|
|
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mappableMemory);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
res = vkBindImageMemory(vulkan_->GetDevice(), mappableImage, mappableMemory, 0);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
|
|
|
|
CreateMappableImage();
|
|
|
|
|
|
|
|
VkImageSubresource subres = {};
|
|
|
|
subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
subres.mipLevel = 0;
|
|
|
|
subres.arrayLayer = 0;
|
|
|
|
|
|
|
|
VkSubresourceLayout layout;
|
|
|
|
void *data;
|
|
|
|
|
|
|
|
// Get the subresource layout so we know what the row pitch is
|
|
|
|
vkGetImageSubresourceLayout(vulkan_->GetDevice(), mappableImage, &subres, &layout);
|
|
|
|
VkResult res = vkMapMemory(vulkan_->GetDevice(), mappableMemory, layout.offset, layout.size, 0, &data);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
*rowPitch = (int)layout.rowPitch;
|
|
|
|
return (uint8_t *)data;
|
|
|
|
}
|
|
|
|
|
2017-08-19 15:32:10 +00:00
|
|
|
void VulkanTexture::Unlock(VkCommandBuffer cmd) {
|
2016-03-17 10:56:43 +00:00
|
|
|
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
|
|
|
|
|
|
|
|
// if we already have an image, queue it for destruction and forget it.
|
|
|
|
Wipe();
|
2017-10-20 15:19:07 +00:00
|
|
|
|
|
|
|
{ // Shrink the diff by not unindenting. If you make major changes, remove this.
|
2018-02-24 15:55:32 +00:00
|
|
|
VkImageCreateInfo image_create_info{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
2016-03-17 10:56:43 +00:00
|
|
|
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
|
|
|
image_create_info.format = format_;
|
|
|
|
image_create_info.extent.width = tex_width;
|
|
|
|
image_create_info.extent.height = tex_height;
|
|
|
|
image_create_info.extent.depth = 1;
|
|
|
|
image_create_info.mipLevels = 1;
|
|
|
|
image_create_info.arrayLayers = 1;
|
|
|
|
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
image_create_info.queueFamilyIndexCount = 0;
|
|
|
|
image_create_info.pQueueFamilyIndices = NULL;
|
|
|
|
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
image_create_info.flags = 0;
|
|
|
|
// The mappable image cannot be our texture, so create an optimally tiled image and blit to it
|
|
|
|
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
|
|
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
|
|
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
|
|
|
|
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
|
|
|
|
|
2018-02-24 15:55:32 +00:00
|
|
|
VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
2016-03-17 10:56:43 +00:00
|
|
|
mem_alloc.memoryTypeIndex = 0;
|
|
|
|
mem_alloc.allocationSize = mem_reqs.size;
|
|
|
|
|
2017-12-03 09:50:25 +00:00
|
|
|
if (allocator_) {
|
|
|
|
offset_ = allocator_->Allocate(mem_reqs, &mem);
|
|
|
|
} else {
|
|
|
|
offset_ = 0;
|
|
|
|
// Find memory type - don't specify any mapping requirements
|
|
|
|
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
|
|
|
assert(pass);
|
|
|
|
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, offset_);
|
2016-03-17 10:56:43 +00:00
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
|
2017-12-05 12:05:11 +00:00
|
|
|
TransitionImageLayout2(cmd, mappableImage, 0, 1,
|
2016-03-17 10:56:43 +00:00
|
|
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
2017-10-20 12:47:36 +00:00
|
|
|
VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
|
|
VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
2016-03-17 10:56:43 +00:00
|
|
|
|
2017-12-05 12:05:11 +00:00
|
|
|
TransitionImageLayout2(cmd, image, 0, 1,
|
2016-03-17 10:56:43 +00:00
|
|
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
2017-10-20 12:47:36 +00:00
|
|
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
0, VK_ACCESS_TRANSFER_WRITE_BIT);
|
2016-03-17 10:56:43 +00:00
|
|
|
|
|
|
|
VkImageCopy copy_region;
|
|
|
|
copy_region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
copy_region.srcSubresource.mipLevel = 0;
|
|
|
|
copy_region.srcSubresource.baseArrayLayer = 0;
|
|
|
|
copy_region.srcSubresource.layerCount = 1;
|
|
|
|
copy_region.srcOffset.x = 0;
|
|
|
|
copy_region.srcOffset.y = 0;
|
|
|
|
copy_region.srcOffset.z = 0;
|
|
|
|
copy_region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
copy_region.dstSubresource.mipLevel = 0;
|
|
|
|
copy_region.dstSubresource.baseArrayLayer = 0;
|
|
|
|
copy_region.dstSubresource.layerCount = 1;
|
|
|
|
copy_region.dstOffset.x = 0;
|
|
|
|
copy_region.dstOffset.y = 0;
|
|
|
|
copy_region.dstOffset.z = 0;
|
|
|
|
copy_region.extent.width = tex_width;
|
|
|
|
copy_region.extent.height = tex_height;
|
|
|
|
copy_region.extent.depth = 1;
|
|
|
|
|
|
|
|
// Put the copy command into the command buffer
|
|
|
|
vkCmdCopyImage(cmd,
|
|
|
|
mappableImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
|
|
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
1, ©_region);
|
|
|
|
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
|
|
|
|
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
|
2017-12-05 12:05:11 +00:00
|
|
|
TransitionImageLayout2(cmd, image, 0, 1,
|
2016-03-17 10:56:43 +00:00
|
|
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
2017-10-20 12:47:36 +00:00
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
|
2016-03-17 10:56:43 +00:00
|
|
|
|
|
|
|
// Then drop the temporary mappable image - although should not be necessary...
|
|
|
|
vulkan_->Delete().QueueDeleteImage(mappableImage);
|
|
|
|
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
|
|
|
|
}
|
|
|
|
|
2018-02-24 15:55:32 +00:00
|
|
|
VkImageViewCreateInfo view_info{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
2016-03-27 01:41:53 +00:00
|
|
|
view_info.image = image;
|
2016-03-17 10:56:43 +00:00
|
|
|
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
view_info.format = format_;
|
|
|
|
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
|
|
|
|
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
|
|
|
|
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
|
|
|
|
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
|
|
|
|
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
view_info.subresourceRange.baseMipLevel = 0;
|
|
|
|
view_info.subresourceRange.levelCount = 1;
|
|
|
|
view_info.subresourceRange.baseArrayLayer = 0;
|
|
|
|
view_info.subresourceRange.layerCount = 1;
|
|
|
|
VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
|
|
|
|
assert(res == VK_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanTexture::Wipe() {
|
|
|
|
if (image) {
|
|
|
|
vulkan_->Delete().QueueDeleteImage(image);
|
|
|
|
}
|
|
|
|
if (view) {
|
|
|
|
vulkan_->Delete().QueueDeleteImageView(view);
|
|
|
|
}
|
2016-03-27 01:22:21 +00:00
|
|
|
if (mem && !allocator_) {
|
2016-03-17 10:56:43 +00:00
|
|
|
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
|
2016-03-27 01:22:21 +00:00
|
|
|
} else if (mem) {
|
|
|
|
allocator_->Free(mem, offset_);
|
|
|
|
mem = VK_NULL_HANDLE;
|
2016-03-17 10:56:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-28 16:18:49 +00:00
|
|
|
static bool IsDepthStencilFormat(VkFormat format) {
|
|
|
|
switch (format) {
|
|
|
|
case VK_FORMAT_D16_UNORM:
|
|
|
|
case VK_FORMAT_D16_UNORM_S8_UINT:
|
|
|
|
case VK_FORMAT_D24_UNORM_S8_UINT:
|
|
|
|
case VK_FORMAT_D32_SFLOAT:
|
|
|
|
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-19 15:32:10 +00:00
|
|
|
bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
|
2016-03-17 10:56:43 +00:00
|
|
|
Wipe();
|
|
|
|
|
|
|
|
tex_width = w;
|
|
|
|
tex_height = h;
|
|
|
|
numMips_ = numMips;
|
|
|
|
format_ = format;
|
|
|
|
|
2016-03-28 16:18:49 +00:00
|
|
|
VkImageAspectFlags aspect = IsDepthStencilFormat(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
|
2018-02-24 15:55:32 +00:00
|
|
|
VkImageCreateInfo image_create_info{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
2016-03-17 10:56:43 +00:00
|
|
|
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
|
|
|
image_create_info.format = format_;
|
|
|
|
image_create_info.extent.width = tex_width;
|
|
|
|
image_create_info.extent.height = tex_height;
|
|
|
|
image_create_info.extent.depth = 1;
|
|
|
|
image_create_info.mipLevels = numMips;
|
|
|
|
image_create_info.arrayLayers = 1;
|
|
|
|
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
image_create_info.flags = 0;
|
|
|
|
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
2016-03-28 16:18:49 +00:00
|
|
|
image_create_info.usage = usage;
|
|
|
|
if (initialLayout == VK_IMAGE_LAYOUT_PREINITIALIZED) {
|
|
|
|
image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
|
|
|
|
} else {
|
|
|
|
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
2016-03-17 10:56:43 +00:00
|
|
|
VkResult res = vkCreateImage(vulkan_->GetDevice(), &image_create_info, NULL, &image);
|
2016-03-27 01:41:53 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
|
|
|
assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-17 10:56:43 +00:00
|
|
|
|
|
|
|
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
|
|
|
|
|
2016-03-27 01:22:21 +00:00
|
|
|
if (allocator_) {
|
|
|
|
offset_ = allocator_->Allocate(mem_reqs, &mem);
|
2016-03-27 01:41:53 +00:00
|
|
|
if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 01:22:21 +00:00
|
|
|
} else {
|
2018-02-24 15:55:32 +00:00
|
|
|
VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
2016-03-27 01:22:21 +00:00
|
|
|
mem_alloc.memoryTypeIndex = 0;
|
|
|
|
mem_alloc.allocationSize = mem_reqs.size;
|
2016-03-17 10:56:43 +00:00
|
|
|
|
2016-03-27 01:22:21 +00:00
|
|
|
// Find memory type - don't specify any mapping requirements
|
|
|
|
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &mem_alloc.memoryTypeIndex);
|
|
|
|
assert(pass);
|
|
|
|
|
|
|
|
res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mem);
|
2016-03-27 01:41:53 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
2017-12-03 09:29:41 +00:00
|
|
|
_assert_msg_(G3D, res != VK_ERROR_TOO_MANY_OBJECTS, "Too many Vulkan memory objects!");
|
2016-03-27 01:41:53 +00:00
|
|
|
assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 01:22:21 +00:00
|
|
|
|
|
|
|
offset_ = 0;
|
|
|
|
}
|
2016-03-17 10:56:43 +00:00
|
|
|
|
2016-03-27 01:22:21 +00:00
|
|
|
res = vkBindImageMemory(vulkan_->GetDevice(), image, mem, offset_);
|
2016-03-27 01:41:53 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
|
|
|
assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-17 10:56:43 +00:00
|
|
|
|
2017-12-20 15:40:09 +00:00
|
|
|
// Write a command to transition the image to the requested layout, if it's not already that layout.
|
|
|
|
if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) {
|
|
|
|
switch (initialLayout) {
|
|
|
|
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
|
|
|
|
TransitionImageLayout2(cmd, image, 0, numMips, VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
0, VK_ACCESS_TRANSFER_WRITE_BIT);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// If you planned to use UploadMip, you want VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. After the
|
|
|
|
// upload, you can transition.
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-17 10:56:43 +00:00
|
|
|
// Create the view while we're at it.
|
2018-02-24 15:55:32 +00:00
|
|
|
VkImageViewCreateInfo view_info{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
2016-03-27 01:41:53 +00:00
|
|
|
view_info.image = image;
|
2016-03-17 10:56:43 +00:00
|
|
|
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
view_info.format = format_;
|
2016-03-26 20:17:17 +00:00
|
|
|
if (mapping) {
|
|
|
|
view_info.components = *mapping;
|
|
|
|
} else {
|
|
|
|
view_info.components.r = VK_COMPONENT_SWIZZLE_R;
|
|
|
|
view_info.components.g = VK_COMPONENT_SWIZZLE_G;
|
|
|
|
view_info.components.b = VK_COMPONENT_SWIZZLE_B;
|
|
|
|
view_info.components.a = VK_COMPONENT_SWIZZLE_A;
|
|
|
|
}
|
2016-03-28 16:18:49 +00:00
|
|
|
view_info.subresourceRange.aspectMask = aspect;
|
2016-03-17 10:56:43 +00:00
|
|
|
view_info.subresourceRange.baseMipLevel = 0;
|
|
|
|
view_info.subresourceRange.levelCount = numMips;
|
|
|
|
view_info.subresourceRange.baseArrayLayer = 0;
|
|
|
|
view_info.subresourceRange.layerCount = 1;
|
2016-03-28 16:18:49 +00:00
|
|
|
|
2016-03-17 10:56:43 +00:00
|
|
|
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
|
2016-03-27 01:41:53 +00:00
|
|
|
if (res != VK_SUCCESS) {
|
|
|
|
assert(res == VK_ERROR_OUT_OF_HOST_MEMORY || res == VK_ERROR_OUT_OF_DEVICE_MEMORY || res == VK_ERROR_TOO_MANY_OBJECTS);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
2016-03-17 10:56:43 +00:00
|
|
|
}
|
|
|
|
|
2017-08-19 15:32:10 +00:00
|
|
|
void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
|
2018-02-24 15:55:32 +00:00
|
|
|
VkBufferImageCopy copy_region{};
|
2016-03-17 10:56:43 +00:00
|
|
|
copy_region.bufferOffset = offset;
|
|
|
|
copy_region.bufferRowLength = (uint32_t)rowLength;
|
|
|
|
copy_region.bufferImageHeight = 0; // 2D
|
|
|
|
copy_region.imageExtent.width = mipWidth;
|
|
|
|
copy_region.imageExtent.height = mipHeight;
|
|
|
|
copy_region.imageExtent.depth = 1;
|
|
|
|
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
copy_region.imageSubresource.mipLevel = mip;
|
|
|
|
copy_region.imageSubresource.baseArrayLayer = 0;
|
|
|
|
copy_region.imageSubresource.layerCount = 1;
|
|
|
|
|
|
|
|
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
|
|
|
}
|
|
|
|
|
2017-12-05 12:05:11 +00:00
|
|
|
void VulkanTexture::GenerateMip(VkCommandBuffer cmd, int mip) {
|
|
|
|
_assert_msg_(G3D, mip != 0, "Cannot generate the first level");
|
|
|
|
_assert_msg_(G3D, mip < numMips_, "Cannot generate mipmaps past the maximum created (%d vs %d)", mip, numMips_);
|
|
|
|
VkImageBlit blit{};
|
|
|
|
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
blit.srcSubresource.layerCount = 1;
|
|
|
|
blit.srcSubresource.mipLevel = mip - 1;
|
|
|
|
blit.srcOffsets[1].x = tex_width >> (mip - 1);
|
|
|
|
blit.srcOffsets[1].y = tex_height >> (mip - 1);
|
|
|
|
blit.srcOffsets[1].z = 1;
|
|
|
|
|
|
|
|
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
blit.dstSubresource.layerCount = 1;
|
|
|
|
blit.dstSubresource.mipLevel = mip;
|
|
|
|
blit.dstOffsets[1].x = tex_width >> mip;
|
|
|
|
blit.dstOffsets[1].y = tex_height >> mip;
|
|
|
|
blit.dstOffsets[1].z = 1;
|
|
|
|
|
|
|
|
TransitionImageLayout2(cmd, image, mip - 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
|
|
|
|
|
|
|
// Low-quality mipmap generation, but works okay.
|
|
|
|
vkCmdBlitImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
|
|
|
|
|
|
|
|
TransitionImageLayout2(cmd, image, mip - 1, 1, VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT);
|
|
|
|
}
|
|
|
|
|
2017-11-11 20:50:24 +00:00
|
|
|
void VulkanTexture::EndCreate(VkCommandBuffer cmd, bool vertexTexture) {
|
2017-12-05 12:05:11 +00:00
|
|
|
TransitionImageLayout2(cmd, image, 0, 1,
|
2016-03-17 10:56:43 +00:00
|
|
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
2017-10-20 15:19:07 +00:00
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
2017-11-11 20:50:24 +00:00
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, vertexTexture ? VK_PIPELINE_STAGE_VERTEX_SHADER_BIT : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
2017-10-20 15:19:07 +00:00
|
|
|
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
|
2016-03-17 10:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VulkanTexture::Destroy() {
|
2016-10-09 19:16:42 +00:00
|
|
|
if (view != VK_NULL_HANDLE) {
|
2016-03-17 10:56:43 +00:00
|
|
|
vulkan_->Delete().QueueDeleteImageView(view);
|
|
|
|
}
|
2016-10-09 19:16:42 +00:00
|
|
|
if (image != VK_NULL_HANDLE) {
|
2016-03-17 10:56:43 +00:00
|
|
|
if (mappableImage == image) {
|
|
|
|
mappableImage = VK_NULL_HANDLE;
|
|
|
|
}
|
2016-10-09 19:16:42 +00:00
|
|
|
vulkan_->Delete().QueueDeleteImage(image);
|
2016-03-17 10:56:43 +00:00
|
|
|
}
|
2016-10-09 19:16:42 +00:00
|
|
|
if (mem != VK_NULL_HANDLE && !allocator_) {
|
2016-03-17 10:56:43 +00:00
|
|
|
if (mappableMemory == mem) {
|
|
|
|
mappableMemory = VK_NULL_HANDLE;
|
|
|
|
}
|
2016-10-09 19:16:42 +00:00
|
|
|
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
|
|
|
|
} else if (mem != VK_NULL_HANDLE) {
|
2016-03-27 01:22:21 +00:00
|
|
|
allocator_->Free(mem, offset_);
|
2016-10-09 19:16:42 +00:00
|
|
|
mem = VK_NULL_HANDLE;
|
2016-03-17 10:56:43 +00:00
|
|
|
}
|
|
|
|
}
|