mirror of
https://github.com/libretro/ppsspp.git
synced 2025-03-04 14:37:17 +00:00
Merge pull request #10645 from hrydgard/vulkan-cleanups
Vulkan cleanups: Remove old texture upload method, etc.
This commit is contained in:
commit
373e53fa66
@ -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();
|
||||
|
@ -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, ©_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_);
|
||||
|
@ -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_;
|
||||
};
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <memory>
|
||||
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
enum ImageFileType {
|
||||
PNG,
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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 });
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user