// Copyright 2020 the Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "dawn_native/Surface.h" #include "common/Platform.h" #include "dawn_native/ChainUtils_autogen.h" #include "dawn_native/Instance.h" #include "dawn_native/SwapChain.h" #if defined(DAWN_PLATFORM_WINDOWS) # include # include #endif // defined(DAWN_PLATFORM_WINDOWS) #if defined(DAWN_USE_X11) # include "common/xlib_with_undefs.h" #endif // defined(DAWN_USE_X11) namespace dawn_native { #if defined(DAWN_ENABLE_BACKEND_METAL) bool InheritsFromCAMetalLayer(void* obj); #endif // defined(DAWN_ENABLE_BACKEND_METAL) MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance, const SurfaceDescriptor* descriptor) { if (descriptor->nextInChain == nullptr) { return DAWN_VALIDATION_ERROR("Surface cannot be created with just the base descriptor"); } DAWN_TRY(ValidateSingleSType(descriptor->nextInChain, wgpu::SType::SurfaceDescriptorFromMetalLayer, wgpu::SType::SurfaceDescriptorFromWindowsHWND, wgpu::SType::SurfaceDescriptorFromWindowsCoreWindow, wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel, wgpu::SType::SurfaceDescriptorFromXlib)); #if defined(DAWN_ENABLE_BACKEND_METAL) const SurfaceDescriptorFromMetalLayer* metalDesc = nullptr; FindInChain(descriptor->nextInChain, &metalDesc); if (!metalDesc) { return DAWN_VALIDATION_ERROR("Unsupported sType"); } // Check that the layer is a CAMetalLayer (or a derived class). if (!InheritsFromCAMetalLayer(metalDesc->layer)) { return DAWN_VALIDATION_ERROR("layer must be a CAMetalLayer"); } #endif // defined(DAWN_ENABLE_BACKEND_METAL) #if defined(DAWN_PLATFORM_WINDOWS) # if defined(DAWN_PLATFORM_WIN32) const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr; FindInChain(descriptor->nextInChain, &hwndDesc); if (hwndDesc) { if (IsWindow(static_cast(hwndDesc->hwnd)) == 0) { return DAWN_VALIDATION_ERROR("Invalid HWND"); } return {}; } # endif // defined(DAWN_PLATFORM_WIN32) const SurfaceDescriptorFromWindowsCoreWindow* coreWindowDesc = nullptr; FindInChain(descriptor->nextInChain, &coreWindowDesc); if (coreWindowDesc) { // Validate the coreWindow by query for ICoreWindow interface ComPtr coreWindow; if (coreWindowDesc->coreWindow == nullptr || FAILED(static_cast(coreWindowDesc->coreWindow) ->QueryInterface(IID_PPV_ARGS(&coreWindow)))) { return DAWN_VALIDATION_ERROR("Invalid CoreWindow"); } return {}; } const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr; FindInChain(descriptor->nextInChain, &swapChainPanelDesc); if (swapChainPanelDesc) { // Validate the swapChainPanel by querying for ISwapChainPanel interface ComPtr swapChainPanel; if (swapChainPanelDesc->swapChainPanel == nullptr || FAILED(static_cast(swapChainPanelDesc->swapChainPanel) ->QueryInterface(IID_PPV_ARGS(&swapChainPanel)))) { return DAWN_VALIDATION_ERROR("Invalid SwapChainPanel"); } return {}; } return DAWN_VALIDATION_ERROR("Unsupported sType"); #endif // defined(DAWN_PLATFORM_WINDOWS) #if defined(DAWN_USE_X11) const SurfaceDescriptorFromXlib* xDesc = nullptr; FindInChain(descriptor->nextInChain, &xDesc); if (!xDesc) { return DAWN_VALIDATION_ERROR("Unsupported sType"); } // Check the validity of the window by calling a getter function on the window that // returns a status code. If the window is bad the call return a status of zero. We // need to set a temporary X11 error handler while doing this because the default // X11 error handler exits the program on any error. XErrorHandler oldErrorHandler = XSetErrorHandler([](Display*, XErrorEvent*) { return 0; }); XWindowAttributes attributes; int status = XGetWindowAttributes(reinterpret_cast(xDesc->display), xDesc->window, &attributes); XSetErrorHandler(oldErrorHandler); if (status == 0) { return DAWN_VALIDATION_ERROR("Invalid X Window"); } #endif // defined(DAWN_USE_X11) return {}; } Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor) : mInstance(instance) { ASSERT(descriptor->nextInChain != nullptr); const SurfaceDescriptorFromMetalLayer* metalDesc = nullptr; const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr; const SurfaceDescriptorFromWindowsCoreWindow* coreWindowDesc = nullptr; const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr; const SurfaceDescriptorFromXlib* xDesc = nullptr; FindInChain(descriptor->nextInChain, &metalDesc); FindInChain(descriptor->nextInChain, &hwndDesc); FindInChain(descriptor->nextInChain, &coreWindowDesc); FindInChain(descriptor->nextInChain, &swapChainPanelDesc); FindInChain(descriptor->nextInChain, &xDesc); ASSERT(metalDesc || hwndDesc || xDesc); if (metalDesc) { mType = Type::MetalLayer; mMetalLayer = metalDesc->layer; } else if (hwndDesc) { mType = Type::WindowsHWND; mHInstance = hwndDesc->hinstance; mHWND = hwndDesc->hwnd; } else if (coreWindowDesc) { #if defined(DAWN_PLATFORM_WINDOWS) mType = Type::WindowsCoreWindow; mCoreWindow = static_cast(coreWindowDesc->coreWindow); #endif // defined(DAWN_PLATFORM_WINDOWS) } else if (swapChainPanelDesc) { #if defined(DAWN_PLATFORM_WINDOWS) mType = Type::WindowsSwapChainPanel; mSwapChainPanel = static_cast(swapChainPanelDesc->swapChainPanel); #endif // defined(DAWN_PLATFORM_WINDOWS) } else if (xDesc) { mType = Type::Xlib; mXDisplay = xDesc->display; mXWindow = xDesc->window; } else { UNREACHABLE(); } } Surface::~Surface() { if (mSwapChain != nullptr) { mSwapChain->DetachFromSurface(); mSwapChain = nullptr; } } NewSwapChainBase* Surface::GetAttachedSwapChain() { return mSwapChain.Get(); } void Surface::SetAttachedSwapChain(NewSwapChainBase* swapChain) { mSwapChain = swapChain; } InstanceBase* Surface::GetInstance() { return mInstance.Get(); } Surface::Type Surface::GetType() const { return mType; } void* Surface::GetMetalLayer() const { ASSERT(mType == Type::MetalLayer); return mMetalLayer; } void* Surface::GetHInstance() const { ASSERT(mType == Type::WindowsHWND); return mHInstance; } void* Surface::GetHWND() const { ASSERT(mType == Type::WindowsHWND); return mHWND; } IUnknown* Surface::GetCoreWindow() const { ASSERT(mType == Type::WindowsCoreWindow); #if defined(DAWN_PLATFORM_WINDOWS) return mCoreWindow.Get(); #else return nullptr; #endif } IUnknown* Surface::GetSwapChainPanel() const { ASSERT(mType == Type::WindowsSwapChainPanel); #if defined(DAWN_PLATFORM_WINDOWS) return mSwapChainPanel.Get(); #else return nullptr; #endif } void* Surface::GetXDisplay() const { ASSERT(mType == Type::Xlib); return mXDisplay; } uint32_t Surface::GetXWindow() const { ASSERT(mType == Type::Xlib); return mXWindow; } } // namespace dawn_native