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