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