Commit 69e46942 by Michael Spang Committed by Commit Bot

Vulkan: Add semaphores test to VulkanExternalImageTest

Add a more substantial test that uses semaphores to VulkanExternalImageTest. It's still just a clear in GL, which exposed a bug that a staged clear wasn't be flushed by a call to glSignalSemaphoreEXT. Bug: angleproject:3289 Change-Id: Id938eaf2c8c20cb0ae9fb948fbfcf3448980b577 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2195684 Commit-Queue: Michael Spang <spang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 7c6a30c2
......@@ -193,6 +193,8 @@ angle::Result SemaphoreVk::signal(gl::Context *context,
layout = image.getCurrentImageLayout();
}
ANGLE_TRY(textureVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
vk::CommandBuffer *commandBuffer;
ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
......
......@@ -374,6 +374,252 @@ TEST_P(VulkanExternalImageTest, TextureFormatCompatChromiumZirconHandle)
}
}
// Test creating and clearing RGBA8 texture in opaque fd with acquire/release.
TEST_P(VulkanExternalImageTest, ShouldClearOpaqueFdWithSemaphores)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_memory_object_fd"));
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_semaphore_fd"));
VulkanExternalHelper helper;
helper.initialize(isSwiftshader());
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
ANGLE_SKIP_TEST_IF(
!helper.canCreateImageOpaqueFd(format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL));
ANGLE_SKIP_TEST_IF(!helper.canCreateSemaphoreOpaqueFd());
VkSemaphore vkAcquireSemaphore = VK_NULL_HANDLE;
VkResult result = helper.createSemaphoreOpaqueFd(&vkAcquireSemaphore);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_TRUE(vkAcquireSemaphore != VK_NULL_HANDLE);
VkSemaphore vkReleaseSemaphore = VK_NULL_HANDLE;
result = helper.createSemaphoreOpaqueFd(&vkReleaseSemaphore);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_TRUE(vkReleaseSemaphore != VK_NULL_HANDLE);
int acquireSemaphoreFd = kInvalidFd;
result = helper.exportSemaphoreOpaqueFd(vkAcquireSemaphore, &acquireSemaphoreFd);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(acquireSemaphoreFd, kInvalidFd);
int releaseSemaphoreFd = kInvalidFd;
result = helper.exportSemaphoreOpaqueFd(vkReleaseSemaphore, &releaseSemaphoreFd);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(releaseSemaphoreFd, kInvalidFd);
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
VkDeviceSize deviceMemorySize = 0;
VkExtent3D extent = {1, 1, 1};
result = helper.createImage2DOpaqueFd(format, extent, &image, &deviceMemory, &deviceMemorySize);
EXPECT_EQ(result, VK_SUCCESS);
int memoryFd = kInvalidFd;
result = helper.exportMemoryOpaqueFd(deviceMemory, &memoryFd);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(memoryFd, kInvalidFd);
{
GLMemoryObject memoryObject;
GLint dedicatedMemory = GL_TRUE;
glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT,
&dedicatedMemory);
glImportMemoryFdEXT(memoryObject, deviceMemorySize, GL_HANDLE_TYPE_OPAQUE_FD_EXT, memoryFd);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0);
GLSemaphore glAcquireSemaphore;
glImportSemaphoreFdEXT(glAcquireSemaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT,
acquireSemaphoreFd);
helper.releaseImageAndSignalSemaphore(image, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL, vkAcquireSemaphore);
const GLuint barrierTextures[] = {
texture,
};
constexpr uint32_t textureBarriersCount = std::extent<decltype(barrierTextures)>();
const GLenum textureSrcLayouts[] = {
GL_LAYOUT_GENERAL_EXT,
};
constexpr uint32_t textureSrcLayoutsCount = std::extent<decltype(textureSrcLayouts)>();
static_assert(textureBarriersCount == textureSrcLayoutsCount,
"barrierTextures and textureSrcLayouts must be the same length");
glWaitSemaphoreEXT(glAcquireSemaphore, 0, nullptr, textureBarriersCount, barrierTextures,
textureSrcLayouts);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
GLSemaphore glReleaseSemaphore;
glImportSemaphoreFdEXT(glReleaseSemaphore, GL_HANDLE_TYPE_OPAQUE_FD_EXT,
releaseSemaphoreFd);
const GLenum textureDstLayouts[] = {
GL_LAYOUT_TRANSFER_SRC_EXT,
};
constexpr uint32_t textureDstLayoutsCount = std::extent<decltype(textureSrcLayouts)>();
static_assert(textureBarriersCount == textureDstLayoutsCount,
"barrierTextures and textureDstLayouts must be the same length");
glSignalSemaphoreEXT(glReleaseSemaphore, 0, nullptr, textureBarriersCount, barrierTextures,
textureDstLayouts);
helper.waitSemaphoreAndAcquireImage(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
vkReleaseSemaphore);
uint8_t pixels[4];
VkOffset3D offset = {};
VkExtent3D extent = {1, 1, 1};
helper.readPixels(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, format, offset, extent,
pixels, sizeof(pixels));
EXPECT_NEAR(0x80, pixels[0], 1);
EXPECT_NEAR(0x80, pixels[1], 1);
EXPECT_NEAR(0x80, pixels[2], 1);
EXPECT_NEAR(0x80, pixels[3], 1);
}
EXPECT_GL_NO_ERROR();
vkDeviceWaitIdle(helper.getDevice());
vkDestroyImage(helper.getDevice(), image, nullptr);
vkDestroySemaphore(helper.getDevice(), vkAcquireSemaphore, nullptr);
vkDestroySemaphore(helper.getDevice(), vkReleaseSemaphore, nullptr);
vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
}
// Test creating and clearing RGBA8 texture in zircon vmo with acquire/release.
TEST_P(VulkanExternalImageTest, ShouldClearZirconVmoWithSemaphores)
{
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_memory_object_fuchsia"));
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_ANGLE_semaphore_fuchsia"));
VulkanExternalHelper helper;
helper.initialize(isSwiftshader());
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM;
ANGLE_SKIP_TEST_IF(
!helper.canCreateImageZirconVmo(format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL));
ANGLE_SKIP_TEST_IF(!helper.canCreateSemaphoreZirconEvent());
VkSemaphore vkAcquireSemaphore = VK_NULL_HANDLE;
VkResult result = helper.createSemaphoreZirconEvent(&vkAcquireSemaphore);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_TRUE(vkAcquireSemaphore != VK_NULL_HANDLE);
VkSemaphore vkReleaseSemaphore = VK_NULL_HANDLE;
result = helper.createSemaphoreZirconEvent(&vkReleaseSemaphore);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_TRUE(vkReleaseSemaphore != VK_NULL_HANDLE);
zx_handle_t acquireSemaphoreHandle = ZX_HANDLE_INVALID;
result = helper.exportSemaphoreZirconEvent(vkAcquireSemaphore, &acquireSemaphoreHandle);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(acquireSemaphoreHandle, ZX_HANDLE_INVALID);
zx_handle_t releaseSemaphoreHandle = ZX_HANDLE_INVALID;
result = helper.exportSemaphoreZirconEvent(vkReleaseSemaphore, &releaseSemaphoreHandle);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(releaseSemaphoreHandle, ZX_HANDLE_INVALID);
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
VkDeviceSize deviceMemorySize = 0;
VkExtent3D extent = {1, 1, 1};
result =
helper.createImage2DZirconVmo(format, extent, &image, &deviceMemory, &deviceMemorySize);
EXPECT_EQ(result, VK_SUCCESS);
zx_handle_t memoryHandle = ZX_HANDLE_INVALID;
result = helper.exportMemoryZirconVmo(deviceMemory, &memoryHandle);
EXPECT_EQ(result, VK_SUCCESS);
EXPECT_NE(memoryHandle, ZX_HANDLE_INVALID);
{
GLMemoryObject memoryObject;
GLint dedicatedMemory = GL_TRUE;
glMemoryObjectParameterivEXT(memoryObject, GL_DEDICATED_MEMORY_OBJECT_EXT,
&dedicatedMemory);
glImportMemoryZirconHandleANGLE(memoryObject, deviceMemorySize,
GL_HANDLE_TYPE_ZIRCON_VMO_ANGLE, memoryHandle);
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorageMem2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1, memoryObject, 0);
GLSemaphore glAcquireSemaphore;
glImportSemaphoreZirconHandleANGLE(glAcquireSemaphore, GL_HANDLE_TYPE_ZIRCON_EVENT_ANGLE,
acquireSemaphoreHandle);
helper.releaseImageAndSignalSemaphore(image, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL, vkAcquireSemaphore);
const GLuint barrierTextures[] = {
texture,
};
constexpr uint32_t textureBarriersCount = std::extent<decltype(barrierTextures)>();
const GLenum textureSrcLayouts[] = {
GL_LAYOUT_GENERAL_EXT,
};
constexpr uint32_t textureSrcLayoutsCount = std::extent<decltype(textureSrcLayouts)>();
static_assert(textureBarriersCount == textureSrcLayoutsCount,
"barrierTextures and textureSrcLayouts must be the same length");
glWaitSemaphoreEXT(glAcquireSemaphore, 0, nullptr, textureBarriersCount, barrierTextures,
textureSrcLayouts);
GLFramebuffer framebuffer;
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
GLSemaphore glReleaseSemaphore;
glImportSemaphoreZirconHandleANGLE(glReleaseSemaphore, GL_HANDLE_TYPE_ZIRCON_EVENT_ANGLE,
releaseSemaphoreHandle);
const GLenum textureDstLayouts[] = {
GL_LAYOUT_TRANSFER_SRC_EXT,
};
constexpr uint32_t textureDstLayoutsCount = std::extent<decltype(textureSrcLayouts)>();
static_assert(textureBarriersCount == textureDstLayoutsCount,
"barrierTextures and textureDstLayouts must be the same length");
glSignalSemaphoreEXT(glReleaseSemaphore, 0, nullptr, textureBarriersCount, barrierTextures,
textureDstLayouts);
helper.waitSemaphoreAndAcquireImage(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
vkReleaseSemaphore);
uint8_t pixels[4];
VkOffset3D offset = {};
VkExtent3D extent = {1, 1, 1};
helper.readPixels(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, format, offset, extent,
pixels, sizeof(pixels));
EXPECT_NEAR(0x80, pixels[0], 1);
EXPECT_NEAR(0x80, pixels[1], 1);
EXPECT_NEAR(0x80, pixels[2], 1);
EXPECT_NEAR(0x80, pixels[3], 1);
}
EXPECT_GL_NO_ERROR();
vkDeviceWaitIdle(helper.getDevice());
vkDestroyImage(helper.getDevice(), image, nullptr);
vkDestroySemaphore(helper.getDevice(), vkAcquireSemaphore, nullptr);
vkDestroySemaphore(helper.getDevice(), vkReleaseSemaphore, nullptr);
vkFreeMemory(helper.getDevice(), deviceMemory, nullptr);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(VulkanExternalImageTest);
......
......@@ -117,6 +117,41 @@ uint32_t FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProperties
return UINT32_MAX;
}
void ImageMemoryBarrier(VkCommandBuffer commandBuffer,
VkImage image,
uint32_t srcQueueFamilyIndex,
uint32_t dstQueueFamilyIndex,
VkImageLayout oldLayout,
VkImageLayout newLayout)
{
const VkImageMemoryBarrier imageMemoryBarriers[] = {
/* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
/* .pNext = */ nullptr,
/* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,
/* .dstAccessMask = */ VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
/* .oldLayout = */ oldLayout,
/* .newLayout = */ newLayout,
/* .srcQueueFamilyIndex = */ srcQueueFamilyIndex,
/* .dstQueueFamilyIndex = */ dstQueueFamilyIndex,
/* .image = */ image,
/* .subresourceRange = */
{
/* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,
/* .basicMiplevel = */ 0,
/* .levelCount = */ 1,
/* .baseArrayLayer = */ 0,
/* .layerCount = */ 1,
}}};
const uint32_t imageMemoryBarrierCount = std::extent<decltype(imageMemoryBarriers)>();
constexpr VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
constexpr VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
const VkDependencyFlags dependencyFlags = 0;
vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags, 0, nullptr, 0,
nullptr, imageMemoryBarrierCount, imageMemoryBarriers);
}
} // namespace
VulkanExternalHelper::VulkanExternalHelper() {}
......@@ -126,6 +161,15 @@ VulkanExternalHelper::~VulkanExternalHelper()
if (mDevice != VK_NULL_HANDLE)
{
vkDeviceWaitIdle(mDevice);
}
if (mCommandPool != VK_NULL_HANDLE)
{
vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
}
if (mDevice != VK_NULL_HANDLE)
{
vkDestroyDevice(mDevice, nullptr);
mDevice = VK_NULL_HANDLE;
......@@ -289,6 +333,15 @@ void VulkanExternalHelper::initialize(bool useSwiftshader, bool enableValidation
vkGetDeviceQueue(mDevice, mGraphicsQueueFamilyIndex, kGraphicsQueueIndex, &mGraphicsQueue);
ASSERT(mGraphicsQueue != VK_NULL_HANDLE);
VkCommandPoolCreateInfo commandPoolCreateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
/* .pNext = */ nullptr,
/* .flags = */ 0,
/* .queueFamilyIndex = */ mGraphicsQueueFamilyIndex,
};
result = vkCreateCommandPool(mDevice, &commandPoolCreateInfo, nullptr, &mCommandPool);
ASSERT(result == VK_SUCCESS);
mHasExternalMemoryFd =
HasExtension(enabledDeviceExtensions, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
mHasExternalSemaphoreFd =
......@@ -303,13 +356,19 @@ void VulkanExternalHelper::initialize(bool useSwiftshader, bool enableValidation
vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceImageFormatProperties2"));
vkGetMemoryFdKHR = reinterpret_cast<PFN_vkGetMemoryFdKHR>(
vkGetInstanceProcAddr(mInstance, "vkGetMemoryFdKHR"));
ASSERT(!mHasExternalMemoryFd || vkGetMemoryFdKHR);
vkGetSemaphoreFdKHR = reinterpret_cast<PFN_vkGetSemaphoreFdKHR>(
vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreFdKHR"));
ASSERT(!mHasExternalSemaphoreFd || vkGetSemaphoreFdKHR);
vkGetPhysicalDeviceExternalSemaphorePropertiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR>(
vkGetInstanceProcAddr(mInstance, "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR"));
vkGetMemoryZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetMemoryZirconHandleFUCHSIA>(
vkGetInstanceProcAddr(mInstance, "vkGetMemoryZirconHandleFUCHSIA"));
ASSERT(!mHasExternalMemoryFuchsia || vkGetMemoryZirconHandleFUCHSIA);
vkGetSemaphoreZirconHandleFUCHSIA = reinterpret_cast<PFN_vkGetSemaphoreZirconHandleFUCHSIA>(
vkGetInstanceProcAddr(mInstance, "vkGetSemaphoreZirconHandleFUCHSIA"));
ASSERT(!mHasExternalSemaphoreFuchsia || vkGetSemaphoreZirconHandleFUCHSIA);
}
bool VulkanExternalHelper::canCreateImageExternal(
......@@ -581,4 +640,352 @@ VkResult VulkanExternalHelper::exportSemaphoreOpaqueFd(VkSemaphore semaphore, in
return vkGetSemaphoreFdKHR(mDevice, &semaphoreGetFdInfo, fd);
}
bool VulkanExternalHelper::canCreateSemaphoreZirconEvent() const
{
if (!mHasExternalSemaphoreFuchsia || !vkGetPhysicalDeviceExternalSemaphorePropertiesKHR)
{
return false;
}
VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
/* .pNext = */ nullptr,
/* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA,
};
VkExternalSemaphoreProperties externalSemaphoreProperties = {
/* .sType = */ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES,
};
vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo,
&externalSemaphoreProperties);
constexpr VkExternalSemaphoreFeatureFlags kRequiredFeatures =
VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
if ((externalSemaphoreProperties.externalSemaphoreFeatures & kRequiredFeatures) !=
kRequiredFeatures)
{
return false;
}
return true;
}
VkResult VulkanExternalHelper::createSemaphoreZirconEvent(VkSemaphore *semaphore)
{
VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
/* .pNext = */ nullptr,
/* .handleTypes = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA,
};
VkSemaphoreCreateInfo semaphoreCreateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
/* .pNext = */ &exportSemaphoreCreateInfo,
/* .flags = */ 0,
};
return vkCreateSemaphore(mDevice, &semaphoreCreateInfo, nullptr, semaphore);
}
VkResult VulkanExternalHelper::exportSemaphoreZirconEvent(VkSemaphore semaphore, zx_handle_t *event)
{
VkSemaphoreGetZirconHandleInfoFUCHSIA semaphoreGetZirconHandleInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_TEMP_SEMAPHORE_GET_ZIRCON_HANDLE_INFO_FUCHSIA,
/* .pNext = */ nullptr,
/* .semaphore = */ semaphore,
/* .handleType = */ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_TEMP_ZIRCON_EVENT_BIT_FUCHSIA,
};
return vkGetSemaphoreZirconHandleFUCHSIA(mDevice, &semaphoreGetZirconHandleInfo, event);
}
void VulkanExternalHelper::releaseImageAndSignalSemaphore(VkImage image,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkSemaphore semaphore)
{
VkResult result;
VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};
constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();
VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
/* .pNext = */ nullptr,
/* .commandPool = */ mCommandPool,
/* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
/* .commandBufferCount = */ commandBufferCount,
};
result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
ASSERT(result == VK_SUCCESS);
VkCommandBufferBeginInfo commandBufferBeginInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
/* .pNext = */ nullptr,
/* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
/* .pInheritanceInfo = */ nullptr,
};
result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
ASSERT(result == VK_SUCCESS);
ImageMemoryBarrier(commandBuffers[0], image, mGraphicsQueueFamilyIndex,
VK_QUEUE_FAMILY_EXTERNAL, oldLayout, newLayout);
result = vkEndCommandBuffer(commandBuffers[0]);
ASSERT(result == VK_SUCCESS);
const VkSemaphore signalSemaphores[] = {
semaphore,
};
constexpr uint32_t signalSemaphoreCount = std::extent<decltype(signalSemaphores)>();
const VkSubmitInfo submits[] = {
/* [0] = */ {
/* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
/* .pNext = */ nullptr,
/* .waitSemaphoreCount = */ 0,
/* .pWaitSemaphores = */ nullptr,
/* .pWaitDstStageMask = */ nullptr,
/* .commandBufferCount = */ commandBufferCount,
/* .pCommandBuffers = */ commandBuffers,
/* .signalSemaphoreCount = */ signalSemaphoreCount,
/* .pSignalSemaphores = */ signalSemaphores,
},
};
constexpr uint32_t submitCount = std::extent<decltype(submits)>();
const VkFence fence = VK_NULL_HANDLE;
result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
ASSERT(result == VK_SUCCESS);
}
void VulkanExternalHelper::waitSemaphoreAndAcquireImage(VkImage image,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkSemaphore semaphore)
{
VkResult result;
VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};
constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();
VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
/* .pNext = */ nullptr,
/* .commandPool = */ mCommandPool,
/* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
/* .commandBufferCount = */ commandBufferCount,
};
result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
ASSERT(result == VK_SUCCESS);
VkCommandBufferBeginInfo commandBufferBeginInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
/* .pNext = */ nullptr,
/* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
/* .pInheritanceInfo = */ nullptr,
};
result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
ASSERT(result == VK_SUCCESS);
ImageMemoryBarrier(commandBuffers[0], image, VK_QUEUE_FAMILY_EXTERNAL,
mGraphicsQueueFamilyIndex, oldLayout, newLayout);
result = vkEndCommandBuffer(commandBuffers[0]);
ASSERT(result == VK_SUCCESS);
const VkSemaphore waitSemaphores[] = {
semaphore,
};
const VkPipelineStageFlags waitDstStageMasks[] = {
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
};
constexpr uint32_t waitSemaphoreCount = std::extent<decltype(waitSemaphores)>();
constexpr uint32_t waitDstStageMaskCount = std::extent<decltype(waitDstStageMasks)>();
static_assert(waitSemaphoreCount == waitDstStageMaskCount,
"waitSemaphores and waitDstStageMasks must be the same length");
const VkSubmitInfo submits[] = {
/* [0] = */ {
/* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
/* .pNext = */ nullptr,
/* .waitSemaphoreCount = */ waitSemaphoreCount,
/* .pWaitSemaphores = */ waitSemaphores,
/* .pWaitDstStageMask = */ waitDstStageMasks,
/* .commandBufferCount = */ commandBufferCount,
/* .pCommandBuffers = */ commandBuffers,
/* .signalSemaphoreCount = */ 0,
/* .pSignalSemaphores = */ nullptr,
},
};
constexpr uint32_t submitCount = std::extent<decltype(submits)>();
const VkFence fence = VK_NULL_HANDLE;
result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
ASSERT(result == VK_SUCCESS);
}
void VulkanExternalHelper::readPixels(VkImage srcImage,
VkImageLayout srcImageLayout,
VkFormat srcImageFormat,
VkOffset3D imageOffset,
VkExtent3D imageExtent,
void *pixels,
size_t pixelsSize)
{
ASSERT(srcImageFormat == VK_FORMAT_B8G8R8A8_UNORM ||
srcImageFormat == VK_FORMAT_R8G8B8A8_UNORM);
ASSERT(imageExtent.depth == 1);
ASSERT(pixelsSize == 4 * imageExtent.width * imageExtent.height);
VkBufferCreateInfo bufferCreateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
/* .pNext = */ nullptr,
/* .flags = */ 0,
/* .size = */ pixelsSize,
/* .usage = */ VK_BUFFER_USAGE_TRANSFER_DST_BIT,
/* .sharingMode = */ VK_SHARING_MODE_EXCLUSIVE,
/* .queueFamilyIndexCount = */ 0,
/* .pQueueFamilyIndices = */ nullptr,
};
VkBuffer stagingBuffer = VK_NULL_HANDLE;
VkResult result = vkCreateBuffer(mDevice, &bufferCreateInfo, nullptr, &stagingBuffer);
ASSERT(result == VK_SUCCESS);
VkMemoryPropertyFlags requestedMemoryPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(mDevice, stagingBuffer, &memoryRequirements);
uint32_t memoryTypeIndex = FindMemoryType(mMemoryProperties, memoryRequirements.memoryTypeBits,
requestedMemoryPropertyFlags);
ASSERT(memoryTypeIndex != UINT32_MAX);
VkDeviceSize deviceMemorySize = memoryRequirements.size;
VkMemoryDedicatedAllocateInfoKHR memoryDedicatedAllocateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
/* .pNext = */ nullptr,
/* .image = */ VK_NULL_HANDLE,
/* .buffer = */ stagingBuffer,
};
VkMemoryAllocateInfo memoryAllocateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
/* .pNext = */ &memoryDedicatedAllocateInfo,
/* .allocationSize = */ deviceMemorySize,
/* .memoryTypeIndex = */ memoryTypeIndex,
};
VkDeviceMemory deviceMemory = VK_NULL_HANDLE;
result = vkAllocateMemory(mDevice, &memoryAllocateInfo, nullptr, &deviceMemory);
ASSERT(result == VK_SUCCESS);
result = vkBindBufferMemory(mDevice, stagingBuffer, deviceMemory, 0 /* memoryOffset */);
ASSERT(result == VK_SUCCESS);
VkCommandBuffer commandBuffers[] = {VK_NULL_HANDLE};
constexpr uint32_t commandBufferCount = std::extent<decltype(commandBuffers)>();
VkCommandBufferAllocateInfo commandBufferAllocateInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
/* .pNext = */ nullptr,
/* .commandPool = */ mCommandPool,
/* .level = */ VK_COMMAND_BUFFER_LEVEL_PRIMARY,
/* .commandBufferCount = */ commandBufferCount,
};
result = vkAllocateCommandBuffers(mDevice, &commandBufferAllocateInfo, commandBuffers);
ASSERT(result == VK_SUCCESS);
VkCommandBufferBeginInfo commandBufferBeginInfo = {
/* .sType = */ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
/* .pNext = */ nullptr,
/* .flags = */ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
/* .pInheritanceInfo = */ nullptr,
};
result = vkBeginCommandBuffer(commandBuffers[0], &commandBufferBeginInfo);
ASSERT(result == VK_SUCCESS);
VkBufferImageCopy bufferImageCopies[] = {
/* [0] = */ {
/* .bufferOffset = */ 0,
/* .bufferRowLength = */ 0,
/* .bufferImageHeight = */ 0,
/* .imageSubresources = */
{
/* .aspectMask = */ VK_IMAGE_ASPECT_COLOR_BIT,
/* .mipLevel = */ 0,
/* .baseArrayLayer = */ 0,
/* .layerCount = */ 1,
},
/* .imageOffset = */ imageOffset,
/* .imageExtent = */ imageExtent,
},
};
constexpr uint32_t bufferImageCopyCount = std::extent<decltype(bufferImageCopies)>();
vkCmdCopyImageToBuffer(commandBuffers[0], srcImage, srcImageLayout, stagingBuffer,
bufferImageCopyCount, bufferImageCopies);
VkMemoryBarrier memoryBarriers[] = {
/* [0] = */ {/* .sType = */ VK_STRUCTURE_TYPE_MEMORY_BARRIER,
/* .pNext = */ nullptr,
/* .srcAccessMask = */ VK_ACCESS_MEMORY_WRITE_BIT,
/* .dstAccessMask = */ VK_ACCESS_HOST_READ_BIT},
};
constexpr uint32_t memoryBarrierCount = std::extent<decltype(memoryBarriers)>();
vkCmdPipelineBarrier(commandBuffers[0], VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_HOST_BIT, 0 /* dependencyFlags */, memoryBarrierCount,
memoryBarriers, 0, nullptr, 0, nullptr);
result = vkEndCommandBuffer(commandBuffers[0]);
ASSERT(result == VK_SUCCESS);
const VkSubmitInfo submits[] = {
/* [0] = */ {
/* .sType */ VK_STRUCTURE_TYPE_SUBMIT_INFO,
/* .pNext = */ nullptr,
/* .waitSemaphoreCount = */ 0,
/* .pWaitSemaphores = */ nullptr,
/* .pWaitDstStageMask = */ nullptr,
/* .commandBufferCount = */ commandBufferCount,
/* .pCommandBuffers = */ commandBuffers,
/* .signalSemaphoreCount = */ 0,
/* .pSignalSemaphores = */ nullptr,
},
};
constexpr uint32_t submitCount = std::extent<decltype(submits)>();
const VkFence fence = VK_NULL_HANDLE;
result = vkQueueSubmit(mGraphicsQueue, submitCount, submits, fence);
ASSERT(result == VK_SUCCESS);
result = vkQueueWaitIdle(mGraphicsQueue);
ASSERT(result == VK_SUCCESS);
vkFreeCommandBuffers(mDevice, mCommandPool, commandBufferCount, commandBuffers);
void *stagingMemory = nullptr;
result = vkMapMemory(mDevice, deviceMemory, 0 /* offset */, pixelsSize, 0 /* flags */,
&stagingMemory);
ASSERT(result == VK_SUCCESS);
VkMappedMemoryRange memoryRanges[] = {
/* [0] = */ {
/* .sType = */ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
/* .pNext = */ nullptr,
/* .memory = */ deviceMemory,
/* .offset = */ 0,
/* .size = */ pixelsSize,
},
};
constexpr uint32_t memoryRangeCount = std::extent<decltype(memoryRanges)>();
result = vkInvalidateMappedMemoryRanges(mDevice, memoryRangeCount, memoryRanges);
ASSERT(result == VK_SUCCESS);
memcpy(pixels, stagingMemory, pixelsSize);
vkUnmapMemory(mDevice, deviceMemory);
vkFreeMemory(mDevice, deviceMemory, nullptr);
vkDestroyBuffer(mDevice, stagingBuffer, nullptr);
}
} // namespace angle
......@@ -66,11 +66,40 @@ class VulkanExternalHelper
VkResult createSemaphoreZirconEvent(VkSemaphore *semaphore);
VkResult exportSemaphoreZirconEvent(VkSemaphore semaphore, zx_handle_t *event);
// Performs a queue ownership transfer to VK_QUEUE_FAMILY_EXTERNAL on an
// image owned by our instance. The current image layout must be |oldLayout|
// and will be in |newLayout| after the memory barrier. |semaphore|
// will be signaled upon completion of the release operation.
void releaseImageAndSignalSemaphore(VkImage image,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkSemaphore semaphore);
// Performs a queue ownership transfer from VK_QUEUE_FAMILY_EXTERNAL on an
// image owned by an external instance. The current image layout must be
// |oldLayout| and will be in |newLayout| after the memory barrier. The
// barrier will wait for |semaphore|.
void waitSemaphoreAndAcquireImage(VkImage image,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkSemaphore semaphore);
// Copies pixels out of an image. Currently only VK_FORMAT_R8G8B8A8_UNORM
// and VK_FORMAT_B8G8R8A8_UNORM formats are supported.
void readPixels(VkImage srcImage,
VkImageLayout srcImageLayout,
VkFormat srcImageFormat,
VkOffset3D imageOffset,
VkExtent3D imageExtent,
void *pixels,
size_t pixelsSize);
private:
VkInstance mInstance = VK_NULL_HANDLE;
VkPhysicalDevice mPhysicalDevice = VK_NULL_HANDLE;
VkDevice mDevice = VK_NULL_HANDLE;
VkQueue mGraphicsQueue = VK_NULL_HANDLE;
VkCommandPool mCommandPool = VK_NULL_HANDLE;
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
......@@ -85,8 +114,9 @@ class VulkanExternalHelper
PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR = nullptr;
PFN_vkGetSemaphoreFdKHR vkGetSemaphoreFdKHR = nullptr;
PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR
vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = nullptr;
PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA = nullptr;
vkGetPhysicalDeviceExternalSemaphorePropertiesKHR = nullptr;
PFN_vkGetMemoryZirconHandleFUCHSIA vkGetMemoryZirconHandleFUCHSIA = nullptr;
PFN_vkGetSemaphoreZirconHandleFUCHSIA vkGetSemaphoreZirconHandleFUCHSIA = nullptr;
};
} // namespace angle
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment