[graphite][vulkan] Support VK_ext_frame_boundary extension
Extended queue submission interface to take a struct similar
to Ganesh that would allow extra metadata to be passed during
submission. Added support to mark frame boundary using
VK_ext_frame_boundary extension if supported. This will make
tracing of Skia-based Android applications easier as some
of them do not use common frame boundary mechanisms like
presenting image on a swapchain
Bug: b/439531864
Change-Id: Ife15d64442de24a691f6213583b18c9f7f38a4bf
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1055416
Commit-Queue: Max Kolesin <maxkolesin@google.com>
Reviewed-by: Nicolette Prevost <nicolettep@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/include/gpu/graphite/Context.h b/include/gpu/graphite/Context.h
index dfcc734..2fd8be1 100644
--- a/include/gpu/graphite/Context.h
+++ b/include/gpu/graphite/Context.h
@@ -80,7 +80,7 @@
std::unique_ptr<PrecompileContext> makePrecompileContext();
InsertStatus insertRecording(const InsertRecordingInfo&);
- bool submit(SyncToCpu = SyncToCpu::kNo);
+ bool submit(SubmitInfo submitInfo = {});
/** Returns true if there is work that was submitted to the GPU that has not finished. */
bool hasUnfinishedGpuWork() const;
diff --git a/include/gpu/graphite/GraphiteTypes.h b/include/gpu/graphite/GraphiteTypes.h
index 2940096..a638da8 100644
--- a/include/gpu/graphite/GraphiteTypes.h
+++ b/include/gpu/graphite/GraphiteTypes.h
@@ -170,6 +170,29 @@
kNo = false
};
+enum class MarkFrameBoundary : bool {
+ kYes = true,
+ kNo = false
+};
+
+struct SubmitInfo {
+ SyncToCpu fSync = SyncToCpu::kNo;
+ MarkFrameBoundary fMarkBoundary = MarkFrameBoundary::kNo;
+ uint64_t fFrameID = 0;
+
+ constexpr SubmitInfo() = default;
+
+ constexpr SubmitInfo(SyncToCpu sync)
+ : fSync(sync)
+ , fMarkBoundary(MarkFrameBoundary::kNo)
+ , fFrameID(0) {}
+
+ constexpr SubmitInfo(SyncToCpu sync, uint64_t frameID)
+ : fSync(sync)
+ , fMarkBoundary(MarkFrameBoundary::kYes)
+ , fFrameID(frameID) {}
+};
+
/*
* For Promise Images - should the Promise Image be fulfilled every time a Recording that references
* it is inserted into the Context.
diff --git a/include/gpu/vk/VulkanPreferredFeatures.h b/include/gpu/vk/VulkanPreferredFeatures.h
index cbe88ac..3810a42 100644
--- a/include/gpu/vk/VulkanPreferredFeatures.h
+++ b/include/gpu/vk/VulkanPreferredFeatures.h
@@ -189,6 +189,9 @@
// Feature of VK_EXT_pipeline_creation_cache_control or Vulkan 1.3
VkPhysicalDevicePipelineCreationCacheControlFeatures fPipelineCreationCacheControl = {};
+ // Feature of VK_EXT_frame_boundary
+ VkPhysicalDeviceFrameBoundaryFeaturesEXT fFrameBoundary = {};
+
// Extensions that don't have a feature:
// VK_KHR_driver_properties or Vulkan 1.2
const char* fDriverPropertiesExtension = nullptr;
diff --git a/relnotes/graphite_submitinfo.md b/relnotes/graphite_submitinfo.md
new file mode 100644
index 0000000..f0511da
--- /dev/null
+++ b/relnotes/graphite_submitinfo.md
@@ -0,0 +1,5 @@
+Add enum class `skgpu::graphite::MarkFrameBoundary` to be used to specify whether a submission is the last logical submission for a frame.
+
+Add struct `skgpu::graphite::SubmitInfo` to hold metadata used for submitting workloads for execution. Allow specifying through `skgpu::graphite::SubmitInfo` whether submission is a frame boundary (last logical submission for a frame) and frameID (uint64_t) with default values to match prior behavior.
+
+Use struct `skgpu::graphite::SubmitInfo` in `skgpu::graphite::QueueManager::submitToGpu`, `skgpu::graphite::QueueManager::onSubmitToGpu` and all derived classes.
diff --git a/src/gpu/graphite/Context.cpp b/src/gpu/graphite/Context.cpp
index 6e34e75..11f611e 100644
--- a/src/gpu/graphite/Context.cpp
+++ b/src/gpu/graphite/Context.cpp
@@ -181,7 +181,7 @@
return false;
}
if (result == StaticBufferManager::FinishResult::kSuccess &&
- !fQueueManager->submitToGpu()) {
+ !fQueueManager->submitToGpu(/*submitInfo=*/{})) {
SKGPU_LOG_W("Failed to submit initial command buffer for Context creation.\n");
return false;
} // else result was kNoWork so skip submitting to the GPU
@@ -238,16 +238,16 @@
return fQueueManager->addRecording(info, this);
}
-bool Context::submit(SyncToCpu syncToCpu) {
+bool Context::submit(SubmitInfo submitInfo) {
ASSERT_SINGLE_OWNER
- if (syncToCpu == SyncToCpu::kYes && !fSharedContext->caps()->allowCpuSync()) {
+ if (submitInfo.fSync == SyncToCpu::kYes && !fSharedContext->caps()->allowCpuSync()) {
SKGPU_LOG_E("SyncToCpu::kYes not supported with ContextOptions::fNeverYieldToWebGPU. "
"The parameter is ignored and no synchronization will occur.");
- syncToCpu = SyncToCpu::kNo;
+ submitInfo.fSync = SyncToCpu::kNo;
}
- bool success = fQueueManager->submitToGpu();
- this->checkForFinishedWork(syncToCpu);
+ bool success = fQueueManager->submitToGpu(submitInfo);
+ this->checkForFinishedWork(submitInfo.fSync);
return success;
}
diff --git a/src/gpu/graphite/QueueManager.cpp b/src/gpu/graphite/QueueManager.cpp
index 756c56b..2948e07 100644
--- a/src/gpu/graphite/QueueManager.cpp
+++ b/src/gpu/graphite/QueueManager.cpp
@@ -274,7 +274,7 @@
return true;
}
-bool QueueManager::submitToGpu() {
+bool QueueManager::submitToGpu(const SubmitInfo& submitInfo) {
TRACE_EVENT0_ALWAYS("skia.gpu", TRACE_FUNC);
if (!fCurrentCommandBuffer) {
@@ -291,7 +291,7 @@
}
#endif
- auto submission = this->onSubmitToGpu();
+ auto submission = this->onSubmitToGpu(submitInfo);
if (!submission) {
return false;
}
diff --git a/src/gpu/graphite/QueueManager.h b/src/gpu/graphite/QueueManager.h
index 8464566..4c380ce 100644
--- a/src/gpu/graphite/QueueManager.h
+++ b/src/gpu/graphite/QueueManager.h
@@ -63,7 +63,7 @@
ResourceProvider*,
SkSpan<const sk_sp<Buffer>> buffersToAsyncMap = {});
- [[nodiscard]] bool submitToGpu();
+ [[nodiscard]] bool submitToGpu(const SubmitInfo&);
[[nodiscard]] bool hasUnfinishedGpuWork();
void checkForFinishedWork(SyncToCpu);
@@ -88,7 +88,7 @@
private:
virtual std::unique_ptr<CommandBuffer> getNewCommandBuffer(ResourceProvider*, Protected) = 0;
- virtual OutstandingSubmission onSubmitToGpu() = 0;
+ virtual OutstandingSubmission onSubmitToGpu(const SubmitInfo&) = 0;
bool setupCommandBuffer(ResourceProvider*, Protected);
diff --git a/src/gpu/graphite/dawn/DawnQueueManager.cpp b/src/gpu/graphite/dawn/DawnQueueManager.cpp
index 6d30ba6..a2a7ee2 100644
--- a/src/gpu/graphite/dawn/DawnQueueManager.cpp
+++ b/src/gpu/graphite/dawn/DawnQueueManager.cpp
@@ -113,7 +113,7 @@
static_cast<DawnResourceProvider*>(resourceProvider));
}
-QueueManager::OutstandingSubmission DawnQueueManager::onSubmitToGpu() {
+QueueManager::OutstandingSubmission DawnQueueManager::onSubmitToGpu(const SubmitInfo&) {
SkASSERT(fCurrentCommandBuffer);
DawnCommandBuffer* dawnCmdBuffer = static_cast<DawnCommandBuffer*>(fCurrentCommandBuffer.get());
auto wgpuCmdBuffer = dawnCmdBuffer->finishEncoding();
diff --git a/src/gpu/graphite/dawn/DawnQueueManager.h b/src/gpu/graphite/dawn/DawnQueueManager.h
index 1e1928e..f1cfcef 100644
--- a/src/gpu/graphite/dawn/DawnQueueManager.h
+++ b/src/gpu/graphite/dawn/DawnQueueManager.h
@@ -30,7 +30,7 @@
const DawnSharedContext* dawnSharedContext() const;
std::unique_ptr<CommandBuffer> getNewCommandBuffer(ResourceProvider*, Protected) override;
- OutstandingSubmission onSubmitToGpu() override;
+ OutstandingSubmission onSubmitToGpu(const SubmitInfo&) override;
#if defined(GPU_TEST_UTILS)
void startCapture() override;
diff --git a/src/gpu/graphite/mtl/MtlQueueManager.h b/src/gpu/graphite/mtl/MtlQueueManager.h
index ff084fb..e2b3b74 100644
--- a/src/gpu/graphite/mtl/MtlQueueManager.h
+++ b/src/gpu/graphite/mtl/MtlQueueManager.h
@@ -26,7 +26,7 @@
const MtlSharedContext* mtlSharedContext() const;
std::unique_ptr<CommandBuffer> getNewCommandBuffer(ResourceProvider*, Protected) override;
- OutstandingSubmission onSubmitToGpu() override;
+ OutstandingSubmission onSubmitToGpu(const SubmitInfo&) override;
#if defined(GPU_TEST_UTILS)
void startCapture() override;
diff --git a/src/gpu/graphite/mtl/MtlQueueManager.mm b/src/gpu/graphite/mtl/MtlQueueManager.mm
index c86c794..e51a49e 100644
--- a/src/gpu/graphite/mtl/MtlQueueManager.mm
+++ b/src/gpu/graphite/mtl/MtlQueueManager.mm
@@ -49,7 +49,7 @@
}
};
-QueueManager::OutstandingSubmission MtlQueueManager::onSubmitToGpu() {
+QueueManager::OutstandingSubmission MtlQueueManager::onSubmitToGpu(const SubmitInfo&) {
SkASSERT(fCurrentCommandBuffer);
MtlCommandBuffer* mtlCmdBuffer = static_cast<MtlCommandBuffer*>(fCurrentCommandBuffer.get());
if (!mtlCmdBuffer->commit()) {
diff --git a/src/gpu/graphite/vk/VulkanCaps.cpp b/src/gpu/graphite/vk/VulkanCaps.cpp
index fd06f15..2f600e5 100644
--- a/src/gpu/graphite/vk/VulkanCaps.cpp
+++ b/src/gpu/graphite/vk/VulkanCaps.cpp
@@ -207,6 +207,7 @@
fSupportsYcbcrConversion = enabledFeatures.fSamplerYcbcrConversion;
fSupportsDeviceFaultInfo = enabledFeatures.fDeviceFault;
+ fSupportsFrameBoundary = enabledFeatures.fFrameBoundary;
if (enabledFeatures.fAdvancedBlendModes) {
fBlendEqSupport = enabledFeatures.fCoherentAdvancedBlendModes
@@ -252,6 +253,9 @@
enabledFeatures.fGraphicsPipelineLibrary &&
(deviceProperties.fGpl.graphicsPipelineLibraryFastLinking || vendorID == kARM_VkVendor);
+
+ fSupportsFrameBoundary = enabledFeatures.fFrameBoundary;
+
// Multisampled render to single-sampled usage depends on the mandatory feature of
// VK_EXT_multisampled_render_to_single_sampled. Per format queries are needed to determine if
// multisampled->single-sampled rendering is supported, which should in practice always be equal
@@ -386,6 +390,13 @@
enabled.fHostImageCopy = feature->hostImageCopy;
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT: {
+ const auto *feature = reinterpret_cast<
+ const VkPhysicalDeviceFrameBoundaryFeaturesEXT*>(
+ pNext);
+ enabled.fFrameBoundary = feature->frameBoundary;
+ break;
+ }
default:
break;
}
diff --git a/src/gpu/graphite/vk/VulkanCaps.h b/src/gpu/graphite/vk/VulkanCaps.h
index 49f293c1..bb6bed5 100644
--- a/src/gpu/graphite/vk/VulkanCaps.h
+++ b/src/gpu/graphite/vk/VulkanCaps.h
@@ -119,6 +119,8 @@
bool mustLoadFullImageForMSAA() const { return fMustLoadFullImageForMSAA; }
bool avoidMSAA() const { return fAvoidMSAA; }
+ bool supportsFrameBoundary() const { return fSupportsFrameBoundary; }
+
private:
void init(const ContextOptions&,
const skgpu::VulkanInterface*,
@@ -152,6 +154,8 @@
bool fMultisampledRenderToSingleSampled = false;
// From VkPhysicalDeviceHostImageCopyFeatures:
bool fHostImageCopy = false;
+ // From VkPhysicalDeviceFrameBoundaryFeaturesEXT:
+ bool fFrameBoundary = false;
};
EnabledFeatures getEnabledFeatures(const VkPhysicalDeviceFeatures2*,
uint32_t physicalDeviceVersion);
@@ -322,6 +326,7 @@
bool fSupportsDeviceFaultInfo = false;
bool fSupportsRasterizationOrderColorAttachmentAccess = false;
bool fIsInputAttachmentReadCoherent = false;
+ bool fSupportsFrameBoundary = false;
// Flags to enable workarounds for driver bugs
bool fMustLoadFullImageForMSAA = false;
diff --git a/src/gpu/graphite/vk/VulkanCommandBuffer.cpp b/src/gpu/graphite/vk/VulkanCommandBuffer.cpp
index 31a7bde..41a1872 100644
--- a/src/gpu/graphite/vk/VulkanCommandBuffer.cpp
+++ b/src/gpu/graphite/vk/VulkanCommandBuffer.cpp
@@ -299,16 +299,32 @@
const VkCommandBuffer* commandBuffers,
uint32_t signalCount,
const VkSemaphore* signalSemaphores,
- Protected protectedContext) {
+ Protected protectedContext,
+ MarkFrameBoundary markFrameBoundary,
+ uint64_t frameID) {
+ VkSubmitInfo submitInfo = {};
+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+
VkProtectedSubmitInfo protectedSubmitInfo = {};
if (protectedContext == Protected::kYes) {
protectedSubmitInfo.sType = VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO;
protectedSubmitInfo.protectedSubmit = VK_TRUE;
+
+ AddToPNextChain(&submitInfo, &protectedSubmitInfo);
}
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.pNext = protectedContext == Protected::kYes ? &protectedSubmitInfo : nullptr;
+
+ VkFrameBoundaryEXT frameBoundary;
+ if (markFrameBoundary == MarkFrameBoundary::kYes &&
+ sharedContext->vulkanCaps().supportsFrameBoundary()) {
+ memset(&frameBoundary, 0, sizeof(VkFrameBoundaryEXT));
+ frameBoundary.sType = VK_STRUCTURE_TYPE_FRAME_BOUNDARY_EXT;
+ frameBoundary.flags = VK_FRAME_BOUNDARY_FRAME_END_BIT_EXT;
+ frameBoundary.frameID = frameID;
+
+ AddToPNextChain(&submitInfo, &frameBoundary);
+ }
+
submitInfo.waitSemaphoreCount = waitCount;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
@@ -316,12 +332,13 @@
submitInfo.pCommandBuffers = commandBuffers;
submitInfo.signalSemaphoreCount = signalCount;
submitInfo.pSignalSemaphores = signalSemaphores;
+
VkResult result;
VULKAN_CALL_RESULT(sharedContext, result, QueueSubmit(queue, 1, &submitInfo, fence));
return result;
}
-bool VulkanCommandBuffer::submit(VkQueue queue) {
+bool VulkanCommandBuffer::submit(VkQueue queue, const SubmitInfo& submitInfo) {
this->end();
auto device = fSharedContext->device();
@@ -360,7 +377,9 @@
&fPrimaryCommandBuffer,
fSignalSemaphores.size(),
fSignalSemaphores.data(),
- this->isProtected());
+ this->isProtected(),
+ submitInfo.fMarkBoundary,
+ submitInfo.fFrameID);
fWaitSemaphores.clear();
fSignalSemaphores.clear();
if (submitResult != VK_SUCCESS) {
diff --git a/src/gpu/graphite/vk/VulkanCommandBuffer.h b/src/gpu/graphite/vk/VulkanCommandBuffer.h
index a9b51db..40445b1 100644
--- a/src/gpu/graphite/vk/VulkanCommandBuffer.h
+++ b/src/gpu/graphite/vk/VulkanCommandBuffer.h
@@ -32,7 +32,7 @@
bool setNewCommandBufferResources() override;
- bool submit(VkQueue);
+ bool submit(VkQueue, const SubmitInfo&);
bool isFinished();
diff --git a/src/gpu/graphite/vk/VulkanQueueManager.cpp b/src/gpu/graphite/vk/VulkanQueueManager.cpp
index ceebb76..a36f31e 100644
--- a/src/gpu/graphite/vk/VulkanQueueManager.cpp
+++ b/src/gpu/graphite/vk/VulkanQueueManager.cpp
@@ -49,11 +49,11 @@
}
};
-QueueManager::OutstandingSubmission VulkanQueueManager::onSubmitToGpu() {
+QueueManager::OutstandingSubmission VulkanQueueManager::onSubmitToGpu(const SubmitInfo& submitInfo) {
SkASSERT(fCurrentCommandBuffer);
VulkanCommandBuffer* vkCmdBuffer =
static_cast<VulkanCommandBuffer*>(fCurrentCommandBuffer.get());
- if (!vkCmdBuffer->submit(fQueue)) {
+ if (!vkCmdBuffer->submit(fQueue, submitInfo)) {
fCurrentCommandBuffer->callFinishedProcs(/*success=*/false);
return nullptr;
}
diff --git a/src/gpu/graphite/vk/VulkanQueueManager.h b/src/gpu/graphite/vk/VulkanQueueManager.h
index ba123d8..6330b9c 100644
--- a/src/gpu/graphite/vk/VulkanQueueManager.h
+++ b/src/gpu/graphite/vk/VulkanQueueManager.h
@@ -25,7 +25,7 @@
const VulkanSharedContext* vkSharedContext() const;
std::unique_ptr<CommandBuffer> getNewCommandBuffer(ResourceProvider*, Protected) override;
- OutstandingSubmission onSubmitToGpu() override;
+ OutstandingSubmission onSubmitToGpu(const SubmitInfo& submitInfo) override;
#if defined(GPU_TEST_UTILS)
// TODO: Implement these
diff --git a/src/gpu/vk/VulkanPreferredFeatures.cpp b/src/gpu/vk/VulkanPreferredFeatures.cpp
index 05b3cfb..b412263 100644
--- a/src/gpu/vk/VulkanPreferredFeatures.cpp
+++ b/src/gpu/vk/VulkanPreferredFeatures.cpp
@@ -159,6 +159,7 @@
// VK_EXT_sampler_filter_minmax samplerFilterMinmax
// VK_EXT_shader_viewport_index_layer shaderOutputViewportIndex, shaderOutputLayer
// VK_KHR_push_descriptor pushDescriptor
+ // VK_EXT_frame_boundary frameBoundaryEXT
bool fShaderDrawParametersKHR = false;
bool fDrawIndirectCountKHR = false;
bool fSamplerMirrorClampToEdgeKHR = false;
@@ -166,6 +167,7 @@
bool fSamplerFilterMinmaxEXT = false;
bool fShaderViewportIndexLayerEXT = false;
bool fPushDescriptorKHR = false;
+ bool fFrameBoundaryEXT = false;
};
void mark_device_extensions(DeviceExtensions& exts, const char* name) {
@@ -231,6 +233,8 @@
exts.fShaderViewportIndexLayerEXT = true;
} else if (strcmp(name, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) == 0) {
exts.fPushDescriptorKHR = true;
+ } else if (strcmp(name, VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME) == 0) {
+ exts.fFrameBoundaryEXT = true;
}
}
@@ -264,6 +268,7 @@
bool fMultisampledRenderToSingleSampled = true;
bool fHostImageCopy = true;
bool fPipelineCreationCacheControl = true;
+ bool fFrameBoundary = true;
};
FeaturesToAdd get_features_to_add(uint32_t apiVersion,
@@ -331,6 +336,7 @@
toAdd.fGraphicsPipelineLibrary = exts.fGraphicsPipelineLibraryEXT;
toAdd.fRGBA10x6Formats = exts.fRGBA10x6FormatsEXT;
toAdd.fMultisampledRenderToSingleSampled = exts.fMultisampledRenderToSingleSampledEXT;
+ toAdd.fFrameBoundary = exts.fFrameBoundaryEXT;
// Then, go over appFeatures::pNext and exclude features that are already being queried by the
// app.
@@ -391,6 +397,9 @@
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES:
toAdd.fPipelineCreationCacheControl = false;
break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT:
+ toAdd.fFrameBoundary = false;
+ break;
default:
break;
}
@@ -569,6 +578,9 @@
if (exts.fConservativeRasterizationEXT) {
fConservativeRasterizationExtension = VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME;
}
+ if (exts.fFrameBoundaryEXT) {
+ fFrameBoundary.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT;
+ }
// Inspect the list of features the app has already included and decide on which features to
// add.
@@ -647,6 +659,10 @@
SkASSERT(fPipelineCreationCacheControl.sType != 0);
AddToPNextChain(&appFeatures, &fPipelineCreationCacheControl);
}
+ if (toAdd.fFrameBoundary) {
+ SkASSERT(fFrameBoundary.sType != 0);
+ AddToPNextChain(&appFeatures, &fFrameBoundary);
+ }
fHasAddedFeaturesToQuery = true;
}
@@ -679,6 +695,7 @@
toAdd.fMultisampledRenderToSingleSampled = fMultisampledRenderToSingleSampled.sType != 0;
toAdd.fHostImageCopy = fHostImageCopy.sType != 0;
toAdd.fPipelineCreationCacheControl = fPipelineCreationCacheControl.sType != 0;
+ toAdd.fFrameBoundary = fFrameBoundary.sType != 0;
// Check which extensions are already enabled by the application.
DeviceExtensions exts;
@@ -744,6 +761,10 @@
appExtensions.push_back(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME);
exts.fPipelineCreationCacheControlEXT = true;
}
+ if (!exts.fFrameBoundaryEXT && toAdd.fFrameBoundary) {
+ appExtensions.push_back(VK_EXT_FRAME_BOUNDARY_EXTENSION_NAME);
+ exts.fFrameBoundaryEXT = true;
+ }
if (!exts.fDriverPropertiesKHR && fDriverPropertiesExtension != nullptr) {
appExtensions.push_back(fDriverPropertiesExtension);
exts.fDriverPropertiesKHR = true;
@@ -1763,6 +1784,17 @@
}
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT: {
+ chain(newChainEnd, pNext);
+ if (exts.fFrameBoundaryEXT) {
+ auto* features =
+ reinterpret_cast<VkPhysicalDeviceFrameBoundaryFeaturesEXT*>(
+ pNext);
+ features->frameBoundary = VK_TRUE;
+ }
+ toAdd.fFrameBoundary = false;
+ break;
+ }
default:
// Retain everything else that's chained.
@@ -1829,6 +1861,9 @@
if (toAdd.fPipelineCreationCacheControl) {
chain(newChainEnd, &fPipelineCreationCacheControl);
}
+ if (toAdd.fFrameBoundary) {
+ chain(newChainEnd, &fFrameBoundary);
+ }
// Replace appFeatures' pNext with the new chain.
*newChainEnd = nullptr;
diff --git a/tests/VkPreferredFeaturesTest.cpp b/tests/VkPreferredFeaturesTest.cpp
index 668cb75..0e3c963 100644
--- a/tests/VkPreferredFeaturesTest.cpp
+++ b/tests/VkPreferredFeaturesTest.cpp
@@ -59,6 +59,7 @@
bool fSamplerFilterMinmaxEXT = true;
bool fShaderViewportIndexLayerEXT = true;
bool fPushDescriptorKHR = true;
+ bool fFrameBoundaryEXT = true;
};
static std::vector<VkExtensionProperties> get_device_exts(const VulkanExts& config) {
@@ -103,6 +104,7 @@
ADD_EXT(fSamplerFilterMinmaxEXT, VK_EXT_SAMPLER_FILTER_MINMAX);
ADD_EXT(fShaderViewportIndexLayerEXT, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER);
ADD_EXT(fPushDescriptorKHR, VK_KHR_PUSH_DESCRIPTOR);
+ ADD_EXT(fFrameBoundaryEXT, VK_EXT_FRAME_BOUNDARY);
#undef ADD_EXT
return exts;
}
@@ -219,6 +221,10 @@
PipelineCreationCacheControlFeatures,
SET_IF(fPipelineCreationCacheControlEXT, pipelineCreationCacheControl))
+ SET_FEATURES(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ SET_IF(fFrameBoundaryEXT, frameBoundary))
+
default:
break;
}
@@ -401,6 +407,7 @@
CHECK_EXT_DISABLED(VK_EXT_SAMPLER_FILTER_MINMAX);
CHECK_EXT_DISABLED(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER);
CHECK_EXT_DISABLED(VK_KHR_PUSH_DESCRIPTOR);
+ CHECK_EXT_ENABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_FEATURE_ENABLED(RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT,
RasterizationOrderAttachmentAccessFeaturesEXT,
@@ -463,6 +470,10 @@
CHECK_FEATURE_ENABLED(PIPELINE_CREATION_CACHE_CONTROL_FEATURES,
PipelineCreationCacheControlFeatures,
pipelineCreationCacheControl);
+
+ CHECK_FEATURE_ENABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
// A test where the application adds no features and extensions and lets Skia choose them. Uses
@@ -527,6 +538,7 @@
CHECK_EXT_DISABLED(VK_EXT_SAMPLER_FILTER_MINMAX);
CHECK_EXT_DISABLED(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER);
CHECK_EXT_DISABLED(VK_KHR_PUSH_DESCRIPTOR);
+ CHECK_EXT_ENABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_EXCLUSIVE(VULKAN_1_1_FEATURES, 16BIT_STORAGE_FEATURES);
CHECK_EXCLUSIVE(VULKAN_1_1_FEATURES, MULTIVIEW_FEATURES);
@@ -619,6 +631,10 @@
CHECK_FEATURE_ENABLED(PIPELINE_CREATION_CACHE_CONTROL_FEATURES,
PipelineCreationCacheControlFeatures,
pipelineCreationCacheControl);
+
+ CHECK_FEATURE_ENABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
// A test where the application adds no features and extensions and lets Skia choose them. Uses
@@ -683,6 +699,7 @@
CHECK_EXT_DISABLED(VK_EXT_SAMPLER_FILTER_MINMAX);
CHECK_EXT_DISABLED(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER);
CHECK_EXT_DISABLED(VK_KHR_PUSH_DESCRIPTOR);
+ CHECK_EXT_ENABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_EXCLUSIVE(VULKAN_1_1_FEATURES, 16BIT_STORAGE_FEATURES);
CHECK_EXCLUSIVE(VULKAN_1_1_FEATURES, MULTIVIEW_FEATURES);
@@ -790,6 +807,10 @@
CHECK_FEATURE_DISABLED(PIPELINE_CREATION_CACHE_CONTROL_FEATURES,
PipelineCreationCacheControlFeatures,
pipelineCreationCacheControl);
+
+ CHECK_FEATURE_ENABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
// A test where the application adds no features and extensions and lets Skia choose them. Uses
@@ -854,6 +875,7 @@
CHECK_EXT_DISABLED(VK_EXT_SAMPLER_FILTER_MINMAX);
CHECK_EXT_DISABLED(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER);
CHECK_EXT_DISABLED(VK_KHR_PUSH_DESCRIPTOR);
+ CHECK_EXT_ENABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_EXCLUSIVE(VULKAN_1_1_FEATURES, 16BIT_STORAGE_FEATURES);
CHECK_EXCLUSIVE(VULKAN_1_1_FEATURES, MULTIVIEW_FEATURES);
@@ -976,6 +998,10 @@
CHECK_FEATURE_DISABLED(PIPELINE_CREATION_CACHE_CONTROL_FEATURES,
PipelineCreationCacheControlFeatures,
pipelineCreationCacheControl);
+
+ CHECK_FEATURE_ENABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
#define CHAIN(STRUCT_NAME, StructName, Feature) \
@@ -1003,6 +1029,7 @@
config.fGraphicsPipelineLibraryEXT = false;
config.fExtendedDynamicState2EXT = false;
config.fCreateRenderpass2KHR = false;
+ config.fFrameBoundaryEXT = false;
const std::vector<VkExtensionProperties> exts = get_device_exts(config);
@@ -1074,6 +1101,7 @@
CHECK_EXT_ENABLED(VK_EXT_SUBGROUP_SIZE_CONTROL);
CHECK_EXT_ENABLED(VK_KHR_MAINTENANCE_4);
CHECK_EXT_ENABLED(VK_KHR_PUSH_DESCRIPTOR);
+ CHECK_EXT_DISABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_FEATURE_ENABLED(RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT,
RasterizationOrderAttachmentAccessFeaturesEXT,
@@ -1141,6 +1169,10 @@
CHECK_FEATURE_ENABLED(SHADER_OBJECT_FEATURES_EXT, ShaderObjectFeaturesEXT, shaderObject);
CHECK_FEATURE_ENABLED(MAINTENANCE_5_FEATURES, Maintenance5Features, maintenance5);
CHECK_FEATURE_ENABLED(HOST_IMAGE_COPY_FEATURES, HostImageCopyFeatures, hostImageCopy);
+
+ CHECK_FEATURE_DISABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
// A test where the application adds some features and extensions and lets Skia add to them. At the
@@ -1154,6 +1186,7 @@
config.fVertexInputDynamicStateEXT = false;
config.fExtendedDynamicStateEXT = false;
config.fExtendedDynamicState2EXT = false;
+ config.fFrameBoundaryEXT = false;
const std::vector<VkExtensionProperties> exts = get_device_exts(config);
@@ -1237,6 +1270,7 @@
CHECK_EXT_ENABLED(VK_KHR_SHADER_DRAW_PARAMETERS);
CHECK_EXT_ENABLED(VK_EXT_DESCRIPTOR_INDEXING);
CHECK_EXT_ENABLED(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE);
+ CHECK_EXT_DISABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_FEATURE_ENABLED(VULKAN_1_1_FEATURES, Vulkan11Features, samplerYcbcrConversion);
CHECK_FEATURE_ENABLED(VULKAN_1_1_FEATURES, Vulkan11Features, shaderDrawParameters);
@@ -1351,6 +1385,10 @@
CHECK_FEATURE_ENABLED(PIPELINE_CREATION_CACHE_CONTROL_FEATURES,
PipelineCreationCacheControlFeatures,
pipelineCreationCacheControl);
+
+ CHECK_FEATURE_DISABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
// A test where the application adds some features and extensions and lets Skia add to them. At the
@@ -1459,6 +1497,7 @@
CHECK_EXT_ENABLED(VK_KHR_SHADER_DRAW_PARAMETERS);
CHECK_EXT_ENABLED(VK_EXT_DESCRIPTOR_INDEXING);
CHECK_EXT_ENABLED(VK_KHR_DYNAMIC_RENDERING);
+ CHECK_EXT_ENABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_FEATURE_ENABLED(VULKAN_1_1_FEATURES, Vulkan11Features, multiview);
CHECK_FEATURE_DISABLED(VULKAN_1_1_FEATURES, Vulkan11Features, samplerYcbcrConversion);
@@ -1562,6 +1601,10 @@
// Features enabled by the app must remain enabled
CHECK_FEATURE_ENABLED(SHADER_OBJECT_FEATURES_EXT, ShaderObjectFeaturesEXT, shaderObject);
+
+ CHECK_FEATURE_ENABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
// A test where the application adds some features and extensions and lets Skia add to them. At the
@@ -1660,6 +1703,7 @@
CHECK_EXT_ENABLED(VK_EXT_SHADER_OBJECT);
CHECK_EXT_ENABLED(VK_EXT_DESCRIPTOR_INDEXING);
CHECK_EXT_ENABLED(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ);
+ CHECK_EXT_ENABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_FEATURE_ENABLED(VULKAN_1_1_FEATURES, Vulkan11Features, samplerYcbcrConversion);
CHECK_FEATURE_DISABLED(VULKAN_1_1_FEATURES, Vulkan11Features, shaderDrawParameters);
@@ -1715,6 +1759,11 @@
// Features enabled by the app must remain enabled
CHECK_FEATURE_ENABLED(SHADER_OBJECT_FEATURES_EXT, ShaderObjectFeaturesEXT, shaderObject);
+
+
+ CHECK_FEATURE_ENABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
// A similar test to VkPreferredFeaturesTest_CustomVulkan*, except the chain passed to
@@ -1726,6 +1775,7 @@
config.fGraphicsPipelineLibraryEXT = false;
config.fPipelineLibraryKHR = false;
config.fBlendOperationAdvancedEXT = false;
+ config.fFrameBoundaryEXT = false;
const std::vector<VkExtensionProperties> exts = get_device_exts(config);
@@ -1811,6 +1861,7 @@
CHECK_EXT_ENABLED(VK_KHR_MAINTENANCE_5);
CHECK_EXT_ENABLED(VK_KHR_PUSH_DESCRIPTOR);
CHECK_EXT_ENABLED(VK_EXT_SHADER_OBJECT);
+ CHECK_EXT_DISABLED(VK_EXT_FRAME_BOUNDARY);
CHECK_FEATURE_ENABLED(VULKAN_1_1_FEATURES, Vulkan11Features, samplerYcbcrConversion);
CHECK_FEATURE_DISABLED(VULKAN_1_1_FEATURES, Vulkan11Features, shaderDrawParameters);
@@ -1864,6 +1915,10 @@
// Features enabled by the app must remain enabled
CHECK_FEATURE_ENABLED(SHADER_OBJECT_FEATURES_EXT, ShaderObjectFeaturesEXT, shaderObject);
CHECK_FEATURE_ENABLED(MAINTENANCE_5_FEATURES, Maintenance5Features, maintenance5);
+
+ CHECK_FEATURE_DISABLED(FRAME_BOUNDARY_FEATURES_EXT,
+ FrameBoundaryFeaturesEXT,
+ frameBoundary);
}
#endif