1 // Copyright 2020 the Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/Surface.h" 16 17 #include "common/Platform.h" 18 #include "dawn_native/ChainUtils_autogen.h" 19 #include "dawn_native/Instance.h" 20 #include "dawn_native/SwapChain.h" 21 22 #if defined(DAWN_PLATFORM_WINDOWS) 23 # include <windows.ui.core.h> 24 # include <windows.ui.xaml.controls.h> 25 #endif // defined(DAWN_PLATFORM_WINDOWS) 26 27 #if defined(DAWN_USE_X11) 28 # include "common/xlib_with_undefs.h" 29 #endif // defined(DAWN_USE_X11) 30 31 namespace dawn_native { 32 AbslFormatConvert(Surface::Type value,const absl::FormatConversionSpec & spec,absl::FormatSink * s)33 absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert( 34 Surface::Type value, 35 const absl::FormatConversionSpec& spec, 36 absl::FormatSink* s) { 37 switch (value) { 38 case Surface::Type::MetalLayer: 39 s->Append("MetalLayer"); 40 break; 41 case Surface::Type::WindowsHWND: 42 s->Append("WindowsHWND"); 43 break; 44 case Surface::Type::WindowsCoreWindow: 45 s->Append("WindowsCoreWindow"); 46 break; 47 case Surface::Type::WindowsSwapChainPanel: 48 s->Append("WindowsSwapChainPanel"); 49 break; 50 case Surface::Type::Xlib: 51 s->Append("Xlib"); 52 break; 53 } 54 return {true}; 55 } 56 57 #if defined(DAWN_ENABLE_BACKEND_METAL) 58 bool InheritsFromCAMetalLayer(void* obj); 59 #endif // defined(DAWN_ENABLE_BACKEND_METAL) 60 ValidateSurfaceDescriptor(const InstanceBase * instance,const SurfaceDescriptor * descriptor)61 MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance, 62 const SurfaceDescriptor* descriptor) { 63 DAWN_INVALID_IF(descriptor->nextInChain == nullptr, 64 "Surface cannot be created with %s. nextInChain is not specified.", 65 descriptor); 66 67 DAWN_TRY(ValidateSingleSType(descriptor->nextInChain, 68 wgpu::SType::SurfaceDescriptorFromMetalLayer, 69 wgpu::SType::SurfaceDescriptorFromWindowsHWND, 70 wgpu::SType::SurfaceDescriptorFromWindowsCoreWindow, 71 wgpu::SType::SurfaceDescriptorFromWindowsSwapChainPanel, 72 wgpu::SType::SurfaceDescriptorFromXlib)); 73 74 #if defined(DAWN_ENABLE_BACKEND_METAL) 75 const SurfaceDescriptorFromMetalLayer* metalDesc = nullptr; 76 FindInChain(descriptor->nextInChain, &metalDesc); 77 if (metalDesc) { 78 // Check that the layer is a CAMetalLayer (or a derived class). 79 DAWN_INVALID_IF(!InheritsFromCAMetalLayer(metalDesc->layer), 80 "Layer must be a CAMetalLayer"); 81 return {}; 82 } 83 #endif // defined(DAWN_ENABLE_BACKEND_METAL) 84 85 #if defined(DAWN_PLATFORM_WINDOWS) 86 # if defined(DAWN_PLATFORM_WIN32) 87 const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr; 88 FindInChain(descriptor->nextInChain, &hwndDesc); 89 if (hwndDesc) { 90 DAWN_INVALID_IF(IsWindow(static_cast<HWND>(hwndDesc->hwnd)) == 0, "Invalid HWND"); 91 return {}; 92 } 93 # endif // defined(DAWN_PLATFORM_WIN32) 94 const SurfaceDescriptorFromWindowsCoreWindow* coreWindowDesc = nullptr; 95 FindInChain(descriptor->nextInChain, &coreWindowDesc); 96 if (coreWindowDesc) { 97 // Validate the coreWindow by query for ICoreWindow interface 98 ComPtr<ABI::Windows::UI::Core::ICoreWindow> coreWindow; 99 DAWN_INVALID_IF(coreWindowDesc->coreWindow == nullptr || 100 FAILED(static_cast<IUnknown*>(coreWindowDesc->coreWindow) 101 ->QueryInterface(IID_PPV_ARGS(&coreWindow))), 102 "Invalid CoreWindow"); 103 return {}; 104 } 105 const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr; 106 FindInChain(descriptor->nextInChain, &swapChainPanelDesc); 107 if (swapChainPanelDesc) { 108 // Validate the swapChainPanel by querying for ISwapChainPanel interface 109 ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> swapChainPanel; 110 DAWN_INVALID_IF(swapChainPanelDesc->swapChainPanel == nullptr || 111 FAILED(static_cast<IUnknown*>(swapChainPanelDesc->swapChainPanel) 112 ->QueryInterface(IID_PPV_ARGS(&swapChainPanel))), 113 "Invalid SwapChainPanel"); 114 return {}; 115 } 116 #endif // defined(DAWN_PLATFORM_WINDOWS) 117 118 #if defined(DAWN_USE_X11) 119 const SurfaceDescriptorFromXlib* xDesc = nullptr; 120 FindInChain(descriptor->nextInChain, &xDesc); 121 if (xDesc) { 122 // Check the validity of the window by calling a getter function on the window that 123 // returns a status code. If the window is bad the call return a status of zero. We 124 // need to set a temporary X11 error handler while doing this because the default 125 // X11 error handler exits the program on any error. 126 XErrorHandler oldErrorHandler = 127 XSetErrorHandler([](Display*, XErrorEvent*) { return 0; }); 128 XWindowAttributes attributes; 129 int status = XGetWindowAttributes(reinterpret_cast<Display*>(xDesc->display), 130 xDesc->window, &attributes); 131 XSetErrorHandler(oldErrorHandler); 132 133 DAWN_INVALID_IF(status == 0, "Invalid X Window"); 134 return {}; 135 } 136 #endif // defined(DAWN_USE_X11) 137 138 return DAWN_FORMAT_VALIDATION_ERROR("Unsupported sType (%s)", 139 descriptor->nextInChain->sType); 140 } 141 Surface(InstanceBase * instance,const SurfaceDescriptor * descriptor)142 Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor) 143 : mInstance(instance) { 144 ASSERT(descriptor->nextInChain != nullptr); 145 const SurfaceDescriptorFromMetalLayer* metalDesc = nullptr; 146 const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr; 147 const SurfaceDescriptorFromWindowsCoreWindow* coreWindowDesc = nullptr; 148 const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr; 149 const SurfaceDescriptorFromXlib* xDesc = nullptr; 150 FindInChain(descriptor->nextInChain, &metalDesc); 151 FindInChain(descriptor->nextInChain, &hwndDesc); 152 FindInChain(descriptor->nextInChain, &coreWindowDesc); 153 FindInChain(descriptor->nextInChain, &swapChainPanelDesc); 154 FindInChain(descriptor->nextInChain, &xDesc); 155 ASSERT(metalDesc || hwndDesc || xDesc); 156 if (metalDesc) { 157 mType = Type::MetalLayer; 158 mMetalLayer = metalDesc->layer; 159 } else if (hwndDesc) { 160 mType = Type::WindowsHWND; 161 mHInstance = hwndDesc->hinstance; 162 mHWND = hwndDesc->hwnd; 163 } else if (coreWindowDesc) { 164 #if defined(DAWN_PLATFORM_WINDOWS) 165 mType = Type::WindowsCoreWindow; 166 mCoreWindow = static_cast<IUnknown*>(coreWindowDesc->coreWindow); 167 #endif // defined(DAWN_PLATFORM_WINDOWS) 168 } else if (swapChainPanelDesc) { 169 #if defined(DAWN_PLATFORM_WINDOWS) 170 mType = Type::WindowsSwapChainPanel; 171 mSwapChainPanel = static_cast<IUnknown*>(swapChainPanelDesc->swapChainPanel); 172 #endif // defined(DAWN_PLATFORM_WINDOWS) 173 } else if (xDesc) { 174 mType = Type::Xlib; 175 mXDisplay = xDesc->display; 176 mXWindow = xDesc->window; 177 } else { 178 UNREACHABLE(); 179 } 180 } 181 ~Surface()182 Surface::~Surface() { 183 if (mSwapChain != nullptr) { 184 mSwapChain->DetachFromSurface(); 185 mSwapChain = nullptr; 186 } 187 } 188 GetAttachedSwapChain()189 NewSwapChainBase* Surface::GetAttachedSwapChain() { 190 return mSwapChain.Get(); 191 } 192 SetAttachedSwapChain(NewSwapChainBase * swapChain)193 void Surface::SetAttachedSwapChain(NewSwapChainBase* swapChain) { 194 mSwapChain = swapChain; 195 } 196 GetInstance()197 InstanceBase* Surface::GetInstance() { 198 return mInstance.Get(); 199 } 200 GetType() const201 Surface::Type Surface::GetType() const { 202 return mType; 203 } 204 GetMetalLayer() const205 void* Surface::GetMetalLayer() const { 206 ASSERT(mType == Type::MetalLayer); 207 return mMetalLayer; 208 } 209 GetHInstance() const210 void* Surface::GetHInstance() const { 211 ASSERT(mType == Type::WindowsHWND); 212 return mHInstance; 213 } GetHWND() const214 void* Surface::GetHWND() const { 215 ASSERT(mType == Type::WindowsHWND); 216 return mHWND; 217 } 218 GetCoreWindow() const219 IUnknown* Surface::GetCoreWindow() const { 220 ASSERT(mType == Type::WindowsCoreWindow); 221 #if defined(DAWN_PLATFORM_WINDOWS) 222 return mCoreWindow.Get(); 223 #else 224 return nullptr; 225 #endif 226 } 227 GetSwapChainPanel() const228 IUnknown* Surface::GetSwapChainPanel() const { 229 ASSERT(mType == Type::WindowsSwapChainPanel); 230 #if defined(DAWN_PLATFORM_WINDOWS) 231 return mSwapChainPanel.Get(); 232 #else 233 return nullptr; 234 #endif 235 } 236 GetXDisplay() const237 void* Surface::GetXDisplay() const { 238 ASSERT(mType == Type::Xlib); 239 return mXDisplay; 240 } GetXWindow() const241 uint32_t Surface::GetXWindow() const { 242 ASSERT(mType == Type::Xlib); 243 return mXWindow; 244 } 245 246 } // namespace dawn_native 247