Merge pull request #10645 from hrydgard/vulkan-cleanups

Vulkan cleanups: Remove old texture upload method, etc.
This commit is contained in:
Henrik Rydgård 2018-02-26 09:24:24 +01:00 committed by GitHub
commit 373e53fa66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 120 additions and 330 deletions

View File

@ -547,7 +547,7 @@ VkResult VulkanContext::CreateDevice() {
return VK_ERROR_INITIALIZATION_FAILED;
}
VkDeviceQueueCreateInfo queue_info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
VkDeviceQueueCreateInfo queue_info{ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
float queue_priorities[1] = { 1.0f };
queue_info.queueCount = 1;
queue_info.pQueuePriorities = queue_priorities;
@ -563,7 +563,7 @@ VkResult VulkanContext::CreateDevice() {
deviceExtensionsLookup_.DEDICATED_ALLOCATION = EnableDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
VkDeviceCreateInfo device_info { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
VkDeviceCreateInfo device_info{ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
device_info.queueCreateInfoCount = 1;
device_info.pQueueCreateInfos = &queue_info;
device_info.enabledLayerCount = (uint32_t)device_layer_names_.size();

View File

@ -2,204 +2,6 @@
#include "Common/Vulkan/VulkanMemory.h"
#include "Common/Log.h"
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);
}
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 = 1;
image_create_info.arrayLayers = 1;
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_create_info.tiling = VK_IMAGE_TILING_LINEAR;
image_create_info.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
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;
VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
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.
bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &mem_alloc.memoryTypeIndex);
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;
}
void VulkanTexture::Unlock(VkCommandBuffer cmd) {
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
// if we already have an image, queue it for destruction and forget it.
Wipe();
{ // Shrink the diff by not unindenting. If you make major changes, remove this.
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 = 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);
VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
mem_alloc.memoryTypeIndex = 0;
mem_alloc.allocationSize = mem_reqs.size;
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_);
assert(res == VK_SUCCESS);
// Since we're going to blit from the mappable image, set its layout to SOURCE_OPTIMAL
TransitionImageLayout2(cmd, mappableImage, 0, 1,
VK_IMAGE_ASPECT_COLOR_BIT,
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);
TransitionImageLayout2(cmd, image, 0, 1,
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);
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, &copy_region);
assert(res == VK_SUCCESS);
// Set the layout for the texture image from DESTINATION_OPTIMAL to SHADER_READ_ONLY
TransitionImageLayout2(cmd, image, 0, 1,
VK_IMAGE_ASPECT_COLOR_BIT,
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);
// Then drop the temporary mappable image - although should not be necessary...
vulkan_->Delete().QueueDeleteImage(mappableImage);
vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
}
VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
view_info.image = image;
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);
@ -238,7 +40,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
VkImageAspectFlags aspect = IsDepthStencilFormat(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
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;
@ -262,6 +64,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
return false;
}
VkMemoryRequirements mem_reqs{};
vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs);
if (allocator_) {
@ -270,7 +73,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
return false;
}
} else {
VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
mem_alloc.memoryTypeIndex = 0;
mem_alloc.allocationSize = mem_reqs.size;
@ -312,7 +115,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
}
// Create the view while we're at it.
VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
VkImageViewCreateInfo view_info{ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
view_info.image = image;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format_;
@ -339,7 +142,7 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips,
}
void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
VkBufferImageCopy copy_region = {};
VkBufferImageCopy copy_region{};
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)rowLength;
copy_region.bufferImageHeight = 0; // 2D
@ -399,15 +202,9 @@ void VulkanTexture::Destroy() {
vulkan_->Delete().QueueDeleteImageView(view);
}
if (image != VK_NULL_HANDLE) {
if (mappableImage == image) {
mappableImage = VK_NULL_HANDLE;
}
vulkan_->Delete().QueueDeleteImage(image);
}
if (mem != VK_NULL_HANDLE && !allocator_) {
if (mappableMemory == mem) {
mappableMemory = VK_NULL_HANDLE;
}
vulkan_->Delete().QueueDeleteDeviceMemory(mem);
} else if (mem != VK_NULL_HANDLE) {
allocator_->Free(mem, offset_);

View File

@ -11,23 +11,12 @@ public:
VulkanTexture(VulkanContext *vulkan, VulkanDeviceAllocator *allocator)
: vulkan_(vulkan), image(VK_NULL_HANDLE), mem(VK_NULL_HANDLE), view(VK_NULL_HANDLE),
tex_width(0), tex_height(0), numMips_(1), format_(VK_FORMAT_UNDEFINED),
mappableImage(VK_NULL_HANDLE), mappableMemory(VK_NULL_HANDLE),
allocator_(allocator), offset_(0) {
memset(&mem_reqs, 0, sizeof(mem_reqs));
}
~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(VkCommandBuffer cmd);
// Fast uploads from buffer. Mipmaps supported.
// Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
// When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
@ -50,18 +39,14 @@ public:
VkFormat GetFormat() const { return format_; }
private:
void CreateMappableImage();
void Wipe();
VulkanContext *vulkan_;
VkImage image;
VkDeviceMemory mem;
VkImageView view;
VkDeviceMemory mem;
int32_t tex_width, tex_height, numMips_;
VkFormat format_;
VkImage mappableImage;
VkDeviceMemory mappableMemory;
VkMemoryRequirements mem_reqs;
VulkanDeviceAllocator *allocator_;
size_t offset_;
};

