| // |
| // Copyright 2016 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // DisplayVk.cpp: |
| // Implements the class methods for DisplayVk. |
| // |
| |
| #include "libANGLE/renderer/vulkan/DisplayVk.h" |
| |
| #include "common/debug.h" |
| #include "common/system_utils.h" |
| #include "libANGLE/BlobCache.h" |
| #include "libANGLE/Context.h" |
| #include "libANGLE/Display.h" |
| #include "libANGLE/renderer/vulkan/BufferVk.h" |
| #include "libANGLE/renderer/vulkan/ContextVk.h" |
| #include "libANGLE/renderer/vulkan/DeviceVk.h" |
| #include "libANGLE/renderer/vulkan/ImageVk.h" |
| #include "libANGLE/renderer/vulkan/ShareGroupVk.h" |
| #include "libANGLE/renderer/vulkan/SurfaceVk.h" |
| #include "libANGLE/renderer/vulkan/SyncVk.h" |
| #include "libANGLE/renderer/vulkan/TextureVk.h" |
| #include "libANGLE/renderer/vulkan/VkImageImageSiblingVk.h" |
| #include "libANGLE/renderer/vulkan/vk_helpers.h" |
| #include "libANGLE/renderer/vulkan/vk_renderer.h" |
| |
| namespace rx |
| { |
| |
| namespace |
| { |
| // Query surface format and colorspace support. |
| void GetSupportedFormatColorspaces(VkPhysicalDevice physicalDevice, |
| const angle::FeaturesVk &featuresVk, |
| VkSurfaceKHR surface, |
| std::vector<VkSurfaceFormat2KHR> *surfaceFormatsOut) |
| { |
| ASSERT(surfaceFormatsOut); |
| surfaceFormatsOut->clear(); |
| |
| constexpr VkSurfaceFormat2KHR kSurfaceFormat2Initializer = { |
| VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR, |
| nullptr, |
| {VK_FORMAT_UNDEFINED, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}}; |
| |
| if (featuresVk.supportsSurfaceCapabilities2Extension.enabled) |
| { |
| VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2 = {}; |
| surfaceInfo2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR; |
| surfaceInfo2.surface = surface; |
| uint32_t surfaceFormatCount = 0; |
| |
| // Query the count first |
| VkResult result = vkGetPhysicalDeviceSurfaceFormats2KHR(physicalDevice, &surfaceInfo2, |
| &surfaceFormatCount, nullptr); |
| ASSERT(result == VK_SUCCESS); |
| ASSERT(surfaceFormatCount > 0); |
| |
| // Query the VkSurfaceFormat2KHR list |
| std::vector<VkSurfaceFormat2KHR> surfaceFormats2(surfaceFormatCount, |
| kSurfaceFormat2Initializer); |
| result = vkGetPhysicalDeviceSurfaceFormats2KHR(physicalDevice, &surfaceInfo2, |
| &surfaceFormatCount, surfaceFormats2.data()); |
| ASSERT(result == VK_SUCCESS); |
| |
| *surfaceFormatsOut = std::move(surfaceFormats2); |
| } |
| else |
| { |
| uint32_t surfaceFormatCount = 0; |
| // Query the count first |
| VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, |
| &surfaceFormatCount, nullptr); |
| ASSERT(result == VK_SUCCESS); |
| |
| // Query the VkSurfaceFormatKHR list |
| std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount); |
| result = vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount, |
| surfaceFormats.data()); |
| ASSERT(result == VK_SUCCESS); |
| |
| // Copy over data from std::vector<VkSurfaceFormatKHR> to std::vector<VkSurfaceFormat2KHR> |
| std::vector<VkSurfaceFormat2KHR> surfaceFormats2(surfaceFormatCount, |
| kSurfaceFormat2Initializer); |
| for (size_t index = 0; index < surfaceFormatCount; index++) |
| { |
| surfaceFormats2[index].surfaceFormat.format = surfaceFormats[index].format; |
| } |
| |
| *surfaceFormatsOut = std::move(surfaceFormats2); |
| } |
| } |
| |
| vk::UseDebugLayers ShouldLoadDebugLayers(const egl::AttributeMap &attribs) |
| { |
| EGLAttrib debugSetting = |
| attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE); |
| |
| #if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT) |
| const bool yes = ShouldUseDebugLayers(attribs); |
| #else |
| const bool yes = debugSetting == EGL_TRUE; |
| #endif // defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT) |
| |
| const bool ifAvailable = debugSetting == EGL_DONT_CARE; |
| |
| return yes && ifAvailable ? vk::UseDebugLayers::YesIfAvailable |
| : yes ? vk::UseDebugLayers::Yes |
| : vk::UseDebugLayers::No; |
| } |
| |
| angle::vk::ICD ChooseICDFromAttribs(const egl::AttributeMap &attribs) |
| { |
| #if !defined(ANGLE_PLATFORM_ANDROID) |
| // Mock ICD does not currently run on Android |
| EGLAttrib deviceType = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, |
| EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); |
| |
| switch (deviceType) |
| { |
| case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: |
| break; |
| case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: |
| return angle::vk::ICD::Mock; |
| case EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE: |
| return angle::vk::ICD::SwiftShader; |
| default: |
| UNREACHABLE(); |
| break; |
| } |
| #endif // !defined(ANGLE_PLATFORM_ANDROID) |
| |
| return angle::vk::ICD::Default; |
| } |
| |
| void InstallDebugAnnotator(egl::Display *display, vk::Renderer *renderer) |
| { |
| bool installedAnnotator = false; |
| |
| // Ensure the appropriate global DebugAnnotator is used |
| ASSERT(renderer); |
| renderer->setGlobalDebugAnnotator(&installedAnnotator); |
| |
| if (!installedAnnotator) |
| { |
| std::unique_lock<angle::SimpleMutex> lock(gl::GetDebugMutex()); |
| display->setGlobalDebugAnnotator(); |
| } |
| } |
| } // namespace |
| |
| DisplayVk::DisplayVk(const egl::DisplayState &state) |
| : DisplayImpl(state), |
| vk::ErrorContext(new vk::Renderer()), |
| mScratchBuffer(1000u), |
| mSupportedColorspaceFormatsMap{} |
| {} |
| |
| DisplayVk::~DisplayVk() |
| { |
| delete mRenderer; |
| } |
| |
| egl::Error DisplayVk::initialize(egl::Display *display) |
| { |
| ASSERT(mRenderer != nullptr && display != nullptr); |
| const egl::AttributeMap &attribs = display->getAttributeMap(); |
| |
| const vk::UseDebugLayers useDebugLayers = ShouldLoadDebugLayers(attribs); |
| const angle::vk::ICD desiredICD = ChooseICDFromAttribs(attribs); |
| const uint32_t preferredVendorId = |
| static_cast<uint32_t>(attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, 0)); |
| const uint32_t preferredDeviceId = |
| static_cast<uint32_t>(attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, 0)); |
| const uint8_t *preferredDeviceUuid = reinterpret_cast<const uint8_t *>( |
| attribs.get(EGL_PLATFORM_ANGLE_VULKAN_DEVICE_UUID_ANGLE, 0)); |
| const uint8_t *preferredDriverUuid = reinterpret_cast<const uint8_t *>( |
| attribs.get(EGL_PLATFORM_ANGLE_VULKAN_DRIVER_UUID_ANGLE, 0)); |
| const VkDriverId preferredDriverId = |
| static_cast<VkDriverId>(attribs.get(EGL_PLATFORM_ANGLE_VULKAN_DRIVER_ID_ANGLE, 0)); |
| |
| angle::Result result = mRenderer->initialize( |
| this, this, desiredICD, preferredVendorId, preferredDeviceId, preferredDeviceUuid, |
| preferredDriverUuid, preferredDriverId, useDebugLayers, getWSIExtension(), getWSILayer(), |
| getWindowSystem(), mState.featureOverrides); |
| ANGLE_TRY(angle::ToEGL(result, EGL_NOT_INITIALIZED)); |
| |
| mDeviceQueueIndex = mRenderer->getDeviceQueueIndex(egl::ContextPriority::Medium); |
| |
| InstallDebugAnnotator(display, mRenderer); |
| |
| // Query and cache supported surface format and colorspace for later use. |
| initSupportedSurfaceFormatColorspaces(); |
| return egl::NoError(); |
| } |
| |
| void DisplayVk::terminate() |
| { |
| mRenderer->reloadVolkIfNeeded(); |
| |
| ASSERT(mRenderer); |
| mRenderer->onDestroy(this); |
| } |
| |
| egl::Error DisplayVk::makeCurrent(egl::Display *display, |
| egl::Surface * /*drawSurface*/, |
| egl::Surface * /*readSurface*/, |
| gl::Context * /*context*/) |
| { |
| InstallDebugAnnotator(display, mRenderer); |
| return egl::NoError(); |
| } |
| |
| bool DisplayVk::testDeviceLost() |
| { |
| return mRenderer->isDeviceLost(); |
| } |
| |
| egl::Error DisplayVk::restoreLostDevice(const egl::Display *display) |
| { |
| // A vulkan device cannot be restored, the entire renderer would have to be re-created along |
| // with any other EGL objects that reference it. |
| return egl::Error(EGL_BAD_DISPLAY); |
| } |
| |
| std::string DisplayVk::getRendererDescription() |
| { |
| if (mRenderer) |
| { |
| return mRenderer->getRendererDescription(); |
| } |
| return std::string(); |
| } |
| |
| std::string DisplayVk::getVendorString() |
| { |
| if (mRenderer) |
| { |
| return mRenderer->getVendorString(); |
| } |
| return std::string(); |
| } |
| |
| std::string DisplayVk::getVersionString(bool includeFullVersion) |
| { |
| if (mRenderer) |
| { |
| return mRenderer->getVersionString(includeFullVersion); |
| } |
| return std::string(); |
| } |
| |
| DeviceImpl *DisplayVk::createDevice() |
| { |
| return new DeviceVk(); |
| } |
| |
| egl::Error DisplayVk::waitClient(const gl::Context *context) |
| { |
| ANGLE_TRACE_EVENT0("gpu.angle", "DisplayVk::waitClient"); |
| ContextVk *contextVk = vk::GetImpl(context); |
| return angle::ToEGL(contextVk->finishImpl(RenderPassClosureReason::EGLWaitClient), |
| EGL_BAD_ACCESS); |
| } |
| |
| egl::Error DisplayVk::waitNative(const gl::Context *context, EGLint engine) |
| { |
| ANGLE_TRACE_EVENT0("gpu.angle", "DisplayVk::waitNative"); |
| return angle::ResultToEGL(waitNativeImpl()); |
| } |
| |
| angle::Result DisplayVk::waitNativeImpl() |
| { |
| return angle::Result::Continue; |
| } |
| |
| SurfaceImpl *DisplayVk::createWindowSurface(const egl::SurfaceState &state, |
| EGLNativeWindowType window, |
| const egl::AttributeMap &attribs) |
| { |
| return createWindowSurfaceVk(state, window); |
| } |
| |
| SurfaceImpl *DisplayVk::createPbufferSurface(const egl::SurfaceState &state, |
| const egl::AttributeMap &attribs) |
| { |
| ASSERT(mRenderer); |
| return new OffscreenSurfaceVk(state, mRenderer); |
| } |
| |
| SurfaceImpl *DisplayVk::createPbufferFromClientBuffer(const egl::SurfaceState &state, |
| EGLenum buftype, |
| EGLClientBuffer clientBuffer, |
| const egl::AttributeMap &attribs) |
| { |
| UNIMPLEMENTED(); |
| return static_cast<SurfaceImpl *>(0); |
| } |
| |
| SurfaceImpl *DisplayVk::createPixmapSurface(const egl::SurfaceState &state, |
| NativePixmapType nativePixmap, |
| const egl::AttributeMap &attribs) |
| { |
| UNIMPLEMENTED(); |
| return static_cast<SurfaceImpl *>(0); |
| } |
| |
| ImageImpl *DisplayVk::createImage(const egl::ImageState &state, |
| const gl::Context *context, |
| EGLenum target, |
| const egl::AttributeMap &attribs) |
| { |
| return new ImageVk(state, context); |
| } |
| |
| ShareGroupImpl *DisplayVk::createShareGroup(const egl::ShareGroupState &state) |
| { |
| return new ShareGroupVk(state, mRenderer); |
| } |
| |
| bool DisplayVk::isConfigFormatSupported(VkFormat format) const |
| { |
| // Requires VK_GOOGLE_surfaceless_query extension to be supported. |
| ASSERT(mRenderer->getFeatures().supportsSurfacelessQueryExtension.enabled); |
| |
| // A format is considered supported if it is supported in atleast 1 colorspace. |
| using ColorspaceFormatSetItem = |
| const std::pair<const VkColorSpaceKHR, std::unordered_set<VkFormat>>; |
| for (ColorspaceFormatSetItem &colorspaceFormatSetItem : mSupportedColorspaceFormatsMap) |
| { |
| if (colorspaceFormatSetItem.second.count(format) > 0) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| bool DisplayVk::isSurfaceFormatColorspacePairSupported(VkSurfaceKHR surface, |
| VkFormat format, |
| VkColorSpaceKHR colorspace) const |
| { |
| if (mSupportedColorspaceFormatsMap.size() > 0) |
| { |
| return mSupportedColorspaceFormatsMap.count(colorspace) > 0 && |
| mSupportedColorspaceFormatsMap.at(colorspace).count(format) > 0; |
| } |
| else |
| { |
| const angle::FeaturesVk &featuresVk = mRenderer->getFeatures(); |
| std::vector<VkSurfaceFormat2KHR> surfaceFormats; |
| GetSupportedFormatColorspaces(mRenderer->getPhysicalDevice(), featuresVk, surface, |
| &surfaceFormats); |
| |
| if (!featuresVk.supportsSurfaceCapabilities2Extension.enabled) |
| { |
| if (surfaceFormats.size() == 1u && |
| surfaceFormats[0].surfaceFormat.format == VK_FORMAT_UNDEFINED) |
| { |
| return true; |
| } |
| } |
| |
| for (const VkSurfaceFormat2KHR &surfaceFormat : surfaceFormats) |
| { |
| if (surfaceFormat.surfaceFormat.format == format && |
| surfaceFormat.surfaceFormat.colorSpace == colorspace) |
| { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| bool DisplayVk::isColorspaceSupported(VkColorSpaceKHR colorspace) const |
| { |
| return mSupportedColorspaceFormatsMap.count(colorspace) > 0; |
| } |
| |
| void DisplayVk::initSupportedSurfaceFormatColorspaces() |
| { |
| const angle::FeaturesVk &featuresVk = mRenderer->getFeatures(); |
| if (featuresVk.supportsSurfacelessQueryExtension.enabled && |
| featuresVk.supportsSurfaceCapabilities2Extension.enabled) |
| { |
| // Use the VK_GOOGLE_surfaceless_query extension to query supported surface formats and |
| // colorspaces by using a VK_NULL_HANDLE for the VkSurfaceKHR handle. |
| std::vector<VkSurfaceFormat2KHR> surfaceFormats; |
| GetSupportedFormatColorspaces(mRenderer->getPhysicalDevice(), featuresVk, VK_NULL_HANDLE, |
| &surfaceFormats); |
| for (const VkSurfaceFormat2KHR &surfaceFormat : surfaceFormats) |
| { |
| // Cache supported VkFormat and VkColorSpaceKHR for later use |
| VkFormat format = surfaceFormat.surfaceFormat.format; |
| VkColorSpaceKHR colorspace = surfaceFormat.surfaceFormat.colorSpace; |
| |
| ASSERT(format != VK_FORMAT_UNDEFINED); |
| |
| mSupportedColorspaceFormatsMap[colorspace].insert(format); |
| } |
| |
| ASSERT(mSupportedColorspaceFormatsMap.size() > 0); |
| } |
| else |
| { |
| mSupportedColorspaceFormatsMap.clear(); |
| } |
| } |
| |
| ContextImpl *DisplayVk::createContext(const gl::State &state, |
| gl::ErrorSet *errorSet, |
| const egl::Config *configuration, |
| const gl::Context *shareContext, |
| const egl::AttributeMap &attribs) |
| { |
| return new ContextVk(state, errorSet, mRenderer); |
| } |
| |
| StreamProducerImpl *DisplayVk::createStreamProducerD3DTexture( |
| egl::Stream::ConsumerType consumerType, |
| const egl::AttributeMap &attribs) |
| { |
| UNIMPLEMENTED(); |
| return static_cast<StreamProducerImpl *>(0); |
| } |
| |
| EGLSyncImpl *DisplayVk::createSync() |
| { |
| return new EGLSyncVk(); |
| } |
| |
| gl::Version DisplayVk::getMaxSupportedESVersion() const |
| { |
| return mRenderer->getMaxSupportedESVersion(); |
| } |
| |
| gl::Version DisplayVk::getMaxConformantESVersion() const |
| { |
| return mRenderer->getMaxConformantESVersion(); |
| } |
| |
| egl::Error DisplayVk::validateImageClientBuffer(const gl::Context *context, |
| EGLenum target, |
| EGLClientBuffer clientBuffer, |
| const egl::AttributeMap &attribs) const |
| { |
| switch (target) |
| { |
| case EGL_VULKAN_IMAGE_ANGLE: |
| { |
| VkImage *vkImage = reinterpret_cast<VkImage *>(clientBuffer); |
| if (!vkImage || *vkImage == VK_NULL_HANDLE) |
| { |
| return egl::Error(EGL_BAD_PARAMETER, "clientBuffer is invalid."); |
| } |
| |
| GLenum internalFormat = |
| static_cast<GLenum>(attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_NONE)); |
| switch (internalFormat) |
| { |
| case GL_RGBA: |
| case GL_BGRA_EXT: |
| case GL_RGB: |
| case GL_RED_EXT: |
| case GL_RG_EXT: |
| case GL_RGB10_A2_EXT: |
| case GL_R16_EXT: |
| case GL_RG16_EXT: |
| case GL_NONE: |
| break; |
| default: |
| std::ostringstream err; |
| err << "Invalid EGLImage texture internal format: 0x" << std::hex |
| << internalFormat; |
| return egl::Error(EGL_BAD_PARAMETER, err.str()); |
| } |
| |
| uint64_t hi = static_cast<uint64_t>(attribs.get(EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE)); |
| uint64_t lo = static_cast<uint64_t>(attribs.get(EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE)); |
| uint64_t info = ((hi & 0xffffffff) << 32) | (lo & 0xffffffff); |
| if (reinterpret_cast<const VkImageCreateInfo *>(info)->sType != |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO) |
| { |
| return egl::Error(EGL_BAD_PARAMETER, |
| "EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE and " |
| "EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE are not pointing to a " |
| "valid VkImageCreateInfo structure."); |
| } |
| |
| return egl::NoError(); |
| } |
| default: |
| return DisplayImpl::validateImageClientBuffer(context, target, clientBuffer, attribs); |
| } |
| } |
| |
| ExternalImageSiblingImpl *DisplayVk::createExternalImageSibling(const gl::Context *context, |
| EGLenum target, |
| EGLClientBuffer buffer, |
| const egl::AttributeMap &attribs) |
| { |
| switch (target) |
| { |
| case EGL_VULKAN_IMAGE_ANGLE: |
| return new VkImageImageSiblingVk(buffer, attribs); |
| default: |
| return DisplayImpl::createExternalImageSibling(context, target, buffer, attribs); |
| } |
| } |
| |
| void DisplayVk::generateExtensions(egl::DisplayExtensions *outExtensions) const |
| { |
| outExtensions->createContextRobustness = getRenderer()->getNativeExtensions().robustnessAny(); |
| outExtensions->surfaceOrientation = true; |
| outExtensions->displayTextureShareGroup = true; |
| outExtensions->displaySemaphoreShareGroup = true; |
| outExtensions->robustResourceInitializationANGLE = true; |
| |
| // The Vulkan implementation will always say that EGL_KHR_swap_buffers_with_damage is supported. |
| // When the Vulkan driver supports VK_KHR_incremental_present, it will use it. Otherwise, it |
| // will ignore the hint and do a regular swap. |
| outExtensions->swapBuffersWithDamage = true; |
| |
| outExtensions->fenceSync = true; |
| outExtensions->waitSync = true; |
| outExtensions->globalFenceSyncANGLE = true; |
| |
| outExtensions->image = true; |
| outExtensions->imageBase = true; |
| outExtensions->imagePixmap = false; // ANGLE does not support pixmaps |
| outExtensions->glTexture2DImage = true; |
| outExtensions->glTextureCubemapImage = true; |
| outExtensions->glTexture3DImage = getFeatures().supportsSampler2dViewOf3d.enabled; |
| outExtensions->glRenderbufferImage = true; |
| outExtensions->imageNativeBuffer = getFeatures().supportsAndroidHardwareBuffer.enabled; |
| outExtensions->surfacelessContext = true; |
| outExtensions->glColorspace = true; |
| outExtensions->imageGlColorspace = |
| outExtensions->glColorspace && getFeatures().supportsImageFormatList.enabled; |
| |
| #if defined(ANGLE_PLATFORM_ANDROID) |
| outExtensions->getNativeClientBufferANDROID = true; |
| outExtensions->framebufferTargetANDROID = true; |
| |
| // Only expose EGL_ANDROID_front_buffer_auto_refresh on Android and when Vulkan supports |
| // VK_EXT_swapchain_maintenance1 (supportsSwapchainMaintenance1 feature), since we know that |
| // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR and VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR |
| // are compatible on Android (does not require swapchain recreation). |
| outExtensions->frontBufferAutoRefreshANDROID = |
| getFeatures().supportsSwapchainMaintenance1.enabled; |
| #endif // defined(ANGLE_PLATFORM_ANDROID) |
| |
| // EGL_EXT_image_dma_buf_import is only exposed if EGL_EXT_image_dma_buf_import_modifiers can |
| // also be exposed. The Vulkan extensions that support these EGL extensions are not split in |
| // the same way; both Vulkan extensions are needed for EGL_EXT_image_dma_buf_import, and with |
| // both Vulkan extensions, EGL_EXT_image_dma_buf_import_modifiers is also supportable. |
| outExtensions->imageDmaBufImportEXT = |
| getFeatures().supportsExternalMemoryDmaBufAndModifiers.enabled; |
| outExtensions->imageDmaBufImportModifiersEXT = outExtensions->imageDmaBufImportEXT; |
| |
| // Disable context priority when non-zero memory init is enabled. This enforces a queue order. |
| outExtensions->contextPriority = !getFeatures().allocateNonZeroMemory.enabled; |
| outExtensions->noConfigContext = true; |
| |
| #if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) |
| outExtensions->nativeFenceSyncANDROID = getFeatures().supportsAndroidNativeFenceSync.enabled; |
| #endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) |
| |
| outExtensions->bufferAgeEXT = true; |
| |
| outExtensions->protectedContentEXT = (getFeatures().supportsProtectedMemory.enabled && |
| getFeatures().supportsSurfaceProtectedSwapchains.enabled); |
| |
| outExtensions->createSurfaceSwapIntervalANGLE = true; |
| |
| outExtensions->mutableRenderBufferKHR = |
| getFeatures().supportsSharedPresentableImageExtension.enabled; |
| |
| outExtensions->vulkanImageANGLE = true; |
| |
| outExtensions->lockSurface3KHR = getFeatures().supportsLockSurfaceExtension.enabled; |
| |
| outExtensions->partialUpdateKHR = true; |
| |
| outExtensions->timestampSurfaceAttributeANGLE = |
| getFeatures().supportsTimestampSurfaceAttribute.enabled; |
| |
| outExtensions->eglColorspaceAttributePassthroughANGLE = |
| outExtensions->glColorspace && getFeatures().eglColorspaceAttributePassthrough.enabled; |
| |
| // If EGL_KHR_gl_colorspace extension is supported check if other colorspace extensions |
| // can be supported as well. |
| if (outExtensions->glColorspace) |
| { |
| if (isColorspaceSupported(VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT)) |
| { |
| outExtensions->glColorspaceDisplayP3 = true; |
| outExtensions->glColorspaceDisplayP3Passthrough = true; |
| } |
| |
| outExtensions->glColorspaceDisplayP3Linear = |
| isColorspaceSupported(VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT); |
| outExtensions->glColorspaceScrgb = |
| isColorspaceSupported(VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT); |
| outExtensions->glColorspaceScrgbLinear = |
| isColorspaceSupported(VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT); |
| outExtensions->glColorspaceBt2020Linear = |
| isColorspaceSupported(VK_COLOR_SPACE_BT2020_LINEAR_EXT); |
| outExtensions->glColorspaceBt2020Pq = |
| isColorspaceSupported(VK_COLOR_SPACE_HDR10_ST2084_EXT); |
| outExtensions->glColorspaceBt2020Hlg = isColorspaceSupported(VK_COLOR_SPACE_HDR10_HLG_EXT); |
| } |
| |
| outExtensions->surfaceCompressionEXT = |
| getFeatures().supportsImageCompressionControlSwapchain.enabled; |
| } |
| |
| void DisplayVk::generateCaps(egl::Caps *outCaps) const |
| { |
| outCaps->textureNPOT = true; |
| outCaps->stencil8 = getRenderer()->getNativeExtensions().textureStencil8OES; |
| } |
| |
| const char *DisplayVk::getWSILayer() const |
| { |
| return nullptr; |
| } |
| |
| void DisplayVk::handleError(VkResult result, |
| const char *file, |
| const char *function, |
| unsigned int line) |
| { |
| ASSERT(result != VK_SUCCESS); |
| |
| std::stringstream errorStream; |
| errorStream << "Internal Vulkan error (" << result << "): " << VulkanResultString(result) |
| << ", in " << file << ", " << function << ":" << line << "."; |
| std::string errorString = errorStream.str(); |
| |
| if (result == VK_ERROR_DEVICE_LOST) |
| { |
| WARN() << errorString; |
| mRenderer->notifyDeviceLost(); |
| } |
| |
| // Note: the errorCode will be set later in angle::ToEGL where it's available. |
| *egl::Display::GetCurrentThreadErrorScratchSpace() = egl::Error(0, 0, std::move(errorString)); |
| } |
| |
| void DisplayVk::initializeFrontendFeatures(angle::FrontendFeatures *features) const |
| { |
| mRenderer->initializeFrontendFeatures(features); |
| } |
| |
| void DisplayVk::populateFeatureList(angle::FeatureList *features) |
| { |
| mRenderer->getFeatures().populateFeatureList(features); |
| } |
| |
| // vk::GlobalOps |
| void DisplayVk::putBlob(const angle::BlobCacheKey &key, const angle::MemoryBuffer &value) |
| { |
| getBlobCache()->putApplication(nullptr, key, value); |
| } |
| |
| bool DisplayVk::getBlob(const angle::BlobCacheKey &key, angle::BlobCacheValue *valueOut) |
| { |
| return getBlobCache()->get(nullptr, &mScratchBuffer, key, valueOut); |
| } |
| |
| std::shared_ptr<angle::WaitableEvent> DisplayVk::postMultiThreadWorkerTask( |
| const std::shared_ptr<angle::Closure> &task) |
| { |
| return mState.multiThreadPool->postWorkerTask(task); |
| } |
| |
| void DisplayVk::notifyDeviceLost() |
| { |
| mState.notifyDeviceLost(); |
| } |
| |
| void DisplayVk::lockVulkanQueue() |
| { |
| mRenderer->lockVulkanQueueForExternalAccess(); |
| } |
| |
| void DisplayVk::unlockVulkanQueue() |
| { |
| mRenderer->unlockVulkanQueueForExternalAccess(); |
| } |
| |
| egl::Error DisplayVk::querySupportedCompressionRates(const egl::Config *configuration, |
| const egl::AttributeMap &attributes, |
| EGLint *rates, |
| EGLint rate_size, |
| EGLint *num_rates) const |
| { |
| ASSERT(mRenderer->getFeatures().supportsImageCompressionControl.enabled); |
| ASSERT(mRenderer->getFeatures().supportsImageCompressionControlSwapchain.enabled); |
| |
| if (rate_size == 0 || rates == nullptr) |
| { |
| *num_rates = 0; |
| return egl::NoError(); |
| } |
| |
| const vk::Format &format = mRenderer->getFormat(configuration->renderTargetFormat); |
| |
| VkImageCompressionControlEXT compressionInfo = {}; |
| compressionInfo.sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT; |
| compressionInfo.flags = VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT; |
| compressionInfo.compressionControlPlaneCount = 1; |
| |
| VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {}; |
| imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; |
| imageFormatInfo.pNext = &compressionInfo; |
| imageFormatInfo.format = |
| vk::GetVkFormatFromFormatID(mRenderer, format.getActualRenderableImageFormatID()); |
| imageFormatInfo.type = VK_IMAGE_TYPE_2D; |
| imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL; |
| imageFormatInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | |
| VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | |
| VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; |
| |
| VkImageCompressionPropertiesEXT compressionProperties = {}; |
| compressionProperties.sType = VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT; |
| |
| VkImageFormatProperties2 imageFormatProperties2 = {}; |
| imageFormatProperties2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; |
| imageFormatProperties2.pNext = &compressionProperties; |
| |
| VkResult result = vkGetPhysicalDeviceImageFormatProperties2( |
| mRenderer->getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties2); |
| |
| if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) |
| { |
| *num_rates = 0; |
| return egl::NoError(); |
| } |
| else if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY) |
| { |
| return egl::Error(EGL_BAD_ALLOC); |
| } |
| else if (result != VK_SUCCESS) |
| { |
| return egl::Error(EGL_BAD_ACCESS); |
| } |
| |
| std::vector<EGLint> eglFixedRates = vk_gl::ConvertCompressionFlagsToEGLFixedRate( |
| compressionProperties.imageCompressionFixedRateFlags, static_cast<size_t>(rate_size)); |
| std::copy(eglFixedRates.begin(), eglFixedRates.end(), rates); |
| *num_rates = static_cast<EGLint>(eglFixedRates.size()); |
| |
| return egl::NoError(); |
| } |
| |
| } // namespace rx |