Add a secondary way to upload textures - through buffers.

This commit is contained in:
Henrik Rydgard 2016-03-14 23:24:19 +01:00
parent c2775d4dfa
commit 5ea01ffff6
3 changed files with 122 additions and 16 deletions

View File

@ -1290,18 +1290,7 @@ void VulkanTexture::Unlock() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
// if we already have an image, queue it for destruction and forget it.
if (image) {
vulkan_->Delete().QueueDeleteImage(image);
image = VK_NULL_HANDLE;
}
if (view) {
vulkan_->Delete().QueueDeleteImageView(view);
view = VK_NULL_HANDLE;
}
if (mem) {
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
mem = VK_NULL_HANDLE;
}
Wipe();
if (!needStaging) {
// If we can use the linear tiled image as a texture, just do it
image = mappableImage;
@ -1424,6 +1413,115 @@ void VulkanTexture::Unlock() {
assert(res == VK_SUCCESS);
}
void VulkanTexture::Wipe() {
if (image) {
vulkan_->Delete().QueueDeleteImage(image);
image = VK_NULL_HANDLE;
}
if (view) {
vulkan_->Delete().QueueDeleteImageView(view);
view = VK_NULL_HANDLE;
}
if (mem) {
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
mem = VK_NULL_HANDLE;
}
}
void VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format) {
Wipe();
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
tex_width = w;
tex_height = h;
numMips_ = numMips;
VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
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;
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);
VkMemoryAllocateInfo mem_alloc = {};
mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_alloc.pNext = NULL;
mem_alloc.memoryTypeIndex = 0;
mem_alloc.allocationSize = mem_reqs.size;
// 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, 0);
assert(res == VK_SUCCESS);
// Since we're going to blit to the target, set its layout to TRANSFER_DST
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Create the view while we're at it.
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = NULL;
view_info.image = VK_NULL_HANDLE;
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 = numMips;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
view_info.image = image;
res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
assert(res == VK_SUCCESS);
}
void VulkanTexture::UploadMip(int mip, VkBuffer buffer, size_t offset, size_t stride) {
VkBufferImageCopy copy_region = {};
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)stride;
copy_region.bufferImageHeight = tex_height;
copy_region.imageExtent.width = tex_width;
copy_region.imageExtent.height = tex_height;
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;
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
}
void VulkanTexture::EndCreate() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
TransitionImageLayout(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void VulkanTexture::Destroy() {
if (view) {
vulkan_->Delete().QueueDeleteImageView(view);

View File

@ -354,27 +354,33 @@ public:
~VulkanTexture() {
Destroy();
}
// Simple usage - no cleverness, no mipmaps.
// Always call Create, Lock, Unlock. Unlock performs the upload if necessary.
// Can later Lock and Unlock again. This cannot change the format. Create cannot
// be called a second time without recreating the texture object until Destroy has
// been called.
VkResult Create(int w, int h, VkFormat format);
uint8_t *Lock(int level, int *rowPitch);
void Unlock();
// Fast uploads from buffer. Mipmaps supported.
void CreateDirect(int w, int h, int numMips, VkFormat format);
void UploadMip(int mip, VkBuffer buffer, size_t offset, size_t stride);
void EndCreate();
void Destroy();
VkImageView GetImageView() const { return view; }
private:
void CreateMappableImage();
void Wipe();
VulkanContext *vulkan_;
VkImage image;
VkDeviceMemory mem;
VkImageView view;
int32_t tex_width, tex_height;
int32_t tex_width, tex_height, numMips_;
VkFormat format_;
VkImage mappableImage;
VkDeviceMemory mappableMemory;

View File

@ -65,8 +65,10 @@
#define TEXCACHE_MIN_PRESSURE 16 * 1024 * 1024 // Total in GL
#define TEXCACHE_SECOND_MIN_PRESSURE 4 * 1024 * 1024
// TODO: Except for color swizzle, exact matches are available.
// So we can get rid of the conversion functions entirely.
#define VULKAN_4444_FORMAT VK_FORMAT_R4G4B4A4_UNORM_PACK16
#define VULKAN_1555_FORMAT VK_FORMAT_R5G5B5A1_UNORM_PACK16 // TODO: Switch to the one that matches the PSP better.
#define VULKAN_1555_FORMAT VK_FORMAT_A1R5G5B5_UNORM_PACK16 // TODO: Switch to the one that matches the PSP better.
#define VULKAN_565_FORMAT VK_FORMAT_R5G6B5_UNORM_PACK16
#define VULKAN_8888_FORMAT VK_FORMAT_R8G8B8A8_UNORM