Android渲染--重温硬件加速下Vulkan篇

前一章Android渲染--重温硬件加速上我们主要介绍了硬件加速在View树更新的时候收集绘制OP,生成DisplayList,接下来就是要开始绘制。

绘制

绘制流程主要是在CanvasContext准备完后,绘制一帧的数据就准备好了。绘制会交给Pipeline做处理,最新版本(Android12)有2种类型的Pipeline,比如SkiaVulkanPipeline。

CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
76                                       RenderNode* rootRenderNode, IContextFactory* contextFactory) {
77      auto renderType = Properties::getRenderPipelineType();
78  
79      switch (renderType) {
80          case RenderPipelineType::SkiaGL:
81              return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
82                                       std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
83          case RenderPipelineType::SkiaVulkan:
84              return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
85                                       std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
86          default:
87              LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
88              break;
89      }
90      return nullptr;
91  }
92  

9.0之后google开始增强了Android的skia,将OpenGL的能力封装进Skia库里(Flutter的Skia图形库也是集成了OpenGl,Vulkan,Metal等)。SkiaVulkanPipeline 的会对 VulkanManager初始化,VulkanManager 是对 Vulkan 使用的封装。

void VulkanManager::initialize() {
343      std::lock_guard _lock{mInitializeLock};
344  
345      if (mDevice != VK_NULL_HANDLE) {
346          return;
347      }
348  
349      GET_PROC(EnumerateInstanceVersion);
350      uint32_t instanceVersion;
351      LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
352      LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
353  
354      this->setupDevice(mExtensions, mPhysicalDeviceFeatures2);
355  
356      mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
357  
358      if (Properties::enablePartialUpdates && Properties::useBufferAge) {
359          mSwapBehavior = SwapBehavior::BufferAge;
360      }
361  }

如果选用了Vulkan就终会执行到draw里,

bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
68                                const LightGeometry& lightGeometry,
69                                LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
70                                bool opaque, const LightInfo& lightInfo,
71                                const std::vector<sp<RenderNode>>& renderNodes,
72                                FrameInfoVisualizer* profiler) {
73      sk_sp<SkSurface> backBuffer = mVkSurface->getCurrentSkSurface();
74      if (backBuffer.get() == nullptr) {
75          return false;
76      }
77      LightingInfo::updateLighting(lightGeometry, lightInfo);
78      renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, backBuffer,
79                  mVkSurface->getCurrentPreTransform());
80  
81      // Draw visual debugging features
82      if (CC_UNLIKELY(Properties::showDirtyRegions ||
83                      ProfileType::None != Properties::getProfileType())) {
84          SkCanvas* profileCanvas = backBuffer->getCanvas();
85          SkiaProfileRenderer profileRenderer(profileCanvas);
86          profiler->draw(profileRenderer);
87      }
88  
89      {
90          ATRACE_NAME("flush commands");
91          vulkanManager().finishFrame(backBuffer.get());
92      }
93      layerUpdateQueue->clear();
94  
95      // Log memory statistics
96      if (CC_UNLIKELY(Properties::debugLevel != kDebugDisabled)) {
97          dumpResourceCacheUsage();
98      }
99  
100      return true;
101  }

Frame是描述一帧数据信息的,主要是宽,高,bufferAge,和Surface这几个属性。绘制开始时,由VulkanManager根据VulkanSurface的属性构建。