View File

@ -36,7 +36,7 @@ VulkanPushBuffer::~VulkanPushBuffer() {
bool VulkanPushBuffer::AddBuffer() {
BufInfo info;
VkBufferCreateInfo b = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
VkBufferCreateInfo b{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
b.size = size_;
b.flags = 0;
b.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
@ -56,7 +56,7 @@ bool VulkanPushBuffer::AddBuffer() {
// TODO: We really should use memoryTypeIndex here..
// Okay, that's the buffer. Now let's allocate some memory for it.
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
// TODO: Should check here that memoryTypeIndex_ matches reqs.memoryTypeBits.
alloc.memoryTypeIndex = memoryTypeIndex_;
alloc.allocationSize = reqs.size;
@ -145,7 +145,7 @@ void VulkanPushBuffer::Unmap() {
assert(writePtr_);
/*
// Should not need this since we use coherent memory.
VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
VkMappedMemoryRange range{ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
range.offset = 0;
range.size = offset_;
range.memory = buffers_[buf_].deviceMemory;
@ -380,7 +380,7 @@ bool VulkanDeviceAllocator::AllocateSlab(VkDeviceSize minBytes) {
minSlabSize_ <<= 1;
}
VkMemoryAllocateInfo alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
alloc.allocationSize = minSlabSize_;
alloc.memoryTypeIndex = memoryTypeIndex_;

View File

@ -95,42 +95,36 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra
void DrawEngineVulkan::InitDeviceObjects() {
// All resources we need for PSP drawing. Usually only bindings 0 and 2-4 are populated.
VkDescriptorSetLayoutBinding bindings[6];
VkDescriptorSetLayoutBinding bindings[6]{};
bindings[0].descriptorCount = 1;
bindings[0].pImmutableSamplers = nullptr;
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings[0].binding = DRAW_BINDING_TEXTURE;
bindings[1].descriptorCount = 1;
bindings[1].pImmutableSamplers = nullptr;
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings[1].binding = DRAW_BINDING_2ND_TEXTURE;
bindings[2].descriptorCount = 1;
bindings[2].pImmutableSamplers = nullptr;
bindings[2].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[2].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
bindings[2].binding = DRAW_BINDING_DYNUBO_BASE;
bindings[3].descriptorCount = 1;
bindings[3].pImmutableSamplers = nullptr;
bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[3].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[3].binding = DRAW_BINDING_DYNUBO_LIGHT;
bindings[4].descriptorCount = 1;
bindings[4].pImmutableSamplers = nullptr;
bindings[4].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
bindings[4].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[4].binding = DRAW_BINDING_DYNUBO_BONE;
// Used only for hardware tessellation.
bindings[5].descriptorCount = 1;
bindings[5].pImmutableSamplers = nullptr;
bindings[5].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
bindings[5].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
bindings[5].binding = DRAW_BINDING_TESS_STORAGE_BUF;
VkDevice device = vulkan_->GetDevice();
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
VkDescriptorSetLayoutCreateInfo dsl{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
dsl.bindingCount = ARRAY_SIZE(bindings);
dsl.pBindings = bindings;
VkResult res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_);
@ -145,7 +139,7 @@ void DrawEngineVulkan::InitDeviceObjects() {
frame_[i].pushIndex = new VulkanPushBuffer(vulkan_, 1 * 1024 * 1024);
}
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
pl.pPushConstantRanges = nullptr;
pl.pushConstantRangeCount = 0;
pl.setLayoutCount = 1;
@ -154,7 +148,7 @@ void DrawEngineVulkan::InitDeviceObjects() {
res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_);
assert(VK_SUCCESS == res);
VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
VkSamplerCreateInfo samp{ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
samp.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samp.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samp.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
@ -424,6 +418,36 @@ void DrawEngineVulkan::SetLineWidth(float lineWidth) {
pipelineManager_->SetLineWidth(lineWidth);
}
VkResult DrawEngineVulkan::RecreateDescriptorPool(FrameData &frame, int newSize) {
// Reallocate this desc pool larger, and "wipe" the cache. We might lose a tiny bit of descriptor set reuse but
// only for this frame.
if (frame.descPool) {
DEBUG_LOG(G3D, "Reallocating desc pool from %d to %d", frame.descPoolSize, newSize);
vulkan_->Delete().QueueDeleteDescriptorPool(frame.descPool);
frame.descSets.Clear();
frame.descCount = 0;
}
frame.descPoolSize = newSize;
VkDescriptorPoolSize dpTypes[3];
dpTypes[0].descriptorCount = frame.descPoolSize * 3;
dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
dpTypes[1].descriptorCount = frame.descPoolSize * 2; // Don't use these for tess anymore, need max two per set.
dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
dpTypes[2].descriptorCount = frame.descPoolSize;
dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
dp.flags = 0; // Don't want to mess around with individually freeing these.
// We zap the whole pool every few frames.
dp.maxSets = frame.descPoolSize;
dp.pPoolSizes = dpTypes;
dp.poolSizeCount = ARRAY_SIZE(dpTypes);
VkResult res = vkCreateDescriptorPool(vulkan_->GetDevice(), &dp, nullptr, &frame.descPool);
return res;
}
VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView, VkSampler sampler, VkBuffer base, VkBuffer light, VkBuffer bone, bool tess) {
DescriptorSetKey key;
key.imageView_ = imageView;
@ -445,47 +469,32 @@ VkDescriptorSet DrawEngineVulkan::GetOrCreateDescriptorSet(VkImageView imageView
}
if (!frame.descPool || frame.descPoolSize < frame.descCount + 1) {
// Reallocate this desc pool larger, and "wipe" the cache. We might lose a tiny bit of descriptor set reuse but
// only for this frame.
if (frame.descPool) {
DEBUG_LOG(G3D, "Reallocating desc pool from %d to %d", frame.descPoolSize, frame.descPoolSize * 2);
vulkan_->Delete().QueueDeleteDescriptorPool(frame.descPool);
frame.descSets.Clear();
frame.descCount = 0;
}
frame.descPoolSize *= 2;
VkDescriptorPoolSize dpTypes[3];
dpTypes[0].descriptorCount = frame.descPoolSize * 3;
dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
dpTypes[1].descriptorCount = frame.descPoolSize * 2; // Don't use these for tess anymore, need max two per set.
dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
dpTypes[2].descriptorCount = frame.descPoolSize;
dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
dp.pNext = nullptr;
dp.flags = 0; // Don't want to mess around with individually freeing these.
// We zap the whole pool every few frames.
dp.maxSets = frame.descPoolSize;
dp.pPoolSizes = dpTypes;
dp.poolSizeCount = ARRAY_SIZE(dpTypes);
VkResult res = vkCreateDescriptorPool(vulkan_->GetDevice(), &dp, nullptr, &frame.descPool);
VkResult res = RecreateDescriptorPool(frame, frame.descPoolSize * 2);
assert(res == VK_SUCCESS);
}
// Didn't find one in the frame descriptor set cache, let's make a new one.
// We wipe the cache on every frame.
VkDescriptorSet desc;
VkDescriptorSetAllocateInfo descAlloc = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
VkDescriptorSetAllocateInfo descAlloc{ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
descAlloc.pNext = nullptr;
descAlloc.pSetLayouts = &descriptorSetLayout_;
descAlloc.descriptorPool = frame.descPool;
descAlloc.descriptorSetCount = 1;
VkResult result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc);
if (result == VK_ERROR_FRAGMENTED_POOL || result < 0) {
// There seems to have been a spec revision. Here we should apparently recreate the descriptor pool,
// so let's do that. See https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkAllocateDescriptorSets.html
// Fragmentation shouldn't really happen though since we wipe the pool every frame..
VkResult res = RecreateDescriptorPool(frame, frame.descPoolSize);
_assert_msg_(G3D, res == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to recreate a descriptor pool. sz=%d res=%d", (int)frame.descSets.size(), (int)res);
descAlloc.descriptorPool = frame.descPool; // Need to update this pointer since we have allocated a new one.
result = vkAllocateDescriptorSets(vulkan_->GetDevice(), &descAlloc, &desc);
_assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space (frag?) and failed to allocate after recreating a descriptor pool. res=%d", (int)result);
}
// Even in release mode, this is bad.
_assert_msg_(G3D, result == VK_SUCCESS, "Ran out of descriptor space in pool. sz=%d res=%d", (int)frame.descSets.size(), (int)result);

View File

@ -195,6 +195,7 @@ private:
void DestroyDeviceObjects();
void DecodeVertsToPushBuffer(VulkanPushBuffer *push, uint32_t *bindOffset, VkBuffer *vkbuf);
VkResult RecreateDescriptorPool(FrameData &frame, int newSize);
void DoFlush();
void UpdateUBOs(FrameData *frame);

View File

@ -133,7 +133,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
}
blend0.colorWriteMask = key.colorWriteMask;
VkPipelineColorBlendStateCreateInfo cbs = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
VkPipelineColorBlendStateCreateInfo cbs{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
cbs.flags = 0;
cbs.pAttachments = &blend0;
cbs.attachmentCount = 1;
@ -143,7 +143,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
else
cbs.logicOp = VK_LOGIC_OP_COPY;
VkPipelineDepthStencilStateCreateInfo dss = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
VkPipelineDepthStencilStateCreateInfo dss{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
dss.depthBoundsTestEnable = false;
dss.stencilTestEnable = key.stencilTestEnable;
if (key.stencilTestEnable) {
@ -175,12 +175,12 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
}
VkPipelineDynamicStateCreateInfo ds = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
ds.flags = 0;
ds.pDynamicStates = dynamicStates;
ds.dynamicStateCount = numDyn;
VkPipelineRasterizationStateCreateInfo rs = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
rs.flags = 0;
rs.depthBiasEnable = false;
rs.cullMode = key.cullMode;
@ -190,7 +190,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
rs.polygonMode = VK_POLYGON_MODE_FILL;
rs.depthClampEnable = key.depthClampEnable;
VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
ms.pSampleMask = nullptr;
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
@ -215,7 +215,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
return nullptr;
}
VkPipelineInputAssemblyStateCreateInfo inputAssembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
inputAssembly.flags = 0;
inputAssembly.topology = (VkPrimitiveTopology)key.topology;
inputAssembly.primitiveRestartEnable = false;
@ -238,21 +238,21 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
ibd.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
ibd.stride = vertexStride;
VkPipelineVertexInputStateCreateInfo vis = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
vis.flags = 0;
vis.vertexBindingDescriptionCount = 1;
vis.pVertexBindingDescriptions = &ibd;
vis.vertexAttributeDescriptionCount = attributeCount;
vis.pVertexAttributeDescriptions = attrs;
VkPipelineViewportStateCreateInfo views = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
VkPipelineViewportStateCreateInfo views{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
views.flags = 0;
views.viewportCount = 1;
views.scissorCount = 1;
views.pViewports = nullptr; // dynamic
views.pScissors = nullptr; // dynamic
VkGraphicsPipelineCreateInfo pipe = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
VkGraphicsPipelineCreateInfo pipe{ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
pipe.flags = 0;
pipe.stageCount = 2;
pipe.pStages = ss;

View File

@ -123,8 +123,6 @@ static UI::Theme ui_theme;
#include "android/android-ndk-profiler/prof.h"
#endif
std::unique_ptr<ManagedTexture> uiTexture;
ScreenManager *screenManager;
std::string config_filename;
@ -622,16 +620,6 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
UIThemeInit();
uiTexture = CreateTextureFromFile(g_draw, "ui_atlas.zim", ImageFileType::ZIM);
if (!uiTexture) {
PanicAlert("Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.");
ELOG("Failed to load ui_atlas.zim");
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
UINT ExitCode = 0;
ExitProcess(ExitCode);
#endif
}
uiContext = new UIContext();
uiContext->theme = &ui_theme;
@ -714,8 +702,6 @@ void NativeShutdownGraphics() {
UIBackgroundShutdown();
uiTexture.reset(nullptr);
delete uiContext;
uiContext = nullptr;
@ -804,10 +790,6 @@ void RenderOverlays(UIContext *dc, void *userdata) {
void NativeRender(GraphicsContext *graphicsContext) {
g_GameManager.Update();
// If uitexture gets reloaded, make sure we use the latest one.
// Not sure this happens anymore now that we tear down all graphics on app switches...
uiContext->FrameSetup(uiTexture->GetTexture());
float xres = dp_xres;
float yres = dp_yres;

View File

@ -3,7 +3,6 @@
#include <memory>
#include "thin3d/thin3d.h"
#include "Core/Config.h"
enum ImageFileType {
PNG,

View File

@ -301,9 +301,9 @@ struct DescriptorSetKey {
class VKTexture : public Texture {
public:
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, const TextureDesc &desc, VulkanDeviceAllocator *alloc)
VKTexture(VulkanContext *vulkan, VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc)
: vulkan_(vulkan), mipLevels_(desc.mipLevels), format_(desc.format) {
bool result = Create(cmd, desc, alloc);
bool result = Create(cmd, pushBuffer, desc, alloc);
assert(result);
}
@ -314,9 +314,7 @@ public:
VkImageView GetImageView() { return vkTex_->GetImageView(); }
private:
void SetImageData(VkCommandBuffer cmd, int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data);
bool Create(VkCommandBuffer cmd, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
bool Create(VkCommandBuffer cmd, VulkanPushBuffer *pushBuffer, const TextureDesc &desc, VulkanDeviceAllocator *alloc);
void Destroy() {
if (vkTex_) {
@ -650,20 +648,45 @@ enum class TextureState {
PENDING_DESTRUCTION,
};
bool VKTexture::Create(VkCommandBuffer cmd, const TextureDesc &desc, VulkanDeviceAllocator *alloc) {
bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const TextureDesc &desc, VulkanDeviceAllocator *alloc) {
// Zero-sized textures not allowed.
assert(desc.width * desc.height * desc.depth > 0);
assert(push);
format_ = desc.format;
mipLevels_ = desc.mipLevels;
width_ = desc.width;
height_ = desc.height;
depth_ = desc.depth;
vkTex_ = new VulkanTexture(vulkan_, alloc);
VkFormat vulkanFormat = DataFormatToVulkan(format_);
int stride = desc.width * (int)DataFormatSizeInBytes(format_);
int bpp = GetBpp(vulkanFormat);
int bytesPerPixel = bpp / 8;
int usageBits = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
if (mipLevels_ > (int)desc.initData.size()) {
// Gonna have to generate some, which requires TRANSFER_SRC
usageBits |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
vkTex_->CreateDirect(cmd, width_, height_, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits);
if (desc.initData.size()) {
for (int i = 0; i < (int)desc.initData.size(); i++) {
this->SetImageData(cmd, 0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]);
int w = width_;
int h = height_;
int i;
for (i = 0; i < (int)desc.initData.size(); i++) {
uint32_t offset;
VkBuffer buf;
size_t size = w * h * bytesPerPixel;
offset = push->PushAligned((const void *)desc.initData[i], size, 16, &buf);
vkTex_->UploadMip(cmd, i, w, h, buf, offset, w);
w = (w + 1) / 2;
h = (h + 1) / 2;
}
// Generate the rest of the mips automatically.
for (; i < mipLevels_; i++) {
vkTex_->GenerateMip(cmd, i);
}
}
vkTex_->EndCreate(cmd, false);
return true;
}
@ -703,13 +726,13 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
dpTypes[1].descriptorCount = 200;
dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
dp.flags = 0; // Don't want to mess around with individually freeing these, let's go dynamic each frame.
dp.maxSets = 200; // 200 textures per frame should be enough for the UI...
dp.pPoolSizes = dpTypes;
dp.poolSizeCount = ARRAY_SIZE(dpTypes);
VkCommandPoolCreateInfo p = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
VkCommandPoolCreateInfo p{ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
p.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
p.queueFamilyIndex = vulkan->GetGraphicsQueueFamilyIndex();
@ -994,23 +1017,7 @@ InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
}
Texture *VKContext::CreateTexture(const TextureDesc &desc) {
return new VKTexture(vulkan_, renderManager_.GetInitCmd(), desc, allocator_);
}
void VKTexture::SetImageData(VkCommandBuffer cmd, int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {
VkFormat vulkanFormat = DataFormatToVulkan(format_);
if (stride == 0) {
stride = width * (int)DataFormatSizeInBytes(format_);
}
int bpp = GetBpp(vulkanFormat);
int bytesPerPixel = bpp / 8;
vkTex_->Create(width, height, vulkanFormat);
int rowPitch;
uint8_t *dstData = vkTex_->Lock(0, &rowPitch);
for (int y = 0; y < height; y++) {
memcpy(dstData + rowPitch * y, data + stride * y, width * bytesPerPixel);
}
vkTex_->Unlock(cmd);
return new VKTexture(vulkan_, renderManager_.GetInitCmd(), push_, desc, allocator_);
}
static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {

View File

@ -6,6 +6,8 @@
#include "gfx_es2/draw_buffer.h"
#include "gfx_es2/draw_text.h"
#include "Common/Log.h"
UIContext::UIContext() {
fontStyle_ = new UI::FontStyle();
bounds_ = Bounds(0, 0, dp_xres, dp_yres);
@ -28,13 +30,19 @@ void UIContext::Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pi
textDrawer_ = TextDrawer::Create(thin3d); // May return nullptr if no implementation is available for this platform.
}
void UIContext::FrameSetup(Draw::Texture *uiTexture) {
uitexture_ = uiTexture;
void UIContext::BeginFrame() {
if (!uitexture_) {
uitexture_ = CreateTextureFromFile(draw_, "ui_atlas.zim", ImageFileType::ZIM);
if (!uitexture_) {
PanicAlert("Failed to load ui_atlas.zim.\n\nPlace it in the directory \"assets\" under your PPSSPP directory.");
FLOG("Failed to load ui_atlas.zim");
}
}
}
void UIContext::Begin() {
draw_->BindSamplerStates(0, 1, &sampler_);
draw_->BindTexture(0, uitexture_);
draw_->BindTexture(0, uitexture_->GetTexture());
ActivateTopScissor();
UIBegin(ui_pipeline_);
}
@ -45,7 +53,7 @@ void UIContext::BeginNoTex() {
}
void UIContext::RebindTexture() const {
draw_->BindTexture(0, uitexture_);
draw_->BindTexture(0, uitexture_->GetTexture());
}
void UIContext::Flush() {

View File

@ -6,6 +6,7 @@
#include "math/geom2d.h"
#include "math/lin/vec3.h"
#include "gfx/texture_atlas.h"
#include "UI/TextureUtil.h"
// Everything you need to draw a UI collected into a single unit that can be passed around.
// Everything forward declared so this header is safe everywhere.
@ -46,7 +47,7 @@ public:
void Init(Draw::DrawContext *thin3d, Draw::Pipeline *uipipe, Draw::Pipeline *uipipenotex, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop);
void FrameSetup(Draw::Texture *uiTexture);
void BeginFrame();
void Begin();
void BeginNoTex();
@ -102,7 +103,7 @@ private:
Draw::SamplerState *sampler_;
Draw::Pipeline *ui_pipeline_ = nullptr;
Draw::Pipeline *ui_pipeline_notex_ = nullptr;
Draw::Texture *uitexture_ = nullptr;
std::unique_ptr<ManagedTexture> uitexture_;
DrawBuffer *uidrawbuffer_ = nullptr;
DrawBuffer *uidrawbufferTop_ = nullptr;

View File

@ -68,6 +68,7 @@ void UIScreen::preRender() {
return;
}
draw->BeginFrame();
screenManager()->getUIContext()->BeginFrame();
// Bind and clear the back buffer
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 });