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/Instance.h" 19 #include "dawn_native/SwapChain.h" 20 21 #if defined(DAWN_PLATFORM_WINDOWS) 22 # include "common/windows_with_undefs.h" 23 #endif // DAWN_PLATFORM_WINDOWS 24 25 #if defined(DAWN_USE_X11) 26 # include "common/xlib_with_undefs.h" 27 #endif // defined(DAWN_USE_X11) 28 29 namespace dawn_native { 30 31 #if defined(DAWN_ENABLE_BACKEND_METAL) 32 bool InheritsFromCAMetalLayer(void* obj); 33 #endif // defined(DAWN_ENABLE_BACKEND_METAL) 34 ValidateSurfaceDescriptor(const InstanceBase * instance,const SurfaceDescriptor * descriptor)35 MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance, 36 const SurfaceDescriptor* descriptor) { 37 // TODO(cwallez@chromium.org): Have some type of helper to iterate over all the chained 38 // structures. 39 if (descriptor->nextInChain == nullptr) { 40 return DAWN_VALIDATION_ERROR("Surface cannot be created with just the base descriptor"); 41 } 42 43 const ChainedStruct* chainedDescriptor = descriptor->nextInChain; 44 if (chainedDescriptor->nextInChain != nullptr) { 45 return DAWN_VALIDATION_ERROR("Cannot specify two windows for a single surface"); 46 } 47 48 switch (chainedDescriptor->sType) { 49 #if defined(DAWN_ENABLE_BACKEND_METAL) 50 case wgpu::SType::SurfaceDescriptorFromMetalLayer: { 51 const SurfaceDescriptorFromMetalLayer* metalDesc = 52 static_cast<const SurfaceDescriptorFromMetalLayer*>(chainedDescriptor); 53 54 // Check that the layer is a CAMetalLayer (or a derived class). 55 if (!InheritsFromCAMetalLayer(metalDesc->layer)) { 56 return DAWN_VALIDATION_ERROR("layer must be a CAMetalLayer"); 57 } 58 break; 59 } 60 #endif // defined(DAWN_ENABLE_BACKEND_METAL) 61 62 #if defined(DAWN_PLATFORM_WINDOWS) 63 case wgpu::SType::SurfaceDescriptorFromWindowsHWND: { 64 const SurfaceDescriptorFromWindowsHWND* hwndDesc = 65 static_cast<const SurfaceDescriptorFromWindowsHWND*>(chainedDescriptor); 66 67 // It is not possible to validate an HINSTANCE. 68 69 // Validate the hwnd using the windows.h IsWindow function. 70 if (IsWindow(static_cast<HWND>(hwndDesc->hwnd)) == 0) { 71 return DAWN_VALIDATION_ERROR("Invalid HWND"); 72 } 73 break; 74 } 75 #endif // defined(DAWN_PLATFORM_WINDOWS) 76 77 #if defined(DAWN_USE_X11) 78 case wgpu::SType::SurfaceDescriptorFromXlib: { 79 const SurfaceDescriptorFromXlib* xDesc = 80 static_cast<const SurfaceDescriptorFromXlib*>(chainedDescriptor); 81 82 // It is not possible to validate an X Display. 83 84 // Check the validity of the window by calling a getter function on the window that 85 // returns a status code. If the window is bad the call return a status of zero. We 86 // need to set a temporary X11 error handler while doing this because the default 87 // X11 error handler exits the program on any error. 88 XErrorHandler oldErrorHandler = 89 XSetErrorHandler([](Display*, XErrorEvent*) { return 0; }); 90 XWindowAttributes attributes; 91 int status = XGetWindowAttributes(reinterpret_cast<Display*>(xDesc->display), 92 xDesc->window, &attributes); 93 XSetErrorHandler(oldErrorHandler); 94 95 if (status == 0) { 96 return DAWN_VALIDATION_ERROR("Invalid X Window"); 97 } 98 break; 99 } 100 #endif // defined(DAWN_USE_X11) 101 102 case wgpu::SType::SurfaceDescriptorFromHTMLCanvasId: 103 default: 104 return DAWN_VALIDATION_ERROR("Unsupported sType"); 105 } 106 107 return {}; 108 } 109 Surface(InstanceBase * instance,const SurfaceDescriptor * descriptor)110 Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor) 111 : mInstance(instance) { 112 ASSERT(descriptor->nextInChain != nullptr); 113 const ChainedStruct* chainedDescriptor = descriptor->nextInChain; 114 115 switch (chainedDescriptor->sType) { 116 case wgpu::SType::SurfaceDescriptorFromMetalLayer: { 117 const SurfaceDescriptorFromMetalLayer* metalDesc = 118 static_cast<const SurfaceDescriptorFromMetalLayer*>(chainedDescriptor); 119 mType = Type::MetalLayer; 120 mMetalLayer = metalDesc->layer; 121 break; 122 } 123 124 case wgpu::SType::SurfaceDescriptorFromWindowsHWND: { 125 const SurfaceDescriptorFromWindowsHWND* hwndDesc = 126 static_cast<const SurfaceDescriptorFromWindowsHWND*>(chainedDescriptor); 127 mType = Type::WindowsHWND; 128 mHInstance = hwndDesc->hinstance; 129 mHWND = hwndDesc->hwnd; 130 break; 131 } 132 133 case wgpu::SType::SurfaceDescriptorFromXlib: { 134 const SurfaceDescriptorFromXlib* xDesc = 135 static_cast<const SurfaceDescriptorFromXlib*>(chainedDescriptor); 136 mType = Type::Xlib; 137 mXDisplay = xDesc->display; 138 mXWindow = xDesc->window; 139 break; 140 } 141 142 default: 143 UNREACHABLE(); 144 } 145 } 146 ~Surface()147 Surface::~Surface() { 148 if (mSwapChain != nullptr) { 149 mSwapChain->DetachFromSurface(); 150 mSwapChain = nullptr; 151 } 152 } 153 GetAttachedSwapChain() const154 NewSwapChainBase* Surface::GetAttachedSwapChain() const { 155 return mSwapChain; 156 } 157 SetAttachedSwapChain(NewSwapChainBase * swapChain)158 void Surface::SetAttachedSwapChain(NewSwapChainBase* swapChain) { 159 mSwapChain = swapChain; 160 } 161 GetInstance()162 InstanceBase* Surface::GetInstance() { 163 return mInstance.Get(); 164 } 165 GetType() const166 Surface::Type Surface::GetType() const { 167 return mType; 168 } 169 GetMetalLayer() const170 void* Surface::GetMetalLayer() const { 171 ASSERT(mType == Type::MetalLayer); 172 return mMetalLayer; 173 } 174 GetHInstance() const175 void* Surface::GetHInstance() const { 176 ASSERT(mType == Type::WindowsHWND); 177 return mHInstance; 178 } GetHWND() const179 void* Surface::GetHWND() const { 180 ASSERT(mType == Type::WindowsHWND); 181 return mHWND; 182 } 183 GetXDisplay() const184 void* Surface::GetXDisplay() const { 185 ASSERT(mType == Type::Xlib); 186 return mXDisplay; 187 } GetXWindow() const188 uint32_t Surface::GetXWindow() const { 189 ASSERT(mType == Type::Xlib); 190 return mXWindow; 191 } 192 193 } // namespace dawn_native 194