Frame SkiaVulkanPipeline::getFrame() {
63      LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr, "getFrame() called on a context with no surface!");
64      return vulkanManager().dequeueNextBuffer(mVkSurface);
65  }
66  
Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
399      VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer();
400  
401      if (bufferInfo == nullptr) {
402          ALOGE("VulkanSurface::dequeueNativeBuffer called with an invalid surface!");
403          return Frame(-1, -1, 0);
404      }
405  
406      LOG_ALWAYS_FATAL_IF(!bufferInfo->dequeued);
407  
408      if (bufferInfo->dequeue_fence != -1) {
409          struct sync_file_info* finfo = sync_file_info(bufferInfo->dequeue_fence);
410          bool isSignalPending = false;
411          if (finfo != NULL) {
412              isSignalPending = finfo->status != 1;
413              sync_file_info_free(finfo);
414          }
415          if (isSignalPending) {
416              int fence_clone = dup(bufferInfo->dequeue_fence);
417              if (fence_clone == -1) {
418                  ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno),
419                        errno);
420                  sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
421              } else {
422                  VkSemaphoreCreateInfo semaphoreInfo;
423                  semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
424                  semaphoreInfo.pNext = nullptr;
425                  semaphoreInfo.flags = 0;
426                  VkSemaphore semaphore;
427                  VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
428                  if (err != VK_SUCCESS) {
429                      ALOGE("Failed to create import semaphore, err: %d", err);
430                      close(fence_clone);
431                      sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
432                  } else {
433                      VkImportSemaphoreFdInfoKHR importInfo;
434                      importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
435                      importInfo.pNext = nullptr;
436                      importInfo.semaphore = semaphore;
437                      importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
438                      importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
439                      importInfo.fd = fence_clone;
440  
441                      err = mImportSemaphoreFdKHR(mDevice, &importInfo);
442                      if (err != VK_SUCCESS) {
443                          ALOGE("Failed to import semaphore, err: %d", err);
444                          mDestroySemaphore(mDevice, semaphore, nullptr);
445                          close(fence_clone);
446                          sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
447                      } else {
448                          GrBackendSemaphore backendSemaphore;
449                          backendSemaphore.initVulkan(semaphore);
450                          // Skia will take ownership of the VkSemaphore and delete it once the wait
451                          // has finished. The VkSemaphore also owns the imported fd, so it will
452                          // close the fd when it is deleted.
453                          bufferInfo->skSurface->wait(1, &backendSemaphore);
454                          // The following flush blocks the GPU immediately instead of waiting for
455                          // other drawing ops. It seems dequeue_fence is not respected otherwise.
456                          // TODO: remove the flush after finding why backendSemaphore is not working.
457                          bufferInfo->skSurface->flushAndSubmit();
458                      }
459                  }
460              }
461          }
462      }
463  
464      int bufferAge = (mSwapBehavior == SwapBehavior::Discard) ? 0 : surface->getCurrentBuffersAge();
465      return Frame(surface->logicalWidth(), surface->logicalHeight(), bufferAge);
466  }

接上面的流程,会执行到SkiaPipeline的renderFrame函数。

void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
442                                 const std::vector<sp<RenderNode>>& nodes, bool opaque,
443                                 const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
444                                 const SkMatrix& preTransform) {
445      bool previousSkpEnabled = Properties::skpCaptureEnabled;
446      if (mPictureCapturedCallback) {
447          Properties::skpCaptureEnabled = true;
448      }
449  
450      // Initialize the canvas for the current frame, that might be a recording canvas if SKP
451      // capture is enabled.
452      SkCanvas* canvas = tryCapture(surface.get(), nodes[0].get(), layers);
453  
454      // draw all layers up front
455      renderLayersImpl(layers, opaque);
456  
457      renderFrameImpl(clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
458  
459      endCapture(surface.get());
460  
461      if (CC_UNLIKELY(Properties::debugOverdraw)) {
462          renderOverdraw(clip, nodes, contentDrawBounds, surface, preTransform);
463      }
464  
465      Properties::skpCaptureEnabled = previousSkpEnabled;
466  }

这里主要对RenderNode做各个layer和内容的绘制,然后内容绘制完成后就执行swapbuffers,具体内部的渲染逻辑暂时先不展开了,有兴趣的读者可以自己研究下。

void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
561      if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
562          ATRACE_NAME("Finishing GPU work");
563          mDeviceWaitIdle(mDevice);
564      }
565  
566      int fenceFd = -1;
567      if (mSwapSemaphore != VK_NULL_HANDLE) {
568          VkSemaphoreGetFdInfoKHR getFdInfo;
569          getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
570          getFdInfo.pNext = nullptr;
571          getFdInfo.semaphore = mSwapSemaphore;
572          getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
573  
574          VkResult err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
575          ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
576      } else {
577          ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
578  
579          std::lock_guard<std::mutex> lock(mGraphicsQueueMutex);
580          mQueueWaitIdle(mGraphicsQueue);
581      }
582      if (mDestroySemaphoreContext) {
583          destroy_semaphore(mDestroySemaphoreContext);
584      }
585  
586      surface->presentCurrentBuffer(dirtyRect, fenceFd);
587      mSwapSemaphore = VK_NULL_HANDLE;
588      mDestroySemaphoreContext = nullptr;
589  }

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值