Add support for vk image sharing mode and handle queues xfers correctly.
Change-Id: I9dbe6020d67cc452c9cbbdeace68f1d01275b419
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293559
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 8f2eb25..e170cad 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -9,6 +9,9 @@
* <insert new release notes here>
+ * Add VkSharingMode field to GrVkImageInfo.
+ https://review.skia.org/293559
+
* Move SkBitmapRegionDecoder into client_utils/android.
* Remove SkSurface::MakeFromBackendTextureAsRenderTarget.
diff --git a/include/gpu/vk/GrVkTypes.h b/include/gpu/vk/GrVkTypes.h
index 784930b..e869238 100644
--- a/include/gpu/vk/GrVkTypes.h
+++ b/include/gpu/vk/GrVkTypes.h
@@ -149,6 +149,12 @@
VkFormatFeatureFlags fFormatFeatures;
};
+/*
+ * When wrapping a GrBackendTexture or GrBackendRendenderTarget, the fCurrentQueueFamily should
+ * either be VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_EXTERNAL, or VK_QUEUE_FAMILY_FOREIGN_EXT. If
+ * fSharingMode is VK_SHARING_MODE_EXCLUSIVE then fCurrentQueueFamily can also be the graphics
+ * queue index passed into Skia.
+ */
struct GrVkImageInfo {
VkImage fImage;
GrVkAlloc fAlloc;
@@ -159,6 +165,7 @@
uint32_t fCurrentQueueFamily;
GrProtected fProtected;
GrVkYcbcrConversionInfo fYcbcrConversionInfo;
+ VkSharingMode fSharingMode;
GrVkImageInfo()
: fImage(VK_NULL_HANDLE)
@@ -169,7 +176,8 @@
, fLevelCount(0)
, fCurrentQueueFamily(VK_QUEUE_FAMILY_IGNORED)
, fProtected(GrProtected::kNo)
- , fYcbcrConversionInfo() {}
+ , fYcbcrConversionInfo()
+ , fSharingMode(VK_SHARING_MODE_EXCLUSIVE) {}
GrVkImageInfo(VkImage image,
GrVkAlloc alloc,
@@ -179,7 +187,8 @@
uint32_t levelCount,
uint32_t currentQueueFamily = VK_QUEUE_FAMILY_IGNORED,
GrProtected isProtected = GrProtected::kNo,
- GrVkYcbcrConversionInfo ycbcrConversionInfo = GrVkYcbcrConversionInfo())
+ GrVkYcbcrConversionInfo ycbcrConversionInfo = GrVkYcbcrConversionInfo(),
+ VkSharingMode sharingMode = VK_SHARING_MODE_EXCLUSIVE)
: fImage(image)
, fAlloc(alloc)
, fImageTiling(imageTiling)
@@ -188,7 +197,8 @@
, fLevelCount(levelCount)
, fCurrentQueueFamily(currentQueueFamily)
, fProtected(isProtected)
- , fYcbcrConversionInfo(ycbcrConversionInfo) {}
+ , fYcbcrConversionInfo(ycbcrConversionInfo)
+ , fSharingMode(sharingMode) {}
GrVkImageInfo(const GrVkImageInfo& info, VkImageLayout layout, uint32_t familyQueueIndex)
: fImage(info.fImage)
@@ -199,7 +209,8 @@
, fLevelCount(info.fLevelCount)
, fCurrentQueueFamily(familyQueueIndex)
, fProtected(info.fProtected)
- , fYcbcrConversionInfo(info.fYcbcrConversionInfo) {}
+ , fYcbcrConversionInfo(info.fYcbcrConversionInfo)
+ , fSharingMode(info.fSharingMode) {}
#if GR_TEST_UTILS
bool operator==(const GrVkImageInfo& that) const {
@@ -207,7 +218,8 @@
fImageTiling == that.fImageTiling && fImageLayout == that.fImageLayout &&
fFormat == that.fFormat && fLevelCount == that.fLevelCount &&
fCurrentQueueFamily == that.fCurrentQueueFamily && fProtected == that.fProtected &&
- fYcbcrConversionInfo == that.fYcbcrConversionInfo;
+ fYcbcrConversionInfo == that.fYcbcrConversionInfo &&
+ fSharingMode == that.fSharingMode;
}
#endif
};
diff --git a/src/gpu/GrAHardwareBufferUtils.cpp b/src/gpu/GrAHardwareBufferUtils.cpp
index b701daf..badb8ee 100644
--- a/src/gpu/GrAHardwareBufferUtils.cpp
+++ b/src/gpu/GrAHardwareBufferUtils.cpp
@@ -486,6 +486,7 @@
// "foreign" device we can leave them as external.
imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
imageInfo.fYcbcrConversionInfo = *ycbcrConversion;
+ imageInfo.fSharingMode = imageCreateInfo.sharingMode;
*deleteProc = delete_vk_image;
*updateProc = update_vk_image;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 97d819f..c8ee2c7 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1198,7 +1198,8 @@
static bool check_image_info(const GrVkCaps& caps,
const GrVkImageInfo& info,
- bool needsAllocation) {
+ bool needsAllocation,
+ uint32_t graphicsQueueIndex) {
if (VK_NULL_HANDLE == info.fImage) {
return false;
}
@@ -1211,6 +1212,18 @@
return false;
}
+ if (info.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
+ info.fCurrentQueueFamily != VK_QUEUE_FAMILY_EXTERNAL &&
+ info.fCurrentQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) {
+ if (info.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
+ if (info.fCurrentQueueFamily != graphicsQueueIndex) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+
if (info.fYcbcrConversionInfo.isValid()) {
if (!caps.supportsYcbcrConversion()) {
return false;
@@ -1256,7 +1269,8 @@
return nullptr;
}
- if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) {
+ if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership,
+ this->queueIndex())) {
return nullptr;
}
@@ -1282,7 +1296,8 @@
return nullptr;
}
- if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) {
+ if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership,
+ this->queueIndex())) {
return nullptr;
}
@@ -1309,7 +1324,8 @@
return nullptr;
}
- if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) {
+ if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership,
+ this->queueIndex())) {
return nullptr;
}
@@ -1349,7 +1365,7 @@
return nullptr;
}
- if (!check_image_info(this->vkCaps(), info, false)) {
+ if (!check_image_info(this->vkCaps(), info, false, this->queueIndex())) {
return nullptr;
}
@@ -1382,7 +1398,7 @@
if (!tex.getVkImageInfo(&imageInfo)) {
return nullptr;
}
- if (!check_image_info(this->vkCaps(), imageInfo, false)) {
+ if (!check_image_info(this->vkCaps(), imageInfo, false, this->queueIndex())) {
return nullptr;
}
diff --git a/src/gpu/vk/GrVkImage.cpp b/src/gpu/vk/GrVkImage.cpp
index 9b50ca7..1270743 100644
--- a/src/gpu/vk/GrVkImage.cpp
+++ b/src/gpu/vk/GrVkImage.cpp
@@ -13,6 +13,43 @@
#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
+GrVkImage::GrVkImage(const GrVkGpu* gpu,
+ const GrVkImageInfo& info,
+ sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
+ GrBackendObjectOwnership ownership,
+ bool forSecondaryCB)
+ : fInfo(info)
+ , fInitialQueueFamily(info.fCurrentQueueFamily)
+ , fMutableState(std::move(mutableState))
+ , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) {
+ SkASSERT(fMutableState->getImageLayout() == fInfo.fImageLayout);
+ SkASSERT(fMutableState->getQueueFamilyIndex() == fInfo.fCurrentQueueFamily);
+#ifdef SK_DEBUG
+ // We can't transfer from the non graphics queue to the graphics queue since we can't
+ // release the image from the original queue without having that queue. This limits us in terms
+ // of the types of queue indices we can handle.
+ if (info.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
+ info.fCurrentQueueFamily != VK_QUEUE_FAMILY_EXTERNAL &&
+ info.fCurrentQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) {
+ if (info.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
+ if (info.fCurrentQueueFamily != gpu->queueIndex()) {
+ SkASSERT(false);
+ }
+ } else {
+ SkASSERT(false);
+ }
+ }
+#endif
+ if (forSecondaryCB) {
+ fResource = nullptr;
+ } else if (fIsBorrowed) {
+ fResource = new BorrowedResource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
+ } else {
+ SkASSERT(VK_NULL_HANDLE != info.fAlloc.fMemory);
+ fResource = new Resource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
+ }
+}
+
VkPipelineStageFlags GrVkImage::LayoutToPipelineSrcStageFlags(const VkImageLayout layout) {
if (VK_IMAGE_LAYOUT_GENERAL == layout) {
return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
@@ -116,15 +153,22 @@
uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
if (this->currentQueueFamilyIndex() != VK_QUEUE_FAMILY_IGNORED &&
- gpu->queueIndex() != this->currentQueueFamilyIndex()) {
+ this->currentQueueFamilyIndex() != gpu->queueIndex()) {
// The image still is owned by its original queue family and we need to transfer it into
// ours.
SkASSERT(!releaseFamilyQueue);
SkASSERT(this->currentQueueFamilyIndex() == fInitialQueueFamily);
-
+ // We only support transferring from external or foreign queues here and not arbitrary
+ // ones.
+ SkASSERT(this->currentQueueFamilyIndex() == VK_QUEUE_FAMILY_EXTERNAL ||
+ this->currentQueueFamilyIndex() == VK_QUEUE_FAMILY_FOREIGN_EXT);
srcQueueFamilyIndex = this->currentQueueFamilyIndex();
- dstQueueFamilyIndex = gpu->queueIndex();
- this->setQueueFamilyIndex(gpu->queueIndex());
+ if (fInfo.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) {
+ dstQueueFamilyIndex = gpu->queueIndex();
+ } else {
+ dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ }
+ this->setQueueFamilyIndex(dstQueueFamilyIndex);
} else if (releaseFamilyQueue) {
// We are releasing the image so we must transfer the image back to its original queue
// family.
@@ -217,6 +261,7 @@
info->fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
info->fProtected =
(createflags & VK_IMAGE_CREATE_PROTECTED_BIT) ? GrProtected::kYes : GrProtected::kNo;
+ info->fSharingMode = VK_SHARING_MODE_EXCLUSIVE;
return true;
}
diff --git a/src/gpu/vk/GrVkImage.h b/src/gpu/vk/GrVkImage.h
index 4ff3e7e..d7657dc 100644
--- a/src/gpu/vk/GrVkImage.h
+++ b/src/gpu/vk/GrVkImage.h
@@ -29,22 +29,8 @@
const GrVkImageInfo& info,
sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
GrBackendObjectOwnership ownership,
- bool forSecondaryCB = false)
- : fInfo(info)
- , fInitialQueueFamily(info.fCurrentQueueFamily)
- , fMutableState(std::move(mutableState))
- , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) {
- SkASSERT(fMutableState->getImageLayout() == fInfo.fImageLayout);
- SkASSERT(fMutableState->getQueueFamilyIndex() == fInfo.fCurrentQueueFamily);
- if (forSecondaryCB) {
- fResource = nullptr;
- } else if (fIsBorrowed) {
- fResource = new BorrowedResource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
- } else {
- SkASSERT(VK_NULL_HANDLE != info.fAlloc.fMemory);
- fResource = new Resource(gpu, info.fImage, info.fAlloc, info.fImageTiling);
- }
- }
+ bool forSecondaryCB = false);
+
virtual ~GrVkImage();
VkImage image() const {
diff --git a/tools/sk_app/VulkanWindowContext.cpp b/tools/sk_app/VulkanWindowContext.cpp
index b65de09..593d60c 100644
--- a/tools/sk_app/VulkanWindowContext.cpp
+++ b/tools/sk_app/VulkanWindowContext.cpp
@@ -317,12 +317,14 @@
fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
}
- this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
+ this->createBuffers(swapchainCreateInfo.imageFormat, colorType,
+ swapchainCreateInfo.imageSharingMode);
return true;
}
-void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
+void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType,
+ VkSharingMode sharingMode) {
fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
SkASSERT(fImageCount);
fImages = new VkImage[fImageCount];
@@ -342,6 +344,7 @@
info.fFormat = format;
info.fLevelCount = 1;
info.fCurrentQueueFamily = fPresentQueueIndex;
+ info.fSharingMode = sharingMode;
if (fSampleCount == 1) {
GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
diff --git a/tools/sk_app/VulkanWindowContext.h b/tools/sk_app/VulkanWindowContext.h
index 2db9e79..5e245af 100644
--- a/tools/sk_app/VulkanWindowContext.h
+++ b/tools/sk_app/VulkanWindowContext.h
@@ -61,7 +61,7 @@
BackbufferInfo* getAvailableBackbuffer();
bool createSwapchain(int width, int height, const DisplayParams& params);
- void createBuffers(VkFormat format, SkColorType colorType);
+ void createBuffers(VkFormat format, SkColorType colorType, VkSharingMode);
void destroyBuffers();
VkInstance fInstance = VK_NULL_HANDLE;