123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- #include "pch.h"
- #include <third_party/libyuv/include/libyuv/convert.h>
- #include "GraphicsDevice/GraphicsUtility.h"
- #include "UnityVulkanInterfaceFunctions.h"
- #include "VulkanGraphicsDevice.h"
- #include "VulkanTexture2D.h"
- #include "VulkanUtility.h"
- #include "WebRTCMacros.h"
- #if CUDA_PLATFORM
- #include "GraphicsDevice/Cuda/GpuMemoryBufferCudaHandle.h"
- #else
- #include "GpuMemoryBuffer.h"
- #endif
- namespace unity
- {
- namespace webrtc
- {
- VulkanGraphicsDevice::VulkanGraphicsDevice(
- UnityGraphicsVulkan* unityVulkan,
- const VkInstance instance,
- const VkPhysicalDevice physicalDevice,
- const VkDevice device,
- const VkQueue graphicsQueue,
- const uint32_t queueFamilyIndex,
- UnityGfxRenderer renderer,
- ProfilerMarkerFactory* profiler)
- : IGraphicsDevice(renderer, profiler)
- , m_unityVulkan(unityVulkan)
- , m_physicalDevice(physicalDevice)
- , m_device(device)
- , m_graphicsQueue(graphicsQueue)
- , m_commandPool(nullptr)
- , m_queueFamilyIndex(queueFamilyIndex)
- , m_allocator(nullptr)
- #if CUDA_PLATFORM
- , m_instance(instance)
- , m_isCudaSupport(false)
- #endif
- {
- if (profiler)
- m_maker = profiler->CreateMarker(
- "VulkanGraphicsDevice.CopyImage", kUnityProfilerCategoryOther, kUnityProfilerMarkerFlagDefault, 0);
- }
- //---------------------------------------------------------------------------------------------------------------------
- bool VulkanGraphicsDevice::InitV()
- {
- #if CUDA_PLATFORM
- m_isCudaSupport = InitCudaContext();
- #endif
- return VK_SUCCESS == CreateCommandPool();
- }
- #if CUDA_PLATFORM
- bool VulkanGraphicsDevice::InitCudaContext()
- {
- if (!VulkanUtility::LoadInstanceFunctions(m_instance))
- return false;
- if (!VulkanUtility::LoadDeviceFunctions(m_device))
- return false;
- CUresult result = m_cudaContext.Init(m_instance, m_physicalDevice);
- if (CUDA_SUCCESS != result)
- return false;
- return true;
- }
- #endif
- //---------------------------------------------------------------------------------------------------------------------
- void VulkanGraphicsDevice::ShutdownV()
- {
- #if CUDA_PLATFORM
- m_cudaContext.Shutdown();
- #endif
- VULKAN_SAFE_DESTROY_COMMAND_POOL(m_device, m_commandPool, m_allocator)
- }
- //---------------------------------------------------------------------------------------------------------------------
- std::unique_ptr<UnityVulkanImage> VulkanGraphicsDevice::AccessTexture(void* ptr) const
- {
- // cannot do resource uploads inside renderpass
- m_unityVulkan->EnsureOutsideRenderPass();
- std::unique_ptr<UnityVulkanImage> unityVulkanImage = std::make_unique<UnityVulkanImage>();
- VkImageSubresource subResource { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
- if (!m_unityVulkan->AccessTexture(
- ptr,
- &subResource,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_ACCESS_TRANSFER_READ_BIT,
- kUnityVulkanResourceAccess_PipelineBarrier,
- unityVulkanImage.get()))
- {
- return nullptr;
- }
- return unityVulkanImage;
- }
- static VkResult BeginCommandBuffer(VkCommandBuffer commandBuffer)
- {
- VkCommandBufferBeginInfo beginInfo = {};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- return vkBeginCommandBuffer(commandBuffer, &beginInfo);
- }
- static VkResult QueueSubmit(VkQueue queue, VkCommandBuffer commandBuffer, VkFence fence)
- {
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &commandBuffer;
- return vkQueueSubmit(queue, 1, &submitInfo, fence);
- }
- // Returns null if failed
- ITexture2D* VulkanGraphicsDevice::CreateDefaultTextureV(
- const uint32_t w, const uint32_t h, UnityRenderingExtTextureFormat textureFormat)
- {
- std::unique_ptr<VulkanTexture2D> vulkanTexture = std::make_unique<VulkanTexture2D>(w, h);
- if (!vulkanTexture->Init(m_physicalDevice, m_device, m_commandPool))
- {
- RTC_LOG(LS_ERROR) << "VulkanTexture2D::Init failed.";
- return nullptr;
- }
- return vulkanTexture.release();
- }
- ITexture2D*
- VulkanGraphicsDevice::CreateCPUReadTextureV(uint32_t w, uint32_t h, UnityRenderingExtTextureFormat textureFormat)
- {
- std::unique_ptr<VulkanTexture2D> vulkanTexture = std::make_unique<VulkanTexture2D>(w, h);
- if (!vulkanTexture->InitCpuRead(m_physicalDevice, m_device, m_commandPool))
- {
- RTC_LOG(LS_ERROR) << "VulkanTexture2D::InitCpuRead failed.";
- return nullptr;
- }
- return vulkanTexture.release();
- }
- //---------------------------------------------------------------------------------------------------------------------
- bool VulkanGraphicsDevice::CopyResourceV(ITexture2D* dest, ITexture2D* src)
- {
- VulkanTexture2D* destTexture = reinterpret_cast<VulkanTexture2D*>(dest);
- VulkanTexture2D* srcTexture = reinterpret_cast<VulkanTexture2D*>(src);
- if (destTexture == srcTexture)
- return false;
- if (destTexture == nullptr || srcTexture == nullptr)
- return false;
- VkCommandBuffer commandBuffer = destTexture->GetCommandBuffer();
- VkResult result = BeginCommandBuffer(commandBuffer);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "BeginCommandBuffer failed. result:" << result;
- return false;
- }
- // Transition the src texture layout.
- result = VulkanUtility::DoImageLayoutTransition(
- commandBuffer,
- srcTexture->GetImage(),
- srcTexture->GetTextureFormat(),
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "DoImageLayoutTransition failed. result:" << result;
- return false;
- }
- // Transition the dst texture layout.
- result = VulkanUtility::DoImageLayoutTransition(
- commandBuffer,
- destTexture->GetImage(),
- destTexture->GetTextureFormat(),
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "DoImageLayoutTransition failed. result:" << result;
- return false;
- }
- result = VulkanUtility::CopyImage(
- commandBuffer,
- srcTexture->GetImage(),
- destTexture->GetImage(),
- destTexture->GetWidth(),
- destTexture->GetHeight());
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "CopyImage failed. result:" << result;
- return false;
- }
- // transition the src texture layout back to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
- result = VulkanUtility::DoImageLayoutTransition(
- commandBuffer,
- srcTexture->GetImage(),
- srcTexture->GetTextureFormat(),
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "DoImageLayoutTransition failed. result:" << result;
- return false;
- }
- result = vkEndCommandBuffer(commandBuffer);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "vkEndCommandBuffer failed. result:" << result;
- return false;
- }
- VkFence fence = destTexture->GetFence();
- result = QueueSubmit(m_graphicsQueue, commandBuffer, fence);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "vkQueueSubmit failed. result:" << result;
- return false;
- }
- return true;
- }
- //---------------------------------------------------------------------------------------------------------------------
- bool VulkanGraphicsDevice::CopyResourceFromNativeV(ITexture2D* dest, void* nativeTexturePtr)
- {
- if (nullptr == dest || nullptr == nativeTexturePtr)
- return false;
- VulkanTexture2D* destTexture = reinterpret_cast<VulkanTexture2D*>(dest);
- UnityVulkanImage* unityVulkanImage = static_cast<UnityVulkanImage*>(nativeTexturePtr);
- VkCommandBuffer commandBuffer = destTexture->GetCommandBuffer();
- VkResult result = BeginCommandBuffer(commandBuffer);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "BeginCommandBuffer failed. result:" << result;
- return false;
- }
- // Transition the src texture layout.
- result = VulkanUtility::DoImageLayoutTransition(
- commandBuffer,
- unityVulkanImage->image,
- unityVulkanImage->format,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "DoImageLayoutTransition failed. result:" << result;
- return false;
- }
- // Transition the dst texture layout.
- result = VulkanUtility::DoImageLayoutTransition(
- commandBuffer,
- destTexture->GetImage(),
- destTexture->GetTextureFormat(),
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "DoImageLayoutTransition failed. result:" << result;
- return false;
- }
- VkImage image = unityVulkanImage->image;
- if (destTexture->GetImage() == image)
- return false;
- {
- std::unique_ptr<const ScopedProfiler> profiler;
- if (m_profiler)
- profiler = m_profiler->CreateScopedProfiler(*m_maker);
- // The layouts of All VulkanTexture2D should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- // so no transition for destTex
- result = VulkanUtility::CopyImage(
- commandBuffer, image, destTexture->GetImage(), destTexture->GetWidth(), destTexture->GetHeight());
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "CopyImage failed. result:" << result;
- return false;
- }
- }
- result = vkEndCommandBuffer(commandBuffer);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "vkEndCommandBuffer failed. result:" << result;
- return false;
- }
- VkFence fence = destTexture->GetFence();
- result = QueueSubmit(m_graphicsQueue, commandBuffer, fence);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "vkQueueSubmit failed. result:" << result;
- return false;
- }
- return true;
- }
- VkResult VulkanGraphicsDevice::CreateCommandPool()
- {
- VkCommandPoolCreateInfo poolInfo = {};
- poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- poolInfo.queueFamilyIndex = m_queueFamilyIndex;
- poolInfo.flags = 0;
- return vkCreateCommandPool(m_device, &poolInfo, m_allocator, &m_commandPool);
- }
- rtc::scoped_refptr<webrtc::I420Buffer> VulkanGraphicsDevice::ConvertRGBToI420(ITexture2D* tex)
- {
- VulkanTexture2D* vulkanTexture = static_cast<VulkanTexture2D*>(tex);
- const int32_t width = static_cast<int32_t>(tex->GetWidth());
- const int32_t height = static_cast<int32_t>(tex->GetHeight());
- const VkDeviceMemory dstImageMemory = vulkanTexture->GetTextureImageMemory();
- VkImageSubresource subresource { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
- VkSubresourceLayout subresourceLayout;
- vkGetImageSubresourceLayout(m_device, vulkanTexture->GetImage(), &subresource, &subresourceLayout);
- const int32_t rowPitch = static_cast<int32_t>(subresourceLayout.rowPitch);
- void* data;
- std::vector<uint8_t> dst;
- dst.resize(vulkanTexture->GetTextureImageMemorySize());
- const VkResult result = vkMapMemory(m_device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, &data);
- if (result != VK_SUCCESS)
- {
- return nullptr;
- }
- std::memcpy(static_cast<void*>(dst.data()), data, dst.size());
- vkUnmapMemory(m_device, dstImageMemory);
- // convert format to i420
- rtc::scoped_refptr<webrtc::I420Buffer> i420Buffer = webrtc::I420Buffer::Create(width, height);
- libyuv::ARGBToI420(
- dst.data(),
- rowPitch,
- i420Buffer->MutableDataY(),
- i420Buffer->StrideY(),
- i420Buffer->MutableDataU(),
- i420Buffer->StrideU(),
- i420Buffer->MutableDataV(),
- i420Buffer->StrideV(),
- width,
- height);
- return i420Buffer;
- }
- std::unique_ptr<GpuMemoryBufferHandle> VulkanGraphicsDevice::Map(ITexture2D* texture)
- {
- #if CUDA_PLATFORM
- if (!IsCudaSupport())
- return nullptr;
- // set context on the thread.
- cuCtxPushCurrent(GetCUcontext());
- VulkanTexture2D* vulkanTexture = static_cast<VulkanTexture2D*>(texture);
- void* exportHandle = VulkanUtility::GetExportHandle(m_device, vulkanTexture->GetTextureImageMemory());
- if (!exportHandle)
- {
- RTC_LOG(LS_ERROR) << "cannot get export handle";
- throw;
- }
- CUDA_EXTERNAL_MEMORY_HANDLE_DESC memDesc = {};
- #ifndef _WIN32
- memDesc.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD;
- #else
- memDesc.type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32;
- #endif
- memDesc.handle.fd = static_cast<int>(reinterpret_cast<uintptr_t>(exportHandle));
- memDesc.size = vulkanTexture->GetTextureImageMemorySize();
- CUresult result;
- CUexternalMemory externalMemory;
- result = cuImportExternalMemory(&externalMemory, &memDesc);
- if (result != CUDA_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "cuImportExternalMemory error:" << result;
- throw;
- }
- const VkExtent2D extent = { texture->GetWidth(), texture->GetHeight() };
- CUDA_ARRAY3D_DESCRIPTOR arrayDesc = {};
- arrayDesc.Width = extent.width;
- arrayDesc.Height = extent.height;
- arrayDesc.Depth = 0; /* CUDA 2D arrays are defined to have depth 0 */
- arrayDesc.Format = CU_AD_FORMAT_UNSIGNED_INT32;
- arrayDesc.NumChannels = 1;
- arrayDesc.Flags = CUDA_ARRAY3D_SURFACE_LDST | CUDA_ARRAY3D_COLOR_ATTACHMENT;
- CUDA_EXTERNAL_MEMORY_MIPMAPPED_ARRAY_DESC mipmapArrayDesc = {};
- mipmapArrayDesc.arrayDesc = arrayDesc;
- mipmapArrayDesc.numLevels = 1;
- CUmipmappedArray mipmappedArray;
- result = cuExternalMemoryGetMappedMipmappedArray(&mipmappedArray, externalMemory, &mipmapArrayDesc);
- if (result != CUDA_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "cuExternalMemoryGetMappedMipmappedArray error:" << result;
- throw;
- }
- CUarray array;
- result = cuMipmappedArrayGetLevel(&array, mipmappedArray, 0);
- if (result != CUDA_SUCCESS)
- {
- RTC_LOG(LS_ERROR) << "cuMipmappedArrayGetLevel error:" << result;
- throw;
- }
- cuCtxPopCurrent(nullptr);
- std::unique_ptr<GpuMemoryBufferCudaHandle> handle = std::make_unique<GpuMemoryBufferCudaHandle>();
- handle->context = GetCUcontext();
- handle->mappedArray = array;
- handle->externalMemory = externalMemory;
- return std::move(handle);
- #else
- return nullptr;
- #endif
- }
- bool VulkanGraphicsDevice::WaitIdleForTest()
- {
- VkResult result = vkQueueWaitIdle(m_graphicsQueue);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_INFO) << "vkQueueWaitIdle failed. result:" << result;
- return false;
- }
- return true;
- }
- bool VulkanGraphicsDevice::WaitSync(const ITexture2D* texture, uint64_t nsTimeout)
- {
- const VulkanTexture2D* vulkanTexture = static_cast<const VulkanTexture2D*>(texture);
- VkFence fence = vulkanTexture->GetFence();
- VkResult result = vkWaitForFences(m_device, 1, &fence, true, nsTimeout);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_INFO) << "vkWaitForFences failed. result:" << result;
- return false;
- }
- return true;
- }
- bool VulkanGraphicsDevice::ResetSync(const ITexture2D* texture)
- {
- const VulkanTexture2D* vulkanTexture = static_cast<const VulkanTexture2D*>(texture);
- VkCommandBuffer commandBuffer = vulkanTexture->GetCommandBuffer();
- VkFence fence = vulkanTexture->GetFence();
- VkResult result = vkGetFenceStatus(m_device, fence);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_INFO) << "vkGetFenceStatus failed. result:" << result;
- return false;
- }
- result = vkResetFences(m_device, 1, &fence);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_INFO) << "vkResetFences failed. result:" << result;
- return false;
- }
- result = vkResetCommandBuffer(commandBuffer, 0);
- if (result != VK_SUCCESS)
- {
- RTC_LOG(LS_INFO) << "vkResetCommandBuffer failed. result:" << result;
- return false;
- }
- return true;
- }
- } // end namespace webrtc
- } // end namespace unity
|