Compare commits

...

1 Commits

Author SHA1 Message Date
Powei Feng
46f38957f2 vk: fix rendering to 2D view of 3D image
BUG=389760706
2025-02-06 16:11:49 -08:00
3 changed files with 88 additions and 53 deletions

View File

@@ -161,13 +161,24 @@ public:
return mProtectedMemorySupported;
}
inline bool isImageView2DOn3DImageSupported() const noexcept {
return mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
}
private:
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
VkPhysicalDeviceProperties2 mPhysicalDeviceProperties = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
};
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
};
VkPhysicalDevicePortabilitySubsetFeaturesKHR mPortabilitySubsetFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
// By default, on platforms where we don't have portability subset, then this feature must
// exists. We only fill this struct only when portability subset is needed (i.e.
// non-conformant vulkan implementation).
.imageView2DOn3DImage = VK_TRUE,
};
bool mDebugMarkersSupported = false;
bool mDebugUtilsSupported = false;

View File

@@ -198,11 +198,20 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = 0,
};
if (target == SamplerType::SAMPLER_CUBEMAP) {
if (target == SamplerType::SAMPLER_3D && any(tusage & TextureUsage::ALL_ATTACHMENTS)) {
if (context.isImageView2DOn3DImageSupported()) {
// Note that VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT is only meant to create 2D views of
// a 3D image in the case where the image is the render target. So, for example, it's
// not meant to allow for 2D views that can be used with a sampler.
imageInfo.flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
} else {
FVK_LOGW << "Note: creating 2D views on 3D image is not available on this platform. "
<< "i.e. we cannot render to slices of a 3D image" << utils::io::endl;
}
} else if (target == SamplerType::SAMPLER_CUBEMAP) {
imageInfo.arrayLayers = 6;
imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
if (target == SamplerType::SAMPLER_2D_ARRAY) {
} else if (target == SamplerType::SAMPLER_2D_ARRAY) {
imageInfo.arrayLayers = depth;
imageInfo.extent.depth = 1;
// NOTE: We do not use VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT here because:

View File

@@ -84,6 +84,13 @@ FixedCapacityVector<const char*> getEnabledLayers() {
}
#endif // FVK_EANBLED(FVK_DEBUG_VALIDATION)
template<typename StructA, typename StructB>
StructA* chainStruct(StructA* structA, StructB* structB) {
structB->pNext = const_cast<void*>(structA->pNext);
structA->pNext = (void*) structB;
return structA;
}
void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
// Print some driver or MoltenVK information if it is available.
if (vkGetPhysicalDeviceProperties2) {
@@ -92,8 +99,8 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) {
};
VkPhysicalDeviceProperties2 physicalDeviceProperties2 = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
.pNext = &driverProperties,
};
chainStruct(&physicalDeviceProperties2, &driverProperties);
vkGetPhysicalDeviceProperties2(device, &physicalDeviceProperties2);
FVK_LOGI << "Vulkan device driver: " << driverProperties.driverName << " "
<< driverProperties.driverInfo << utils::io::endl;
@@ -194,7 +201,7 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
#if FVK_ENABLED(FVK_DEBUG_DEBUG_UTILS)
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
#endif
// We only support external image for Android for now, but nothing bars us from
// We only support external image for Android for now, but nothing bars us from
// supporting other platforms.
#if defined(__ANDROID__)
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
@@ -231,7 +238,9 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) {
VkInstance createInstance(ExtensionSet const& requiredExts) {
VkInstance instance;
VkInstanceCreateInfo instanceCreateInfo = {};
VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
};
bool validationFeaturesSupported = false;
#if FVK_ENABLED(FVK_DEBUG_VALIDATION)
@@ -282,7 +291,6 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
appInfo.pEngineName = "Filament";
appInfo.apiVersion
= VK_MAKE_API_VERSION(0, FVK_REQUIRED_VERSION_MAJOR, FVK_REQUIRED_VERSION_MINOR, 0);
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pApplicationInfo = &appInfo;
instanceCreateInfo.enabledExtensionCount = enabledExtensionCount;
instanceCreateInfo.ppEnabledExtensionNames = ppEnabledExtensions;
@@ -290,16 +298,17 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}
VkValidationFeaturesEXT features = {};
VkValidationFeaturesEXT features = {
.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT,
};
VkValidationFeatureEnableEXT enables[] = {
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT,
};
if (validationFeaturesSupported) {
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
features.enabledValidationFeatureCount = sizeof(enables) / sizeof(enables[0]);
features.pEnabledValidationFeatures = enables;
instanceCreateInfo.pNext = &features;
chainStruct(&instanceCreateInfo, &features);
}
VkResult result = vkCreateInstance(&instanceCreateInfo, VKALLOC, &instance);
@@ -310,11 +319,13 @@ VkInstance createInstance(ExtensionSet const& requiredExts) {
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures2 const& features, uint32_t graphicsQueueFamilyIndex,
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions) {
uint32_t protectedGraphicsQueueFamilyIndex, ExtensionSet const& deviceExtensions,
bool requestImageView2DOn3DImage) {
VkDevice device;
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
const float queuePriority[] = {1.0f};
VkDeviceCreateInfo deviceCreateInfo = {};
float queuePriority[] = {1.0f};
VkDeviceCreateInfo deviceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
};
FixedCapacityVector<const char*> requestExtensions;
requestExtensions.reserve(deviceExtensions.size() + 1);
@@ -323,6 +334,7 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
for (auto const& ext: deviceExtensions) {
requestExtensions.push_back(ext.data());
}
VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = {};
deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
deviceQueueCreateInfo[0].queueFamilyIndex = graphicsQueueFamilyIndex;
deviceQueueCreateInfo[0].queueCount = 1;
@@ -334,7 +346,6 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
deviceQueueCreateInfo[1].queueCount = 1;
deviceQueueCreateInfo[1].pQueuePriorities = &queuePriority[0];
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
bool const hasProtectedQueue = protectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX;
deviceCreateInfo.queueCreateInfoCount = hasProtectedQueue ? 2 : 1;
deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo;
@@ -353,42 +364,36 @@ VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice,
deviceCreateInfo.enabledExtensionCount = (uint32_t) requestExtensions.size();
deviceCreateInfo.ppEnabledExtensionNames = requestExtensions.data();
void* pNext = nullptr;
VkPhysicalDevicePortabilitySubsetFeaturesKHR portability = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
.pNext = nullptr,
.imageViewFormatSwizzle = VK_TRUE,
.mutableComparisonSamplers = VK_TRUE,
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR,
.imageViewFormatSwizzle = VK_TRUE,
.mutableComparisonSamplers = VK_TRUE,
.imageView2DOn3DImage = requestImageView2DOn3DImage ? VK_TRUE : VK_FALSE,
};
if (setContains(deviceExtensions, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
portability.pNext = pNext;
pNext = &portability;
chainStruct(&deviceCreateInfo, &portability);
}
VkPhysicalDeviceMultiviewFeaturesKHR multiview = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
.pNext = nullptr,
.multiview = VK_TRUE,
.multiviewGeometryShader = VK_FALSE,
.multiviewTessellationShader = VK_FALSE
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
.pNext = nullptr,
.multiview = VK_TRUE,
.multiviewGeometryShader = VK_FALSE,
.multiviewTessellationShader = VK_FALSE,
};
if (setContains(deviceExtensions, VK_KHR_MULTIVIEW_EXTENSION_NAME)) {
multiview.pNext = pNext;
pNext = &multiview;
chainStruct(&deviceCreateInfo, &multiview);
}
VkPhysicalDeviceProtectedMemoryFeatures protectedMemory = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
.protectedMemory = VK_TRUE,
};
if (hasProtectedQueue) {
// Enable protected memory, if requested.
protectedMemory.protectedMemory = VK_TRUE;
protectedMemory.pNext = pNext;
pNext = &protectedMemory;
chainStruct(&deviceCreateInfo, &protectedMemory);
}
deviceCreateInfo.pNext = pNext;
VkResult result = vkCreateDevice(physicalDevice, &deviceCreateInfo, VKALLOC, &device);
FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS)
<< "vkCreateDevice error=" << static_cast<int32_t>(result);
@@ -501,7 +506,7 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance,
// Does the device have any command queues that support graphics?
// In theory, we should also ensure that the device supports presentation of our
// particular VkSurface, but we don't have a VkSurface yet, so we'll skip this requirement.
if (identifyGraphicsQueueFamilyIndex(candidateDevice, VK_QUEUE_GRAPHICS_BIT)
if (identifyGraphicsQueueFamilyIndex(candidateDevice, VK_QUEUE_GRAPHICS_BIT)
== INVALID_VK_INDEX) {
continue;
}
@@ -721,14 +726,11 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
VkPhysicalDeviceProtectedMemoryFeatures queryProtectedMemoryFeatures = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES,
};
// Chain to the pNext linked list
queryProtectedMemoryFeatures.pNext = context.mPhysicalDeviceFeatures.pNext;
context.mPhysicalDeviceFeatures.pNext = &queryProtectedMemoryFeatures;
VkPhysicalDeviceProtectedMemoryProperties protectedMemoryProperties = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES,
};
protectedMemoryProperties.pNext = context.mPhysicalDeviceProperties.pNext;
context.mPhysicalDeviceProperties.pNext = &protectedMemoryProperties;
chainStruct(&context.mPhysicalDeviceFeatures, &queryProtectedMemoryFeatures);
chainStruct(&context.mPhysicalDeviceProperties, &protectedMemoryProperties);
// Initialize the following fields: physicalDeviceProperties, memoryProperties,
// physicalDeviceFeatures, graphicsQueueFamilyIndex.
@@ -738,17 +740,17 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
mImpl->mGraphicsQueueFamilyIndex
= mImpl->mGraphicsQueueFamilyIndex == INVALID_VK_INDEX
? identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
? identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
VK_QUEUE_GRAPHICS_BIT)
: mImpl->mGraphicsQueueFamilyIndex;
assert_invariant(mImpl->mGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
// We know we need to allocate the protected version of the VK objects
context.mProtectedMemorySupported =
context.mProtectedMemorySupported =
static_cast<bool>(queryProtectedMemoryFeatures.protectedMemory);
if (context.mProtectedMemorySupported) {
mImpl->mProtectedGraphicsQueueFamilyIndex
= identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
= identifyGraphicsQueueFamilyIndex(mImpl->mPhysicalDevice,
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_PROTECTED_BIT));
assert_invariant(mImpl->mProtectedGraphicsQueueFamilyIndex != INVALID_VK_INDEX);
}
@@ -768,7 +770,7 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
// Applying the same logic to the protected queue index (Not sure about shared context and protection)
mImpl->mProtectedGraphicsQueueIndex
= mImpl->mProtectedGraphicsQueueIndex == INVALID_VK_INDEX ? 0 :
= mImpl->mProtectedGraphicsQueueIndex == INVALID_VK_INDEX ? 0 :
mImpl->mProtectedGraphicsQueueIndex;
ExtensionSet deviceExts;
@@ -785,11 +787,24 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
}
}
mImpl->mDevice
= mImpl->mDevice == VK_NULL_HANDLE ? createLogicalDevice(mImpl->mPhysicalDevice,
context.mPhysicalDeviceFeatures, mImpl->mGraphicsQueueFamilyIndex,
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts)
: mImpl->mDevice;
bool requestPortabilitySubsetImageView2DOn3DImage = false;
if (setContains(deviceExts, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
// We are on a non-conformant vulkan implementation so we need to ascertain if the features
// we need are available.
chainStruct(&context.mPhysicalDeviceFeatures, &context.mPortabilitySubsetFeatures);
vkGetPhysicalDeviceFeatures2(mImpl->mPhysicalDevice, &context.mPhysicalDeviceFeatures);
requestPortabilitySubsetImageView2DOn3DImage =
context.mPortabilitySubsetFeatures.imageView2DOn3DImage == VK_TRUE;
}
mImpl->mDevice =
mImpl->mDevice == VK_NULL_HANDLE
? createLogicalDevice(mImpl->mPhysicalDevice, context.mPhysicalDeviceFeatures,
mImpl->mGraphicsQueueFamilyIndex,
mImpl->mProtectedGraphicsQueueFamilyIndex, deviceExts,
requestPortabilitySubsetImageView2DOn3DImage)
: mImpl->mDevice;
assert_invariant(mImpl->mDevice != VK_NULL_HANDLE);
vkGetDeviceQueue(mImpl->mDevice, mImpl->mGraphicsQueueFamilyIndex, mImpl->mGraphicsQueueIndex,