• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // DisplayVk.cpp:
7 //    Implements the class methods for DisplayVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/DisplayVk.h"
11 
12 #include "common/debug.h"
13 #include "common/system_utils.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Display.h"
16 #include "libANGLE/renderer/vulkan/BufferVk.h"
17 #include "libANGLE/renderer/vulkan/ContextVk.h"
18 #include "libANGLE/renderer/vulkan/DeviceVk.h"
19 #include "libANGLE/renderer/vulkan/ImageVk.h"
20 #include "libANGLE/renderer/vulkan/RendererVk.h"
21 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
22 #include "libANGLE/renderer/vulkan/SyncVk.h"
23 #include "libANGLE/renderer/vulkan/VkImageImageSiblingVk.h"
24 #include "libANGLE/trace.h"
25 
26 namespace rx
27 {
28 // Time interval in seconds that we should try to prune default buffer pools.
29 constexpr double kTimeElapsedForPruneDefaultBufferPool = 0.25;
30 
DisplayVk(const egl::DisplayState & state)31 DisplayVk::DisplayVk(const egl::DisplayState &state)
32     : DisplayImpl(state),
33       vk::Context(new RendererVk()),
34       mScratchBuffer(1000u),
35       mSavedError({VK_SUCCESS, "", "", 0})
36 {}
37 
~DisplayVk()38 DisplayVk::~DisplayVk()
39 {
40     delete mRenderer;
41 }
42 
initialize(egl::Display * display)43 egl::Error DisplayVk::initialize(egl::Display *display)
44 {
45     ASSERT(mRenderer != nullptr && display != nullptr);
46     angle::Result result = mRenderer->initialize(this, display, getWSIExtension(), getWSILayer());
47     ANGLE_TRY(angle::ToEGL(result, this, EGL_NOT_INITIALIZED));
48     return egl::NoError();
49 }
50 
terminate()51 void DisplayVk::terminate()
52 {
53     mRenderer->reloadVolkIfNeeded();
54 
55     ASSERT(mRenderer);
56     mRenderer->onDestroy(this);
57 }
58 
makeCurrent(egl::Display *,egl::Surface *,egl::Surface *,gl::Context *)59 egl::Error DisplayVk::makeCurrent(egl::Display * /*display*/,
60                                   egl::Surface * /*drawSurface*/,
61                                   egl::Surface * /*readSurface*/,
62                                   gl::Context * /*context*/)
63 {
64     // Ensure the appropriate global DebugAnnotator is used
65     ASSERT(mRenderer);
66     mRenderer->setGlobalDebugAnnotator();
67 
68     return egl::NoError();
69 }
70 
testDeviceLost()71 bool DisplayVk::testDeviceLost()
72 {
73     return mRenderer->isDeviceLost();
74 }
75 
restoreLostDevice(const egl::Display * display)76 egl::Error DisplayVk::restoreLostDevice(const egl::Display *display)
77 {
78     // A vulkan device cannot be restored, the entire renderer would have to be re-created along
79     // with any other EGL objects that reference it.
80     return egl::EglBadDisplay();
81 }
82 
getRendererDescription()83 std::string DisplayVk::getRendererDescription()
84 {
85     if (mRenderer)
86     {
87         return mRenderer->getRendererDescription();
88     }
89     return std::string();
90 }
91 
getVendorString()92 std::string DisplayVk::getVendorString()
93 {
94     if (mRenderer)
95     {
96         return mRenderer->getVendorString();
97     }
98     return std::string();
99 }
100 
getVersionString(bool includeFullVersion)101 std::string DisplayVk::getVersionString(bool includeFullVersion)
102 {
103     if (mRenderer)
104     {
105         return mRenderer->getVersionString(includeFullVersion);
106     }
107     return std::string();
108 }
109 
createDevice()110 DeviceImpl *DisplayVk::createDevice()
111 {
112     return new DeviceVk();
113 }
114 
waitClient(const gl::Context * context)115 egl::Error DisplayVk::waitClient(const gl::Context *context)
116 {
117     ANGLE_TRACE_EVENT0("gpu.angle", "DisplayVk::waitClient");
118     ContextVk *contextVk = vk::GetImpl(context);
119     return angle::ToEGL(contextVk->finishImpl(RenderPassClosureReason::EGLWaitClient), this,
120                         EGL_BAD_ACCESS);
121 }
122 
waitNative(const gl::Context * context,EGLint engine)123 egl::Error DisplayVk::waitNative(const gl::Context *context, EGLint engine)
124 {
125     ANGLE_TRACE_EVENT0("gpu.angle", "DisplayVk::waitNative");
126     return angle::ResultToEGL(waitNativeImpl());
127 }
128 
waitNativeImpl()129 angle::Result DisplayVk::waitNativeImpl()
130 {
131     return angle::Result::Continue;
132 }
133 
createWindowSurface(const egl::SurfaceState & state,EGLNativeWindowType window,const egl::AttributeMap & attribs)134 SurfaceImpl *DisplayVk::createWindowSurface(const egl::SurfaceState &state,
135                                             EGLNativeWindowType window,
136                                             const egl::AttributeMap &attribs)
137 {
138     return createWindowSurfaceVk(state, window);
139 }
140 
createPbufferSurface(const egl::SurfaceState & state,const egl::AttributeMap & attribs)141 SurfaceImpl *DisplayVk::createPbufferSurface(const egl::SurfaceState &state,
142                                              const egl::AttributeMap &attribs)
143 {
144     ASSERT(mRenderer);
145     return new OffscreenSurfaceVk(state, mRenderer);
146 }
147 
createPbufferFromClientBuffer(const egl::SurfaceState & state,EGLenum buftype,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs)148 SurfaceImpl *DisplayVk::createPbufferFromClientBuffer(const egl::SurfaceState &state,
149                                                       EGLenum buftype,
150                                                       EGLClientBuffer clientBuffer,
151                                                       const egl::AttributeMap &attribs)
152 {
153     UNIMPLEMENTED();
154     return static_cast<SurfaceImpl *>(0);
155 }
156 
createPixmapSurface(const egl::SurfaceState & state,NativePixmapType nativePixmap,const egl::AttributeMap & attribs)157 SurfaceImpl *DisplayVk::createPixmapSurface(const egl::SurfaceState &state,
158                                             NativePixmapType nativePixmap,
159                                             const egl::AttributeMap &attribs)
160 {
161     UNIMPLEMENTED();
162     return static_cast<SurfaceImpl *>(0);
163 }
164 
createImage(const egl::ImageState & state,const gl::Context * context,EGLenum target,const egl::AttributeMap & attribs)165 ImageImpl *DisplayVk::createImage(const egl::ImageState &state,
166                                   const gl::Context *context,
167                                   EGLenum target,
168                                   const egl::AttributeMap &attribs)
169 {
170     return new ImageVk(state, context);
171 }
172 
createShareGroup()173 ShareGroupImpl *DisplayVk::createShareGroup()
174 {
175     return new ShareGroupVk();
176 }
177 
createContext(const gl::State & state,gl::ErrorSet * errorSet,const egl::Config * configuration,const gl::Context * shareContext,const egl::AttributeMap & attribs)178 ContextImpl *DisplayVk::createContext(const gl::State &state,
179                                       gl::ErrorSet *errorSet,
180                                       const egl::Config *configuration,
181                                       const gl::Context *shareContext,
182                                       const egl::AttributeMap &attribs)
183 {
184     return new ContextVk(state, errorSet, mRenderer);
185 }
186 
createStreamProducerD3DTexture(egl::Stream::ConsumerType consumerType,const egl::AttributeMap & attribs)187 StreamProducerImpl *DisplayVk::createStreamProducerD3DTexture(
188     egl::Stream::ConsumerType consumerType,
189     const egl::AttributeMap &attribs)
190 {
191     UNIMPLEMENTED();
192     return static_cast<StreamProducerImpl *>(0);
193 }
194 
createSync(const egl::AttributeMap & attribs)195 EGLSyncImpl *DisplayVk::createSync(const egl::AttributeMap &attribs)
196 {
197     return new EGLSyncVk(attribs);
198 }
199 
getMaxSupportedESVersion() const200 gl::Version DisplayVk::getMaxSupportedESVersion() const
201 {
202     return mRenderer->getMaxSupportedESVersion();
203 }
204 
getMaxConformantESVersion() const205 gl::Version DisplayVk::getMaxConformantESVersion() const
206 {
207     return mRenderer->getMaxConformantESVersion();
208 }
209 
validateImageClientBuffer(const gl::Context * context,EGLenum target,EGLClientBuffer clientBuffer,const egl::AttributeMap & attribs) const210 egl::Error DisplayVk::validateImageClientBuffer(const gl::Context *context,
211                                                 EGLenum target,
212                                                 EGLClientBuffer clientBuffer,
213                                                 const egl::AttributeMap &attribs) const
214 {
215     switch (target)
216     {
217         case EGL_VULKAN_IMAGE_ANGLE:
218         {
219             VkImage *vkImage = reinterpret_cast<VkImage *>(clientBuffer);
220             if (!vkImage || *vkImage == VK_NULL_HANDLE)
221             {
222                 return egl::EglBadParameter() << "clientBuffer is invalid.";
223             }
224 
225             GLenum internalFormat =
226                 static_cast<GLenum>(attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_NONE));
227             switch (internalFormat)
228             {
229                 case GL_RGBA:
230                 case GL_BGRA_EXT:
231                 case GL_RGB:
232                 case GL_RED_EXT:
233                 case GL_RG_EXT:
234                 case GL_RGB10_A2_EXT:
235                 case GL_R16_EXT:
236                 case GL_RG16_EXT:
237                 case GL_NONE:
238                     break;
239                 default:
240                     return egl::EglBadParameter() << "Invalid EGLImage texture internal format: 0x"
241                                                   << std::hex << internalFormat;
242             }
243 
244             uint64_t hi = static_cast<uint64_t>(attribs.get(EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE));
245             uint64_t lo = static_cast<uint64_t>(attribs.get(EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE));
246             uint64_t info = ((hi & 0xffffffff) << 32) | (lo & 0xffffffff);
247             if (reinterpret_cast<const VkImageCreateInfo *>(info)->sType !=
248                 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO)
249             {
250                 return egl::EglBadParameter()
251                        << "EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE and "
252                           "EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE are not pointing to a "
253                           "valid VkImageCreateInfo structure.";
254             }
255 
256             return egl::NoError();
257         }
258         default:
259             return DisplayImpl::validateImageClientBuffer(context, target, clientBuffer, attribs);
260     }
261 }
262 
createExternalImageSibling(const gl::Context * context,EGLenum target,EGLClientBuffer buffer,const egl::AttributeMap & attribs)263 ExternalImageSiblingImpl *DisplayVk::createExternalImageSibling(const gl::Context *context,
264                                                                 EGLenum target,
265                                                                 EGLClientBuffer buffer,
266                                                                 const egl::AttributeMap &attribs)
267 {
268     switch (target)
269     {
270         case EGL_VULKAN_IMAGE_ANGLE:
271             return new VkImageImageSiblingVk(buffer, attribs);
272         default:
273             return DisplayImpl::createExternalImageSibling(context, target, buffer, attribs);
274     }
275 }
276 
generateExtensions(egl::DisplayExtensions * outExtensions) const277 void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const
278 {
279     outExtensions->createContextRobustness    = getRenderer()->getNativeExtensions().robustnessEXT;
280     outExtensions->surfaceOrientation         = true;
281     outExtensions->displayTextureShareGroup   = true;
282     outExtensions->displaySemaphoreShareGroup = true;
283     outExtensions->robustResourceInitializationANGLE = true;
284 
285     // The Vulkan implementation will always say that EGL_KHR_swap_buffers_with_damage is supported.
286     // When the Vulkan driver supports VK_KHR_incremental_present, it will use it.  Otherwise, it
287     // will ignore the hint and do a regular swap.
288     outExtensions->swapBuffersWithDamage = true;
289 
290     outExtensions->fenceSync = true;
291     outExtensions->waitSync  = true;
292 
293     outExtensions->image                 = true;
294     outExtensions->imageBase             = true;
295     outExtensions->imagePixmap           = false;  // ANGLE does not support pixmaps
296     outExtensions->glTexture2DImage      = true;
297     outExtensions->glTextureCubemapImage = true;
298     outExtensions->glTexture3DImage      = false;
299     outExtensions->glRenderbufferImage   = true;
300     outExtensions->imageNativeBuffer =
301         getRenderer()->getFeatures().supportsAndroidHardwareBuffer.enabled;
302     outExtensions->surfacelessContext = true;
303     outExtensions->glColorspace       = true;
304     outExtensions->imageGlColorspace =
305         outExtensions->glColorspace && getRenderer()->getFeatures().supportsImageFormatList.enabled;
306 
307 #if defined(ANGLE_PLATFORM_ANDROID)
308     outExtensions->getNativeClientBufferANDROID = true;
309     outExtensions->framebufferTargetANDROID     = true;
310 #endif  // defined(ANGLE_PLATFORM_ANDROID)
311 
312     // EGL_EXT_image_dma_buf_import is only exposed if EGL_EXT_image_dma_buf_import_modifiers can
313     // also be exposed.  The Vulkan extensions that support these EGL extensions are not split in
314     // the same way; both Vulkan extensions are needed for EGL_EXT_image_dma_buf_import, and with
315     // both Vulkan extensions, EGL_EXT_image_dma_buf_import_modifiers is also supportable.
316     outExtensions->imageDmaBufImportEXT =
317         getRenderer()->getFeatures().supportsExternalMemoryDmaBufAndModifiers.enabled;
318     outExtensions->imageDmaBufImportModifiersEXT = outExtensions->imageDmaBufImportEXT;
319 
320     // Disable context priority when non-zero memory init is enabled. This enforces a queue order.
321     outExtensions->contextPriority = !getRenderer()->getFeatures().allocateNonZeroMemory.enabled;
322     outExtensions->noConfigContext = true;
323 
324 #if defined(ANGLE_PLATFORM_ANDROID)
325     outExtensions->nativeFenceSyncANDROID =
326         getRenderer()->getFeatures().supportsAndroidNativeFenceSync.enabled;
327 #endif  // defined(ANGLE_PLATFORM_ANDROID)
328 
329 #if defined(ANGLE_PLATFORM_GGP)
330     outExtensions->ggpStreamDescriptor = true;
331     outExtensions->swapWithFrameToken  = getRenderer()->getFeatures().supportsGGPFrameToken.enabled;
332 #endif  // defined(ANGLE_PLATFORM_GGP)
333 
334     outExtensions->bufferAgeEXT = true;
335 
336     outExtensions->protectedContentEXT =
337         (getRenderer()->getFeatures().supportsProtectedMemory.enabled &&
338          getRenderer()->getFeatures().supportsSurfaceProtectedSwapchains.enabled);
339 
340     outExtensions->createSurfaceSwapIntervalANGLE = true;
341 
342     outExtensions->mutableRenderBufferKHR =
343         getRenderer()->getFeatures().supportsSharedPresentableImageExtension.enabled;
344 
345     outExtensions->vulkanImageANGLE = true;
346 
347     outExtensions->lockSurface3KHR =
348         getRenderer()->getFeatures().supportsLockSurfaceExtension.enabled;
349 
350     outExtensions->partialUpdateKHR = true;
351 }
352 
generateCaps(egl::Caps * outCaps) const353 void DisplayVk::generateCaps(egl::Caps *outCaps) const
354 {
355     outCaps->textureNPOT = true;
356     outCaps->stencil8    = getRenderer()->getNativeExtensions().textureStencil8OES;
357 }
358 
getWSILayer() const359 const char *DisplayVk::getWSILayer() const
360 {
361     return nullptr;
362 }
363 
isUsingSwapchain() const364 bool DisplayVk::isUsingSwapchain() const
365 {
366     return true;
367 }
368 
getScratchBuffer(size_t requstedSizeBytes,angle::MemoryBuffer ** scratchBufferOut) const369 bool DisplayVk::getScratchBuffer(size_t requstedSizeBytes,
370                                  angle::MemoryBuffer **scratchBufferOut) const
371 {
372     return mScratchBuffer.get(requstedSizeBytes, scratchBufferOut);
373 }
374 
handleError(VkResult result,const char * file,const char * function,unsigned int line)375 void DisplayVk::handleError(VkResult result,
376                             const char *file,
377                             const char *function,
378                             unsigned int line)
379 {
380     ASSERT(result != VK_SUCCESS);
381 
382     mSavedError.errorCode = result;
383     mSavedError.file      = file;
384     mSavedError.function  = function;
385     mSavedError.line      = line;
386 
387     if (result == VK_ERROR_DEVICE_LOST)
388     {
389         WARN() << "Internal Vulkan error (" << result << "): " << VulkanResultString(result)
390                << ", in " << file << ", " << function << ":" << line << ".";
391         mRenderer->notifyDeviceLost();
392     }
393 }
394 
395 // TODO(jmadill): Remove this. http://anglebug.com/3041
getEGLError(EGLint errorCode)396 egl::Error DisplayVk::getEGLError(EGLint errorCode)
397 {
398     std::stringstream errorStream;
399     errorStream << "Internal Vulkan error (" << mSavedError.errorCode
400                 << "): " << VulkanResultString(mSavedError.errorCode) << ", in " << mSavedError.file
401                 << ", " << mSavedError.function << ":" << mSavedError.line << ".";
402     std::string errorString = errorStream.str();
403 
404     return egl::Error(errorCode, 0, std::move(errorString));
405 }
406 
initializeFrontendFeatures(angle::FrontendFeatures * features) const407 void DisplayVk::initializeFrontendFeatures(angle::FrontendFeatures *features) const
408 {
409     mRenderer->initializeFrontendFeatures(features);
410 }
411 
populateFeatureList(angle::FeatureList * features)412 void DisplayVk::populateFeatureList(angle::FeatureList *features)
413 {
414     mRenderer->getFeatures().populateFeatureList(features);
415 }
416 
ShareGroupVk()417 ShareGroupVk::ShareGroupVk()
418 {
419     mLastPruneTime             = angle::GetCurrentSystemTime();
420     mOrphanNonEmptyBufferBlock = false;
421 }
422 
addContext(ContextVk * contextVk)423 void ShareGroupVk::addContext(ContextVk *contextVk)
424 {
425     mContexts.insert(contextVk);
426 
427     if (contextVk->getState().hasDisplayTextureShareGroup())
428     {
429         mOrphanNonEmptyBufferBlock = true;
430     }
431 }
432 
removeContext(ContextVk * contextVk)433 void ShareGroupVk::removeContext(ContextVk *contextVk)
434 {
435     mContexts.erase(contextVk);
436 }
437 
onDestroy(const egl::Display * display)438 void ShareGroupVk::onDestroy(const egl::Display *display)
439 {
440     RendererVk *renderer = vk::GetImpl(display)->getRenderer();
441 
442     for (std::unique_ptr<vk::BufferPool> &pool : mDefaultBufferPools)
443     {
444         if (pool)
445         {
446             pool->destroy(renderer, mOrphanNonEmptyBufferBlock);
447         }
448     }
449 
450     if (mSmallBufferPool)
451     {
452         mSmallBufferPool->destroy(renderer, mOrphanNonEmptyBufferBlock);
453     }
454 
455     mPipelineLayoutCache.destroy(renderer);
456     mDescriptorSetLayoutCache.destroy(renderer);
457 
458     ASSERT(mResourceUseLists.empty());
459 }
460 
releaseResourceUseLists(const Serial & submitSerial)461 void ShareGroupVk::releaseResourceUseLists(const Serial &submitSerial)
462 {
463     if (!mResourceUseLists.empty())
464     {
465         for (vk::ResourceUseList &it : mResourceUseLists)
466         {
467             it.releaseResourceUsesAndUpdateSerials(submitSerial);
468         }
469         mResourceUseLists.clear();
470     }
471 }
472 
getDefaultBufferPool(RendererVk * renderer,VkDeviceSize size,uint32_t memoryTypeIndex)473 vk::BufferPool *ShareGroupVk::getDefaultBufferPool(RendererVk *renderer,
474                                                    VkDeviceSize size,
475                                                    uint32_t memoryTypeIndex)
476 {
477     if (size <= kMaxSizeToUseSmallBufferPool &&
478         memoryTypeIndex ==
479             renderer->getVertexConversionBufferMemoryTypeIndex(vk::MemoryHostVisibility::Visible))
480     {
481         if (!mSmallBufferPool)
482         {
483             const vk::Allocator &allocator = renderer->getAllocator();
484             VkBufferUsageFlags usageFlags  = GetDefaultBufferUsageFlags(renderer);
485 
486             VkMemoryPropertyFlags memoryPropertyFlags;
487             allocator.getMemoryTypeProperties(memoryTypeIndex, &memoryPropertyFlags);
488 
489             std::unique_ptr<vk::BufferPool> pool = std::make_unique<vk::BufferPool>();
490             pool->initWithFlags(renderer, vma::VirtualBlockCreateFlagBits::BUDDY, usageFlags, 0,
491                                 memoryTypeIndex, memoryPropertyFlags);
492             mSmallBufferPool = std::move(pool);
493         }
494         return mSmallBufferPool.get();
495     }
496     else if (!mDefaultBufferPools[memoryTypeIndex])
497     {
498         const vk::Allocator &allocator = renderer->getAllocator();
499         VkBufferUsageFlags usageFlags  = GetDefaultBufferUsageFlags(renderer);
500 
501         VkMemoryPropertyFlags memoryPropertyFlags;
502         allocator.getMemoryTypeProperties(memoryTypeIndex, &memoryPropertyFlags);
503 
504         std::unique_ptr<vk::BufferPool> pool = std::make_unique<vk::BufferPool>();
505         pool->initWithFlags(renderer, vma::VirtualBlockCreateFlagBits::GENERAL, usageFlags, 0,
506                             memoryTypeIndex, memoryPropertyFlags);
507         mDefaultBufferPools[memoryTypeIndex] = std::move(pool);
508     }
509 
510     return mDefaultBufferPools[memoryTypeIndex].get();
511 }
512 
pruneDefaultBufferPools(RendererVk * renderer)513 void ShareGroupVk::pruneDefaultBufferPools(RendererVk *renderer)
514 {
515     mLastPruneTime = angle::GetCurrentSystemTime();
516 
517     for (std::unique_ptr<vk::BufferPool> &pool : mDefaultBufferPools)
518     {
519         if (pool)
520         {
521             pool->pruneEmptyBuffers(renderer);
522         }
523     }
524     if (mSmallBufferPool)
525     {
526         mSmallBufferPool->pruneEmptyBuffers(renderer);
527     }
528 }
529 
isDueForBufferPoolPrune()530 bool ShareGroupVk::isDueForBufferPoolPrune()
531 {
532     double timeElapsed = angle::GetCurrentSystemTime() - mLastPruneTime;
533     return timeElapsed > kTimeElapsedForPruneDefaultBufferPool;
534 }
535 }  // namespace rx
536