diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index e11012bc8f..b8e484321f 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -242,6 +242,7 @@
+
@@ -313,6 +314,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index e5bc85c777..351cfd7608 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -67,6 +67,9 @@
Vulkan
+
+ Vulkan
+
@@ -121,6 +124,9 @@
Vulkan
+
+ Vulkan
+
diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp
index ac601ccd30..048f8f66ed 100644
--- a/Common/Vulkan/VulkanContext.cpp
+++ b/Common/Vulkan/VulkanContext.cpp
@@ -42,6 +42,8 @@ static const char *validationLayers[] = {
*/
};
+static VkBool32 CheckLayers(const std::vector &layer_props, const std::vector &layer_names);
+
VulkanContext::VulkanContext(const char *app_name, int app_ver, uint32_t flags)
: device_(nullptr),
gfx_queue_(VK_NULL_HANDLE),
@@ -581,7 +583,7 @@ VkResult VulkanContext::InitDeviceLayerProperties() {
* Return 1 (true) if all layer names specified in check_names
* can be found in given layer properties.
*/
-VkBool32 CheckLayers(const std::vector &layer_props, const std::vector &layer_names) {
+static VkBool32 CheckLayers(const std::vector &layer_props, const std::vector &layer_names) {
uint32_t check_count = (uint32_t)layer_names.size();
uint32_t layer_count = (uint32_t)layer_props.size();
for (uint32_t i = 0; i < check_count; i++) {
@@ -1188,361 +1190,6 @@ void VulkanContext::InitCommandPool() {
assert(res == VK_SUCCESS);
}
-VkResult VulkanTexture::Create(int w, int h, VkFormat format) {
- tex_width = w;
- tex_height = h;
- format_ = format;
-
- VkFormatProperties formatProps;
- vkGetPhysicalDeviceFormatProperties(vulkan_->GetPhysicalDevice(), format, &formatProps);
-
- // See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
- // Linear tiling is usually only supported for 2D non-array textures.
- // needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
- // Always stage.
- needStaging = true;
-
- return VK_SUCCESS;
-}
-
-void VulkanTexture::CreateMappableImage() {
- // If we already have a mappableImage, forget it.
- if (mappableImage) {
- vulkan_->Delete().QueueDeleteImage(mappableImage);
- mappableImage = VK_NULL_HANDLE;
- }
- if (mappableMemory) {
- vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
- mappableMemory = VK_NULL_HANDLE;
- }
-
- bool U_ASSERT_ONLY pass;
-
- VkImageCreateInfo image_create_info = {};
- image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- image_create_info.pNext = NULL;
- 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 = needStaging ? 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 = {};
- mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- mem_alloc.pNext = NULL;
- 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.
- pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_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() {
- vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
-
- VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
-
- // if we already have an image, queue it for destruction and forget it.
- Wipe();
- if (!needStaging) {
- // If we can use the linear tiled image as a texture, just do it
- image = mappableImage;
- mem = mappableMemory;
- TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
- // Make sure we don't accidentally delete the main image.
- mappableImage = VK_NULL_HANDLE;
- mappableMemory = VK_NULL_HANDLE;
- } else {
- VkImageCreateInfo image_create_info = {};
- image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- image_create_info.pNext = NULL;
- 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 = {};
- 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 from the mappable image, set its layout to SOURCE_OPTIMAL
- TransitionImageLayout(cmd, mappableImage,
- VK_IMAGE_ASPECT_COLOR_BIT,
- VK_IMAGE_LAYOUT_PREINITIALIZED,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
-
- TransitionImageLayout(cmd, image,
- VK_IMAGE_ASPECT_COLOR_BIT,
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
-
- 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
- TransitionImageLayout(cmd, image,
- VK_IMAGE_ASPECT_COLOR_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-
- // Then drop the temporary mappable image - although should not be necessary...
- vulkan_->Delete().QueueDeleteImage(mappableImage);
- vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
-
- mappableImage = VK_NULL_HANDLE;
- mappableMemory = VK_NULL_HANDLE;
- }
-
- 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 = 1;
- view_info.subresourceRange.baseArrayLayer = 0;
- view_info.subresourceRange.layerCount = 1;
- view_info.image = image;
- VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
- 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;
- format_ = format;
-
- 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 = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
- 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, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength) {
- VkBufferImageCopy copy_region = {};
- 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;
-
- VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
- vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_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);
- }
- if (image) {
- vulkan_->Delete().QueueDeleteImage(image);
- if (mappableImage == image) {
- mappableImage = VK_NULL_HANDLE;
- }
- }
- if (mem) {
- vulkan_->Delete().QueueDeleteDeviceMemory(mem);
- if (mappableMemory == mem) {
- mappableMemory = VK_NULL_HANDLE;
- }
- }
-
- view = VK_NULL_HANDLE;
- image = VK_NULL_HANDLE;
- mem = VK_NULL_HANDLE;
-}
-
VkFence VulkanContext::CreateFence(bool presignalled) {
VkFence fence;
VkFenceCreateInfo fenceInfo;
@@ -1889,22 +1536,3 @@ const char *VulkanResultToString(VkResult res) {
void VulkanAssertImpl(VkResult check, const char *function, const char *file, int line) {
const char *error = "(none)";
}
-
-void VulkanFramebuffer::Create(VulkanContext *vulkan, int w, int h, VkFormat format) {
-
-}
-// void TransitionToImage()
-
-void VulkanFramebuffer::BeginPass(VkCommandBuffer cmd) {
-
-}
-void VulkanFramebuffer::EndPass(VkCommandBuffer cmd) {
-
-}
-void VulkanFramebuffer::TransitionToTexture(VkCommandBuffer cmd) {
-
-}
-
-VkImageView VulkanFramebuffer::GetColorImageView() {
- return VK_NULL_HANDLE;
-}
diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h
index 3a4982175b..e6eda63762 100644
--- a/Common/Vulkan/VulkanContext.h
+++ b/Common/Vulkan/VulkanContext.h
@@ -340,71 +340,6 @@ private:
std::vector cmdQueue_;
};
-// Wrapper around what you need to use a texture.
-// Not very optimal - if you have many small textures you should use other strategies.
-// Only supports simple 2D textures for now. Mipmap support will be added later.
-class VulkanTexture {
-public:
- VulkanTexture(VulkanContext *vulkan)
- : 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), needStaging(false) {
- 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();
-
- // Fast uploads from buffer. Mipmaps supported.
- void CreateDirect(int w, int h, int numMips, VkFormat format);
- void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength); // rowLength is in pixels
- void EndCreate();
- int GetNumMips() const { return numMips_; }
- 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, numMips_;
- VkFormat format_;
- VkImage mappableImage;
- VkDeviceMemory mappableMemory;
- VkMemoryRequirements mem_reqs;
- bool needStaging;
-};
-
-// Placeholder
-
-class VulkanFramebuffer {
-public:
- void Create(VulkanContext *vulkan, int w, int h, VkFormat format);
-
- void BeginPass(VkCommandBuffer cmd);
- void EndPass(VkCommandBuffer cmd);
- void TransitionToTexture(VkCommandBuffer cmd);
-
- VkImageView GetColorImageView();
-
-private:
- VkImage image_;
- VkFramebuffer framebuffer_;
-};
-
// Use these to push vertex, index and uniform data. Generally you'll have two of these
// and alternate on each frame.
// TODO: Make it possible to suballocate pushbuffers from a large DeviceMemory block.
@@ -505,16 +440,8 @@ private:
uint8_t *writePtr_;
};
-
-VkBool32 CheckLayers(const std::vector &layer_props, const std::vector &layer_names);
-
+// Stand-alone utility functions
void VulkanBeginCommandBuffer(VkCommandBuffer cmd);
-
-void init_glslang();
-void finalize_glslang();
-
-bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector &spirv, std::string *errorMessage = nullptr);
-
void TransitionImageLayout(
VkCommandBuffer cmd,
VkImage image,
@@ -522,5 +449,10 @@ void TransitionImageLayout(
VkImageLayout old_image_layout,
VkImageLayout new_image_layout);
+// GLSL compiler
+void init_glslang();
+void finalize_glslang();
+bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector &spirv, std::string *errorMessage = nullptr);
+
#endif // UTIL_INIT
diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp
new file mode 100644
index 0000000000..c2cd59e6c5
--- /dev/null
+++ b/Common/Vulkan/VulkanImage.cpp
@@ -0,0 +1,356 @@
+#include "Common/Vulkan/VulkanImage.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);
+
+ // See if we can use a linear tiled image for a texture, if not, we will need a staging image for the texture data.
+ // Linear tiling is usually only supported for 2D non-array textures.
+ // needStaging = (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) ? true : false;
+ // Always stage.
+ needStaging = true;
+
+ return VK_SUCCESS;
+}
+
+void VulkanTexture::CreateMappableImage() {
+ // If we already have a mappableImage, forget it.
+ if (mappableImage) {
+ vulkan_->Delete().QueueDeleteImage(mappableImage);
+ mappableImage = VK_NULL_HANDLE;
+ }
+ if (mappableMemory) {
+ vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
+ mappableMemory = VK_NULL_HANDLE;
+ }
+
+ bool U_ASSERT_ONLY pass;
+
+ VkImageCreateInfo image_create_info = {};
+ image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ image_create_info.pNext = NULL;
+ 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 = needStaging ? 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 = {};
+ mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ mem_alloc.pNext = NULL;
+ 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.
+ pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_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() {
+ vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
+
+ VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
+
+ // if we already have an image, queue it for destruction and forget it.
+ Wipe();
+ if (!needStaging) {
+ // If we can use the linear tiled image as a texture, just do it
+ image = mappableImage;
+ mem = mappableMemory;
+ TransitionImageLayout(cmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ // Make sure we don't accidentally delete the main image.
+ mappableImage = VK_NULL_HANDLE;
+ mappableMemory = VK_NULL_HANDLE;
+ } else {
+ VkImageCreateInfo image_create_info = {};
+ image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ image_create_info.pNext = NULL;
+ 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 = {};
+ 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 from the mappable image, set its layout to SOURCE_OPTIMAL
+ TransitionImageLayout(cmd, mappableImage,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ VK_IMAGE_LAYOUT_PREINITIALIZED,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
+
+ TransitionImageLayout(cmd, image,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
+
+ 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
+ TransitionImageLayout(cmd, image,
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+
+ // Then drop the temporary mappable image - although should not be necessary...
+ vulkan_->Delete().QueueDeleteImage(mappableImage);
+ vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory);
+
+ mappableImage = VK_NULL_HANDLE;
+ mappableMemory = VK_NULL_HANDLE;
+ }
+
+ 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 = 1;
+ view_info.subresourceRange.baseArrayLayer = 0;
+ view_info.subresourceRange.layerCount = 1;
+ view_info.image = image;
+ VkResult res = vkCreateImageView(vulkan_->GetDevice(), &view_info, NULL, &view);
+ 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, VkImageUsageFlags usage) {
+ Wipe();
+
+ VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
+
+ tex_width = w;
+ tex_height = h;
+ numMips_ = numMips;
+ format_ = format;
+
+ 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 = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
+ 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, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength) {
+ VkBufferImageCopy copy_region = {};
+ 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;
+
+ VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
+ vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_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);
+ }
+ if (image) {
+ vulkan_->Delete().QueueDeleteImage(image);
+ if (mappableImage == image) {
+ mappableImage = VK_NULL_HANDLE;
+ }
+ }
+ if (mem) {
+ vulkan_->Delete().QueueDeleteDeviceMemory(mem);
+ if (mappableMemory == mem) {
+ mappableMemory = VK_NULL_HANDLE;
+ }
+ }
+
+ view = VK_NULL_HANDLE;
+ image = VK_NULL_HANDLE;
+ mem = VK_NULL_HANDLE;
+}
diff --git a/Common/Vulkan/VulkanImage.h b/Common/Vulkan/VulkanImage.h
new file mode 100644
index 0000000000..482f52f98c
--- /dev/null
+++ b/Common/Vulkan/VulkanImage.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "Common/Vulkan/VulkanContext.h"
+
+// Wrapper around what you need to use a texture.
+// Not very optimal - if you have many small textures you should use other strategies.
+class VulkanTexture {
+public:
+ VulkanTexture(VulkanContext *vulkan)
+ : 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), needStaging(false) {
+ 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();
+
+ // Fast uploads from buffer. Mipmaps supported. Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
+ void CreateDirect(int w, int h, int numMips, VkFormat format, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
+ void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, size_t offset, size_t rowLength); // rowLength is in pixels
+ void EndCreate();
+ int GetNumMips() const { return numMips_; }
+ 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, numMips_;
+ VkFormat format_;
+ VkImage mappableImage;
+ VkDeviceMemory mappableMemory;
+ VkMemoryRequirements mem_reqs;
+ bool needStaging;
+};
diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h
index f9ebd1e3ad..4456e3461c 100644
--- a/GPU/Common/FramebufferCommon.h
+++ b/GPU/Common/FramebufferCommon.h
@@ -51,7 +51,7 @@ namespace DX9 {
struct FBO_DX9;
}
-class VulkanFramebuffer;
+class VulkanFBO;
struct VirtualFramebuffer {
int last_frame_used;
@@ -87,12 +87,13 @@ struct VirtualFramebuffer {
int lastFrameNewSize;
GEBufferFormat format; // virtual, right now they are all RGBA8888
+
// TODO: Handle fbo and colorDepth better.
u8 colorDepth;
union {
FBO *fbo;
DX9::FBO_DX9 *fbo_dx9;
- VulkanFramebuffer *fbo_vk;
+ VulkanFBO *fbo_vk;
};
u16 drawnWidth;
diff --git a/GPU/Common/VertexDecoderCommon.h b/GPU/Common/VertexDecoderCommon.h
index 69dbe4da53..14ed122bae 100644
--- a/GPU/Common/VertexDecoderCommon.h
+++ b/GPU/Common/VertexDecoderCommon.h
@@ -106,8 +106,7 @@ inline int RoundUp4(int x) {
}
// Reads decoded vertex formats in a convenient way. For software transform and debugging.
-class VertexReader
-{
+class VertexReader {
public:
VertexReader(u8 *base, const DecVtxFormat &decFmt, int vtype) : base_(base), data_(base), decFmt_(decFmt), vtype_(vtype) {}
diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj
index 1f21022378..cfb441cc35 100644
--- a/GPU/GPU.vcxproj
+++ b/GPU/GPU.vcxproj
@@ -345,6 +345,7 @@
+
@@ -354,4 +355,4 @@
-
+
\ No newline at end of file
diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters
index 21183c6e72..7558d33b67 100644
--- a/GPU/GPU.vcxproj.filters
+++ b/GPU/GPU.vcxproj.filters
@@ -458,5 +458,6 @@
Vulkan
+
\ No newline at end of file
diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp
index 14f17ba6a8..74c1c94ec0 100644
--- a/GPU/Vulkan/FramebufferVulkan.cpp
+++ b/GPU/Vulkan/FramebufferVulkan.cpp
@@ -41,10 +41,12 @@
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
+#include "Common/Vulkan/VulkanImage.h"
#include "GPU/Vulkan/FramebufferVulkan.h"
#include "GPU/Vulkan/DrawEngineVulkan.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
#include "GPU/Vulkan/ShaderManagerVulkan.h"
+#include "GPU/Vulkan/VulkanUtil.h"
#include "UI/OnScreenDisplay.h"
@@ -599,7 +601,7 @@ void FramebufferManagerVulkan::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w,
return;
}
- vfb->fbo_vk = new VulkanFramebuffer();
+ vfb->fbo_vk = new VulkanFBO();
// bo_create(vfb->renderWidth, vfb->renderHeight, 1, true, (FBOColorDepth)vfb->colorDepth);
if (old.fbo_vk) {
INFO_LOG(SCEGE, "Resizing FBO for %08x : %i x %i x %i", vfb->fb_address, w, h, vfb->format);
@@ -777,7 +779,7 @@ void FramebufferManagerVulkan::BlitFramebufferDepth(VirtualFramebuffer *src, Vir
}*/
}
-VulkanFramebuffer *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth) {
+VulkanFBO *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth) {
u64 key = ((u64)depth << 32) | ((u32)w << 16) | h;
auto it = tempFBOs_.find(key);
if (it != tempFBOs_.end()) {
@@ -787,7 +789,7 @@ VulkanFramebuffer *FramebufferManagerVulkan::GetTempFBO(u16 w, u16 h, VulkanFBOC
textureCache_->ForgetLastTexture();
// FBO *fbo_vk = fbo_create(w, h, 1, false, depth);
- VulkanFramebuffer *fbo_vk = new VulkanFramebuffer();
+ VulkanFBO *fbo_vk = new VulkanFBO();
if (!fbo_vk)
return nullptr;
// fbo_bind_as_render_target(fbo_vk);
diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h
index 510714458e..0b93fabef0 100644
--- a/GPU/Vulkan/FramebufferVulkan.h
+++ b/GPU/Vulkan/FramebufferVulkan.h
@@ -36,13 +36,13 @@ class DrawEngineVulkan;
class VulkanContext;
class ShaderManagerVulkan;
class VulkanTexture;
-class VulkanFramebuffer;
struct PostShaderUniforms {
float texelDelta[2]; float pad[2];
float pixelDelta[2]; float pad0[2];
float time[4];
};
+
// Simple struct for asynchronous PBO readbacks
// TODO: Probably will need a complete redesign.
struct AsyncPBOVulkan {
@@ -122,7 +122,7 @@ public:
virtual void RebindFramebuffer() override;
- VulkanFramebuffer *GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth = VK_FBO_8888);
+ VulkanFBO *GetTempFBO(u16 w, u16 h, VulkanFBOColorDepth depth = VK_FBO_8888);
// Cardboard Settings Calculator
struct CardboardSettings * GetCardboardSettings(struct CardboardSettings * cardboardSettings);
@@ -182,7 +182,7 @@ private:
bool resized_;
struct TempFBO {
- VulkanFramebuffer *fbo_vk;
+ VulkanFBO *fbo_vk;
int last_frame_used;
};
diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h
index bcdc0eaa64..e6672b4fcc 100644
--- a/GPU/Vulkan/ShaderManagerVulkan.h
+++ b/GPU/Vulkan/ShaderManagerVulkan.h
@@ -1,5 +1,4 @@
-#pragma once
-// Copyright (c) 2012- PPSSPP Project.
+// Copyright (c) 2016- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp
index 0cef7827de..655a12c05d 100644
--- a/GPU/Vulkan/TextureCacheVulkan.cpp
+++ b/GPU/Vulkan/TextureCacheVulkan.cpp
@@ -22,13 +22,16 @@
#include "i18n/i18n.h"
#include "math/math_util.h"
#include "profiler/profiler.h"
-#include "Common/Vulkan/VulkanContext.h"
#include "Common/ColorConv.h"
#include "Core/Config.h"
#include "Core/Host.h"
#include "Core/MemMap.h"
#include "Core/Reporting.h"
#include "Core/System.h"
+
+#include "Common/Vulkan/VulkanContext.h"
+#include "Common/Vulkan/VulkanImage.h"
+
#include "GPU/ge_constants.h"
#include "GPU/GPUState.h"
#include "GPU/Vulkan/TextureCacheVulkan.h"
@@ -81,6 +84,10 @@ SamplerCache::~SamplerCache() {
}
}
+CachedTextureVulkan::~CachedTextureVulkan() {
+ delete texture_;
+}
+
VkSampler SamplerCache::GetOrCreateSampler(const SamplerCacheKey &key) {
auto iter = cache_.find(key);
if (iter != cache_.end()) {
@@ -905,9 +912,9 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VkCommandBuffer cmd, TexCacheEn
}
if (depal) {
// VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
- VulkanFramebuffer *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
+ VulkanFBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, VK_FBO_8888);
- depalFBO->BeginPass(cmd);
+ //depalFBO->BeginPass(cmd);
struct Pos {
Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
@@ -1018,9 +1025,9 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VkCommandBuffer cmd, TexCacheEn
glDisableVertexAttribArray(depal->a_position);
glDisableVertexAttribArray(depal->a_texcoord0);
*/
- depalFBO->EndPass(cmd);
- depalFBO->TransitionToTexture(cmd);
- imageView = depalFBO->GetColorImageView();
+ //depalFBO->EndPass(cmd);
+ //depalFBO->TransitionToTexture(cmd);
+ //imageView = depalFBO->GetColorImageView();
}
/*
diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h
index 0d732f480d..0d256ba3a9 100644
--- a/GPU/Vulkan/TextureCacheVulkan.h
+++ b/GPU/Vulkan/TextureCacheVulkan.h
@@ -33,7 +33,7 @@ class ShaderManagerVulkan;
class DrawEngineVulkan;
class VulkanContext;
-class VulkanImage;
+class VulkanTexture;
struct SamplerCacheKey {
SamplerCacheKey() : fullKey(0) {}
@@ -61,9 +61,8 @@ class CachedTextureVulkan {
public:
CachedTextureVulkan() : texture_(nullptr) {
}
- ~CachedTextureVulkan() {
- delete texture_;
- }
+ ~CachedTextureVulkan();
+
// TODO: Switch away from VulkanImage to some kind of smart suballocating texture pool.
VulkanTexture *texture_;
};
diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp
new file mode 100644
index 0000000000..a8a39ccdd9
--- /dev/null
+++ b/GPU/Vulkan/VulkanUtil.cpp
@@ -0,0 +1,45 @@
+// Copyright (c) 2016- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "GPU/Vulkan/VulkanUtil.h"
+
+VulkanFBO::VulkanFBO() : color_(nullptr), depthStencil_(nullptr) {}
+
+VulkanFBO::~VulkanFBO() {
+ delete color_;
+ delete depthStencil_;
+}
+
+void VulkanFBO::Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat color_Format) {
+ color_ = new VulkanTexture(vulkan);
+ VkImageCreateFlags flags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ color_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, flags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
+ depthStencil_->CreateDirect(width, height, 1, VK_FORMAT_D24_UNORM_S8_UINT, flags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+
+ VkImageView views[2] = { color_->GetImageView(), depthStencil_->GetImageView() };
+
+ VkFramebufferCreateInfo fb = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
+ fb.pAttachments = views;
+ fb.attachmentCount = 2;
+ fb.flags = 0;
+ fb.renderPass = rp_compatible;
+ fb.width = width;
+ fb.height = height;
+ fb.layers = 1;
+
+ vkCreateFramebuffer(vulkan->GetDevice(), &fb, nullptr, &framebuffer_);
+}
diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h
index fe41a2b8e0..61a4160359 100644
--- a/GPU/Vulkan/VulkanUtil.h
+++ b/GPU/Vulkan/VulkanUtil.h
@@ -1,4 +1,48 @@
+// Copyright (c) 2016- PPSSPP Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0 or later versions.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
#pragma once
#include "Common/Vulkan/VulkanLoader.h"
+#include "Common/Vulkan/VulkanImage.h"
+// Vulkan doesn't really have the concept of an FBO that owns the images,
+// but it does have the concept of a framebuffer as a set of attachments.
+// VulkanFBO is an approximation of the FBO concept the other backends use
+// to make things as similar as possible without being suboptimal.
+//
+class VulkanFBO {
+public:
+ VulkanFBO();
+ ~VulkanFBO();
+
+ // Depth-format is chosen automatically depending on hardware support.
+ // Color format will be 32-bit RGBA.
+ void Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat colorFormat);
+
+ VulkanTexture *GetColor() { return color_; }
+ VulkanTexture *GetDepthStencil() { return depthStencil_; }
+
+ VkFramebuffer GetFramebuffer() { return framebuffer_; }
+
+private:
+ VulkanTexture *color_;
+ VulkanTexture *depthStencil_;
+
+ // This point specifically to color and depth.
+ VkFramebuffer framebuffer_;
+};
\ No newline at end of file
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index c752482e2d..45d2f9e0f7 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -127,6 +127,7 @@ EGL_FILES := \
VULKAN_FILES := \
$(SRC)/Common/Vulkan/VulkanLoader.cpp \
$(SRC)/Common/Vulkan/VulkanContext.cpp \
+ $(SRC)/Common/Vulkan/VulkanImage.cpp \
$(SRC)/GPU/Vulkan/FragmentShaderGeneratorVulkan.cpp \
$(SRC)/GPU/Vulkan/DrawEngineVulkan.cpp \
$(SRC)/GPU/Vulkan/FramebufferVulkan.cpp \
@@ -137,7 +138,8 @@ VULKAN_FILES := \
$(SRC)/GPU/Vulkan/TextureCacheVulkan.cpp \
$(SRC)/GPU/Vulkan/TextureScalerVulkan.cpp \
$(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \
- $(SRC)/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp
+ $(SRC)/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp \
+ $(SRC)/GPU/Vulkan/VulkanUtil.cpp
#endif
EXEC_AND_LIB_FILES := \
diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp
index f547e58cb0..6a9585c538 100644
--- a/ext/native/thin3d/thin3d_vulkan.cpp
+++ b/ext/native/thin3d/thin3d_vulkan.cpp
@@ -30,7 +30,9 @@
#include "math/lin/matrix4x4.h"
#include "math/dataconv.h"
#include "thin3d/thin3d.h"
+
#include "Common/Vulkan/VulkanContext.h"
+#include "Common/Vulkan/VulkanImage.h"
// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point.
// binding 0 - uniform data