555 lines
20 KiB
C++
555 lines
20 KiB
C++
#include "RenderAPI.h"
|
|
#include "PlatformBase.h"
|
|
|
|
#if SUPPORT_VULKAN
|
|
|
|
#include <string>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <math.h>
|
|
#include <algorithm>
|
|
|
|
// This plugin does not link to the Vulkan loader, easier to support multiple APIs and systems that don't have Vulkan support
|
|
#define VK_NO_PROTOTYPES
|
|
#include "Unity/IUnityGraphicsVulkan.h"
|
|
|
|
#define UNITY_USED_VULKAN_API_FUNCTIONS(apply) \
|
|
apply(vkCreateInstance); \
|
|
apply(vkCmdBeginRenderPass); \
|
|
apply(vkCreateBuffer); \
|
|
apply(vkGetPhysicalDeviceMemoryProperties); \
|
|
apply(vkGetBufferMemoryRequirements); \
|
|
apply(vkMapMemory); \
|
|
apply(vkBindBufferMemory); \
|
|
apply(vkAllocateMemory); \
|
|
apply(vkDestroyBuffer); \
|
|
apply(vkFreeMemory); \
|
|
apply(vkUnmapMemory); \
|
|
apply(vkQueueWaitIdle); \
|
|
apply(vkDeviceWaitIdle); \
|
|
apply(vkCmdCopyBufferToImage); \
|
|
apply(vkFlushMappedMemoryRanges); \
|
|
apply(vkCreatePipelineLayout); \
|
|
apply(vkCreateShaderModule); \
|
|
apply(vkDestroyShaderModule); \
|
|
apply(vkCreateGraphicsPipelines); \
|
|
apply(vkCmdBindPipeline); \
|
|
apply(vkCmdDraw); \
|
|
apply(vkCmdPushConstants); \
|
|
apply(vkCmdBindVertexBuffers); \
|
|
apply(vkDestroyPipeline); \
|
|
apply(vkCmdSetFragmentShadingRateKHR); \
|
|
apply(vkCmdBindDescriptorSets); \
|
|
apply(vkCreateDevice); \
|
|
apply(vkGetPhysicalDeviceFeatures2); \
|
|
apply(vkGetPhysicalDeviceProperties2); \
|
|
apply(vkEnumerateDeviceExtensionProperties); \
|
|
apply(vkGetPhysicalDeviceProperties2KHR); \
|
|
apply(vkDestroyPipelineLayout);
|
|
|
|
#define VULKAN_DEFINE_API_FUNCPTR(func) static PFN_##func func
|
|
VULKAN_DEFINE_API_FUNCPTR(vkGetInstanceProcAddr);
|
|
UNITY_USED_VULKAN_API_FUNCTIONS(VULKAN_DEFINE_API_FUNCPTR);
|
|
#undef VULKAN_DEFINE_API_FUNCPTR
|
|
|
|
|
|
#if OHOS
|
|
#include "xengine/xeg_vulkan_adaptive_vrs.h"
|
|
#include "xengine/xeg_vulkan_spatial_upscale.h"
|
|
#include "xengine/xeg_vulkan_extension.h"
|
|
#endif
|
|
|
|
extern void unityLog(const char *msg);
|
|
|
|
enum VRSPluginShadingRate
|
|
{
|
|
X1_PER_PIXEL,
|
|
X1_PER_2X1_PIXELS,
|
|
X1_PER_1X2_PIXELS,
|
|
X1_PER_2X2_PIXELS,
|
|
X1_PER_4X2_PIXELS,
|
|
X1_PER_2X4_PIXELS,
|
|
X1_PER_4X4_PIXELS,
|
|
};
|
|
|
|
static VkExtent2D vrs_argment_size_table[] = {
|
|
VkExtent2D{1, 1},
|
|
VkExtent2D{2, 1},
|
|
VkExtent2D{1, 2},
|
|
VkExtent2D{2, 2},
|
|
VkExtent2D{4, 2},
|
|
VkExtent2D{2, 4},
|
|
VkExtent2D{4, 4},
|
|
};
|
|
|
|
static VkExtent2D vrs_fragment_size = vrs_argment_size_table[0];
|
|
static bool vrs_enable;
|
|
static int curVrsIndex = 0;
|
|
|
|
static void LoadVulkanAPI(PFN_vkGetInstanceProcAddr getInstanceProcAddr, VkInstance instance)
|
|
{
|
|
unityLog("LoadVulkanAPI called.");
|
|
if (!vkGetInstanceProcAddr && getInstanceProcAddr)
|
|
vkGetInstanceProcAddr = getInstanceProcAddr;
|
|
|
|
if (!vkCreateInstance)
|
|
vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance");
|
|
|
|
#define LOAD_VULKAN_FUNC(fn) \
|
|
if (!fn) \
|
|
fn = (PFN_##fn)vkGetInstanceProcAddr(instance, #fn)
|
|
UNITY_USED_VULKAN_API_FUNCTIONS(LOAD_VULKAN_FUNC);
|
|
#undef LOAD_VULKAN_FUNC
|
|
}
|
|
|
|
static VKAPI_ATTR void VKAPI_CALL Hook_vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin, VkSubpassContents contents)
|
|
{
|
|
// Change this to 'true' to override the clear color with green
|
|
const bool allowOverrideClearColor = false;
|
|
if (pRenderPassBegin->clearValueCount <= 16 && pRenderPassBegin->clearValueCount > 0 && allowOverrideClearColor)
|
|
{
|
|
VkClearValue clearValues[16] = {};
|
|
memcpy(clearValues, pRenderPassBegin->pClearValues, pRenderPassBegin->clearValueCount * sizeof(VkClearValue));
|
|
|
|
VkRenderPassBeginInfo patchedBeginInfo = *pRenderPassBegin;
|
|
patchedBeginInfo.pClearValues = clearValues;
|
|
for (unsigned int i = 0; i < pRenderPassBegin->clearValueCount - 1; ++i)
|
|
{
|
|
clearValues[i].color.float32[0] = 0.0;
|
|
clearValues[i].color.float32[1] = 1.0;
|
|
clearValues[i].color.float32[2] = 0.0;
|
|
clearValues[i].color.float32[3] = 1.0;
|
|
}
|
|
vkCmdBeginRenderPass(commandBuffer, &patchedBeginInfo, contents);
|
|
}
|
|
else
|
|
{
|
|
vkCmdBeginRenderPass(commandBuffer, pRenderPassBegin, contents);
|
|
}
|
|
}
|
|
|
|
static VKAPI_ATTR VkResult VKAPI_CALL Hook_vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkInstance *pInstance)
|
|
{
|
|
unityLog("Hook_vkCreateInstance called.");
|
|
if (pCreateInfo->ppEnabledExtensionNames)
|
|
{
|
|
for (size_t i = 0; i < pCreateInfo->enabledExtensionCount; i++)
|
|
{
|
|
unityLog(pCreateInfo->ppEnabledExtensionNames[i]);
|
|
}
|
|
}
|
|
|
|
vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance");
|
|
|
|
VkResult result = vkCreateInstance(pCreateInfo, pAllocator, pInstance);
|
|
if (result == VK_SUCCESS)
|
|
LoadVulkanAPI(vkGetInstanceProcAddr, *pInstance);
|
|
|
|
return result;
|
|
}
|
|
|
|
static VKAPI_ATTR VkResult VKAPI_CALL Hook_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
|
|
{
|
|
if (pCreateInfo->pNext)
|
|
{
|
|
unityLog("pCreateInfo->pNext");
|
|
}
|
|
|
|
return vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
|
|
}
|
|
static VKAPI_ATTR void VKAPI_CALL Hook_vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
|
|
VkPipelineLayout layout, uint32_t firstSet,
|
|
uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets,
|
|
uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets)
|
|
{
|
|
if (vrs_enable)
|
|
{
|
|
VkExtent2D fragment_size = vrs_argment_size_table[curVrsIndex];
|
|
|
|
VkFragmentShadingRateCombinerOpKHR combiner_ops[2];
|
|
// If shading rate from attachment is enabled, we set the combiner, so that the values from the attachment are used
|
|
// Combiner for pipeline (A) and primitive (B) - Not used in this sample
|
|
combiner_ops[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR;
|
|
// Combiner for pipeline (A) and attachment (B), replace the pipeline default value (fragment_size) with the fragment sizes stored in the attachment
|
|
combiner_ops[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR;
|
|
vkCmdSetFragmentShadingRateKHR(commandBuffer, &fragment_size, combiner_ops);
|
|
}
|
|
|
|
vkCmdBindDescriptorSets(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
|
|
}
|
|
|
|
static VKAPI_ATTR void VKAPI_CALL Hook_vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline)
|
|
{
|
|
// if (vrs_enable)
|
|
//{
|
|
// VkExtent2D fragment_size = vrs_argment_size_table[curVrsIndex];
|
|
|
|
// VkFragmentShadingRateCombinerOpKHR combiner_ops[2];
|
|
// // If shading rate from attachment is enabled, we set the combiner, so that the values from the attachment are used
|
|
// // Combiner for pipeline (A) and primitive (B) - Not used in this sample
|
|
// combiner_ops[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR;
|
|
// // Combiner for pipeline (A) and attachment (B), replace the pipeline default value (fragment_size) with the fragment sizes stored in the attachment
|
|
// combiner_ops[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR;
|
|
|
|
// vkCmdSetFragmentShadingRateKHR(commandBuffer, &fragment_size, combiner_ops);
|
|
//}
|
|
|
|
vkCmdBindPipeline(commandBuffer, pipelineBindPoint, pipeline);
|
|
}
|
|
|
|
static int FindMemoryTypeIndex(VkPhysicalDeviceMemoryProperties const &physicalDeviceMemoryProperties, VkMemoryRequirements const &memoryRequirements, VkMemoryPropertyFlags memoryPropertyFlags)
|
|
{
|
|
uint32_t memoryTypeBits = memoryRequirements.memoryTypeBits;
|
|
|
|
// Search memtypes to find first curVrsIndex with those properties
|
|
for (uint32_t memoryTypeIndex = 0; memoryTypeIndex < VK_MAX_MEMORY_TYPES; ++memoryTypeIndex)
|
|
{
|
|
if ((memoryTypeBits & 1) == 1)
|
|
{
|
|
// Type is available, does it match user properties?
|
|
if ((physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & memoryPropertyFlags) == memoryPropertyFlags)
|
|
return memoryTypeIndex;
|
|
}
|
|
memoryTypeBits >>= 1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL Hook_vkGetInstanceProcAddr(VkInstance device, const char *funcName)
|
|
{
|
|
if (!funcName)
|
|
return NULL;
|
|
unityLog(funcName);
|
|
#define INTERCEPT(fn) \
|
|
if (strcmp(funcName, #fn) == 0) \
|
|
return (PFN_vkVoidFunction) & Hook_##fn
|
|
INTERCEPT(vkCreateInstance);
|
|
INTERCEPT(vkCreateDevice);
|
|
INTERCEPT(vkCmdBindPipeline);
|
|
INTERCEPT(vkCmdBindDescriptorSets);
|
|
#undef INTERCEPT
|
|
|
|
return (PFN_vkVoidFunction)vkGetInstanceProcAddr(device, funcName);
|
|
}
|
|
|
|
static PFN_vkGetInstanceProcAddr UNITY_INTERFACE_API InterceptVulkanInitialization(PFN_vkGetInstanceProcAddr getInstanceProcAddr, void *)
|
|
{
|
|
vkGetInstanceProcAddr = getInstanceProcAddr;
|
|
return Hook_vkGetInstanceProcAddr;
|
|
}
|
|
|
|
extern "C" void RenderAPI_Vulkan_OnPluginLoad(IUnityInterfaces *interfaces)
|
|
{
|
|
if (IUnityGraphicsVulkanV2 *vulkanInterface = interfaces->Get<IUnityGraphicsVulkanV2>())
|
|
{
|
|
vulkanInterface->AddInterceptInitialization(InterceptVulkanInitialization, NULL, 0);
|
|
}
|
|
else if (IUnityGraphicsVulkan *vulkanInterface = interfaces->Get<IUnityGraphicsVulkan>())
|
|
{
|
|
vulkanInterface->InterceptInitialization(InterceptVulkanInitialization, NULL);
|
|
}
|
|
}
|
|
|
|
struct VulkanBuffer
|
|
{
|
|
VkBuffer buffer;
|
|
VkDeviceMemory deviceMemory;
|
|
void *mapped;
|
|
VkDeviceSize sizeInBytes;
|
|
VkDeviceSize deviceMemorySize;
|
|
VkMemoryPropertyFlags deviceMemoryFlags;
|
|
};
|
|
|
|
class RenderAPI_Vulkan : public RenderAPI
|
|
{
|
|
public:
|
|
RenderAPI_Vulkan();
|
|
virtual ~RenderAPI_Vulkan() {}
|
|
|
|
virtual void processDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces *interfaces) override;
|
|
virtual bool getUsesReverseZ() override { return true; }
|
|
|
|
virtual void enableVRS(int vrsEnum) override;
|
|
virtual void disableVRS() override;
|
|
|
|
virtual void enableFGExtrapolation(void* data) override;
|
|
virtual void preFGExtrapolation() override;
|
|
virtual bool doFGExtrapolation(void *src, void *data, void *dst) override;
|
|
virtual void postFGExtrapolation() override;
|
|
virtual void disableFGExtrapolation() override;
|
|
|
|
private:
|
|
typedef std::vector<VulkanBuffer> VulkanBuffers;
|
|
typedef std::map<unsigned long long, VulkanBuffers> DeleteQueue;
|
|
|
|
private:
|
|
bool createVulkanBuffer(size_t bytes, VulkanBuffer *buffer, VkBufferUsageFlags usage);
|
|
void immediateDestroyVulkanBuffer(const VulkanBuffer &buffer);
|
|
void safeDestroy(unsigned long long frameNumber, const VulkanBuffer &buffer);
|
|
void garbageCollect(bool force = false);
|
|
|
|
virtual void initSupportFeature() override;
|
|
|
|
private:
|
|
IUnityGraphicsVulkan *unity_vulkan;
|
|
UnityVulkanInstance unity_vk_instance;
|
|
std::map<unsigned long long, VulkanBuffers> m_DeleteQueue;
|
|
};
|
|
|
|
RenderAPI *CreateRenderAPI_Vulkan()
|
|
{
|
|
return new RenderAPI_Vulkan();
|
|
}
|
|
|
|
RenderAPI_Vulkan::RenderAPI_Vulkan()
|
|
: unity_vulkan(NULL)
|
|
{
|
|
}
|
|
|
|
void RenderAPI_Vulkan::processDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces *interfaces)
|
|
{
|
|
switch (type)
|
|
{
|
|
case kUnityGfxDeviceEventInitialize:
|
|
unityLog("ProcessDeviceEvent called. kUnityGfxDeviceEventInitialize");
|
|
|
|
unity_vulkan = interfaces->Get<IUnityGraphicsVulkan>();
|
|
unity_vk_instance = unity_vulkan->Instance();
|
|
|
|
// Make sure Vulkan API functions are loaded
|
|
LoadVulkanAPI(unity_vk_instance.getInstanceProcAddr, unity_vk_instance.instance);
|
|
|
|
UnityVulkanPluginEventConfig config_1;
|
|
config_1.graphicsQueueAccess = kUnityVulkanGraphicsQueueAccess_DontCare;
|
|
config_1.renderPassPrecondition = kUnityVulkanRenderPass_EnsureInside;
|
|
config_1.flags = kUnityVulkanEventConfigFlag_EnsurePreviousFrameSubmission | kUnityVulkanEventConfigFlag_ModifiesCommandBuffersState;
|
|
unity_vulkan->ConfigureEvent(1, &config_1);
|
|
|
|
// alternative way to intercept API
|
|
unity_vulkan->InterceptVulkanAPI("vkCmdBeginRenderPass", (PFN_vkVoidFunction)Hook_vkCmdBeginRenderPass);
|
|
initSupportFeature();
|
|
break;
|
|
case kUnityGfxDeviceEventShutdown:
|
|
unityLog("ProcessDeviceEvent called. kUnityGfxDeviceEventShutdown");
|
|
|
|
if (unity_vk_instance.device != VK_NULL_HANDLE)
|
|
{
|
|
garbageCollect(true);
|
|
}
|
|
|
|
unity_vulkan = NULL;
|
|
unity_vk_instance = UnityVulkanInstance();
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool RenderAPI_Vulkan::createVulkanBuffer(size_t sizeInBytes, VulkanBuffer *buffer, VkBufferUsageFlags usage)
|
|
{
|
|
if (sizeInBytes == 0)
|
|
return false;
|
|
|
|
VkBufferCreateInfo bufferCreateInfo;
|
|
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
bufferCreateInfo.pNext = NULL;
|
|
bufferCreateInfo.pQueueFamilyIndices = &unity_vk_instance.queueFamilyIndex;
|
|
bufferCreateInfo.queueFamilyIndexCount = 1;
|
|
bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
bufferCreateInfo.usage = usage;
|
|
bufferCreateInfo.flags = 0;
|
|
bufferCreateInfo.size = sizeInBytes;
|
|
|
|
*buffer = VulkanBuffer();
|
|
|
|
if (vkCreateBuffer(unity_vk_instance.device, &bufferCreateInfo, NULL, &buffer->buffer) != VK_SUCCESS)
|
|
return false;
|
|
|
|
VkPhysicalDeviceMemoryProperties physicalDeviceProperties;
|
|
vkGetPhysicalDeviceMemoryProperties(unity_vk_instance.physicalDevice, &physicalDeviceProperties);
|
|
|
|
VkMemoryRequirements memoryRequirements;
|
|
vkGetBufferMemoryRequirements(unity_vk_instance.device, buffer->buffer, &memoryRequirements);
|
|
|
|
const int memoryTypeIndex = FindMemoryTypeIndex(physicalDeviceProperties, memoryRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
|
|
if (memoryTypeIndex < 0)
|
|
{
|
|
immediateDestroyVulkanBuffer(*buffer);
|
|
return false;
|
|
}
|
|
|
|
VkMemoryAllocateInfo memoryAllocateInfo;
|
|
memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
memoryAllocateInfo.pNext = NULL;
|
|
memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex;
|
|
memoryAllocateInfo.allocationSize = memoryRequirements.size;
|
|
|
|
if (vkAllocateMemory(unity_vk_instance.device, &memoryAllocateInfo, NULL, &buffer->deviceMemory) != VK_SUCCESS)
|
|
{
|
|
immediateDestroyVulkanBuffer(*buffer);
|
|
return false;
|
|
}
|
|
|
|
if (vkMapMemory(unity_vk_instance.device, buffer->deviceMemory, 0, VK_WHOLE_SIZE, 0, &buffer->mapped) != VK_SUCCESS)
|
|
{
|
|
immediateDestroyVulkanBuffer(*buffer);
|
|
return false;
|
|
}
|
|
|
|
if (vkBindBufferMemory(unity_vk_instance.device, buffer->buffer, buffer->deviceMemory, 0) != VK_SUCCESS)
|
|
{
|
|
immediateDestroyVulkanBuffer(*buffer);
|
|
return false;
|
|
}
|
|
|
|
buffer->sizeInBytes = sizeInBytes;
|
|
buffer->deviceMemoryFlags = physicalDeviceProperties.memoryTypes[memoryTypeIndex].propertyFlags;
|
|
buffer->deviceMemorySize = memoryAllocateInfo.allocationSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
void RenderAPI_Vulkan::immediateDestroyVulkanBuffer(const VulkanBuffer &buffer)
|
|
{
|
|
if (buffer.buffer != VK_NULL_HANDLE)
|
|
vkDestroyBuffer(unity_vk_instance.device, buffer.buffer, NULL);
|
|
|
|
if (buffer.mapped && buffer.deviceMemory != VK_NULL_HANDLE)
|
|
vkUnmapMemory(unity_vk_instance.device, buffer.deviceMemory);
|
|
|
|
if (buffer.deviceMemory != VK_NULL_HANDLE)
|
|
vkFreeMemory(unity_vk_instance.device, buffer.deviceMemory, NULL);
|
|
}
|
|
|
|
void RenderAPI_Vulkan::safeDestroy(unsigned long long frameNumber, const VulkanBuffer &buffer)
|
|
{
|
|
m_DeleteQueue[frameNumber].push_back(buffer);
|
|
}
|
|
|
|
void RenderAPI_Vulkan::garbageCollect(bool force /*= false*/)
|
|
{
|
|
UnityVulkanRecordingState recordingState;
|
|
if (force)
|
|
recordingState.safeFrameNumber = ~0ull;
|
|
else if (!unity_vulkan->CommandRecordingState(&recordingState, kUnityVulkanGraphicsQueueAccess_DontCare))
|
|
return;
|
|
|
|
DeleteQueue::iterator it = m_DeleteQueue.begin();
|
|
while (it != m_DeleteQueue.end())
|
|
{
|
|
if (it->first <= recordingState.safeFrameNumber)
|
|
{
|
|
for (size_t i = 0; i < it->second.size(); ++i)
|
|
immediateDestroyVulkanBuffer(it->second[i]);
|
|
m_DeleteQueue.erase(it++);
|
|
}
|
|
else
|
|
++it;
|
|
}
|
|
}
|
|
|
|
#if OHOS
|
|
void checkXEngine(VkPhysicalDevice physic_device, SupportFeatureList &fl)
|
|
{
|
|
std::vector<std::string> supported_extensions;
|
|
uint32_t property_cnt;
|
|
HMS_XEG_EnumerateDeviceExtensionProperties(physic_device, &property_cnt, nullptr);
|
|
if (property_cnt > 0)
|
|
{
|
|
std::vector<XEG_ExtensionProperties> properties(property_cnt);
|
|
if (HMS_XEG_EnumerateDeviceExtensionProperties(physic_device, &property_cnt,
|
|
&properties.front()) == VK_SUCCESS)
|
|
{
|
|
for (auto ext : properties)
|
|
{
|
|
supported_extensions.push_back(ext.extensionName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (std::find(supported_extensions.begin(), supported_extensions.end(), XEG_SPATIAL_UPSCALE_EXTENSION_NAME) !=
|
|
supported_extensions.end())
|
|
{
|
|
fl[GraphicsFeature::HW_SPATIAL_SR] = true;
|
|
}
|
|
|
|
if (std::find(supported_extensions.begin(), supported_extensions.end(), XEG_ADAPTIVE_VRS_EXTENSION_NAME) !=
|
|
supported_extensions.end())
|
|
{
|
|
fl[GraphicsFeature::HW_ADAPTIVE_VRS] = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void RenderAPI_Vulkan::initSupportFeature()
|
|
{
|
|
auto physic_device = unity_vk_instance.physicalDevice;
|
|
uint32_t extension_cnt;
|
|
vkEnumerateDeviceExtensionProperties(physic_device, nullptr, &extension_cnt, nullptr);
|
|
std::vector<VkExtensionProperties> available_extensions(extension_cnt);
|
|
vkEnumerateDeviceExtensionProperties(physic_device, nullptr, &extension_cnt, available_extensions.data());
|
|
|
|
VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_feature{};
|
|
vrs_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
|
|
VkPhysicalDeviceFeatures2 features2{};
|
|
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
|
features2.pNext = &vrs_feature;
|
|
vkGetPhysicalDeviceFeatures2(physic_device, &features2);
|
|
|
|
support_features[GraphicsFeature::VRS_DRAW] = vrs_feature.pipelineFragmentShadingRate;
|
|
support_features[GraphicsFeature::VRS_PRIMITIVE] = vrs_feature.primitiveFragmentShadingRate;
|
|
support_features[GraphicsFeature::VRS_ATTACHMENT] = vrs_feature.attachmentFragmentShadingRate;
|
|
|
|
#if OHOS
|
|
checkXEngine(physic_device, support_features);
|
|
#endif
|
|
// char buf[40];
|
|
// sprintf(buf, "initSupportFeature VRS %d %d %d \n", (int)support_vrs_draw, (int)support_vrs_primitive, (int)support_vrs_attachment);
|
|
// unityLog(buf);
|
|
}
|
|
|
|
void RenderAPI_Vulkan::enableVRS(int vrsEnum)
|
|
{
|
|
curVrsIndex = vrsEnum;
|
|
vrs_fragment_size = vrs_argment_size_table[vrsEnum];
|
|
vrs_enable = true;
|
|
}
|
|
|
|
void RenderAPI_Vulkan::disableVRS()
|
|
{
|
|
vrs_enable = false;
|
|
}
|
|
|
|
void RenderAPI_Vulkan::enableFGExtrapolation(void* data)
|
|
{
|
|
}
|
|
|
|
void RenderAPI_Vulkan::preFGExtrapolation()
|
|
{
|
|
}
|
|
|
|
bool RenderAPI_Vulkan::doFGExtrapolation(void *src, void *data, void *dst)
|
|
{
|
|
// ???
|
|
// unity_vulkan->EnsureOutsideRenderPass();
|
|
|
|
UnityVulkanImage image;
|
|
if (unity_vulkan->AccessTexture(src, UnityVulkanWholeImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, kUnityVulkanResourceAccess_PipelineBarrier, &image))
|
|
{
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void RenderAPI_Vulkan::postFGExtrapolation()
|
|
{
|
|
}
|
|
|
|
void RenderAPI_Vulkan::disableFGExtrapolation()
|
|
{
|
|
}
|
|
#endif // #if SUPPORT_VULKAN
|