// Copyright (c) 2015- 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/. #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #undef min #undef max #endif #include #include #include #ifdef USE_CRT_DBG #undef new #endif #include "ext/glslang/SPIRV/GlslangToSpv.h" #include "ext/glslang/SPIRV/disassemble.h" #ifdef USE_CRT_DBG #define new DBG_NEW #endif #include "thin3d/vulkan_utils.h" void VulkanDeviceMemoryManager::Init(VkPhysicalDevice gpu) { // Get Memory information and properties vkGetPhysicalDeviceMemoryProperties(gpu, &memory_properties_); } VkResult VulkanDeviceMemoryManager::memory_type_from_properties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex) { // Search memtypes to find first index with those properties for (uint32_t i = 0; i < 32; i++) { if ((typeBits & 1) == 1) { // Type is available, does it match user properties? if ((memory_properties_.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) { *typeIndex = i; return VK_SUCCESS; } } typeBits >>= 1; } // No memory types matched, return failure return VK_ERROR_FORMAT_NOT_SUPPORTED; } void VulkanImage::Create2D(VkDevice device, VulkanDeviceMemoryManager *memMan, VkFormat format, VkFlags required_props, VkImageUsageFlags usage, int width, int height) { width_ = width; height_ = height; VkImageCreateInfo i; i.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; i.pNext = NULL; i.imageType = VK_IMAGE_TYPE_2D; i.format = format; i.extent = { (uint32_t)width, (uint32_t)height, 1 }; i.mipLevels = 1; i.arrayLayers = 1; i.samples = VK_SAMPLE_COUNT_1_BIT; i.tiling = VK_IMAGE_TILING_LINEAR; i.usage = usage; i.flags = 0; i.sharingMode = VK_SHARING_MODE_EXCLUSIVE; i.queueFamilyIndexCount = 0; i.pQueueFamilyIndices = nullptr; i.initialLayout = VK_IMAGE_LAYOUT_GENERAL; VkMemoryRequirements mem_reqs; VkResult err = vkCreateImage(device, &i, nullptr, &image_); assert(!err); vkGetImageMemoryRequirements(device, image_, &mem_reqs); mem_alloc_.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; mem_alloc_.pNext = NULL; mem_alloc_.allocationSize = mem_reqs.size; mem_alloc_.memoryTypeIndex = 0; err = memMan->memory_type_from_properties(mem_reqs.memoryTypeBits, required_props, &mem_alloc_.memoryTypeIndex); assert(!err); err = vkAllocateMemory(device, &mem_alloc_, nullptr, &memory_); assert(!err); err = vkBindImageMemory(device, image_, memory_, 0); // at offset 0. } void VulkanImage::SetImageData2D(VkDevice device, const uint8_t *data, int width, int height, int pitch) { VkImageSubresource subres; subres.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; subres.mipLevel = 0; subres.arrayLayer = 0; VkSubresourceLayout layout; void *destData; vkGetImageSubresourceLayout(device, image_, &subres, &layout); VkResult err = vkMapMemory(device, memory_, 0, mem_alloc_.allocationSize, 0, &destData); assert(!err); uint8_t *writePtr = (uint8_t *)destData + layout.offset; int bpp = 4; // TODO for (int y = 0; y < height; y++) { memcpy(writePtr + y * layout.rowPitch, data + y * pitch, bpp * width); } vkUnmapMemory(device, memory_); } void VulkanImage::ChangeLayout(VkCommandBuffer cmd, VkImageAspectFlags aspectMask, VkImageLayout old_image_layout, VkImageLayout new_image_layout) { VkImageMemoryBarrier image_memory_barrier; image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; image_memory_barrier.pNext = NULL; image_memory_barrier.dstAccessMask = 0; image_memory_barrier.srcAccessMask = 0; image_memory_barrier.oldLayout = old_image_layout; image_memory_barrier.newLayout = new_image_layout; image_memory_barrier.image = image_; image_memory_barrier.subresourceRange.aspectMask = aspectMask; image_memory_barrier.subresourceRange.layerCount = 1; image_memory_barrier.subresourceRange.baseArrayLayer = 0; image_memory_barrier.subresourceRange.baseMipLevel = 0; image_memory_barrier.subresourceRange.levelCount = 1; if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { /* Make sure anything that was copying from this image has completed */ image_memory_barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; } if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { /* Make sure any Copy or CPU writes to image are flushed */ image_memory_barrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT; } VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; vkCmdPipelineBarrier(cmd, src_stages, dest_stages, false, 0, nullptr, 0, nullptr, 1, &image_memory_barrier); } bool CreateShaderModule(VkDevice device, const std::vector &spirv, VkShaderModule *shaderModule) { VkShaderModuleCreateInfo sm; sm.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; sm.pNext = nullptr; sm.pCode = spirv.data(); sm.codeSize = spirv.size() * sizeof(uint32_t); sm.flags = 0; VkResult result = vkCreateShaderModule(device, &sm, NULL, shaderModule); if (result != VK_SUCCESS) { return false; } else { return true; } }