• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 "SampleUtils.h"
16 
17 #include "common/Assert.h"
18 #include "common/Log.h"
19 #include "common/Platform.h"
20 #include "common/SystemUtils.h"
21 #include "utils/BackendBinding.h"
22 #include "utils/GLFWUtils.h"
23 #include "utils/TerribleCommandBuffer.h"
24 
25 #include <dawn/dawn_proc.h>
26 #include <dawn/dawn_wsi.h>
27 #include <dawn_native/DawnNative.h>
28 #include <dawn_wire/WireClient.h>
29 #include <dawn_wire/WireServer.h>
30 #include "GLFW/glfw3.h"
31 
32 #include <algorithm>
33 #include <cstring>
34 
PrintDeviceError(WGPUErrorType errorType,const char * message,void *)35 void PrintDeviceError(WGPUErrorType errorType, const char* message, void*) {
36     const char* errorTypeName = "";
37     switch (errorType) {
38         case WGPUErrorType_Validation:
39             errorTypeName = "Validation";
40             break;
41         case WGPUErrorType_OutOfMemory:
42             errorTypeName = "Out of memory";
43             break;
44         case WGPUErrorType_Unknown:
45             errorTypeName = "Unknown";
46             break;
47         case WGPUErrorType_DeviceLost:
48             errorTypeName = "Device lost";
49             break;
50         default:
51             UNREACHABLE();
52             return;
53     }
54     dawn::ErrorLog() << errorTypeName << " error: " << message;
55 }
56 
PrintGLFWError(int code,const char * message)57 void PrintGLFWError(int code, const char* message) {
58     dawn::ErrorLog() << "GLFW error: " << code << " - " << message;
59 }
60 
61 enum class CmdBufType {
62     None,
63     Terrible,
64     // TODO(cwallez@chromium.org): double terrible cmdbuf
65 };
66 
67 // Default to D3D12, Metal, Vulkan, OpenGL in that order as D3D12 and Metal are the preferred on
68 // their respective platforms, and Vulkan is preferred to OpenGL
69 #if defined(DAWN_ENABLE_BACKEND_D3D12)
70 static wgpu::BackendType backendType = wgpu::BackendType::D3D12;
71 #elif defined(DAWN_ENABLE_BACKEND_METAL)
72 static wgpu::BackendType backendType = wgpu::BackendType::Metal;
73 #elif defined(DAWN_ENABLE_BACKEND_VULKAN)
74 static wgpu::BackendType backendType = wgpu::BackendType::Vulkan;
75 #elif defined(DAWN_ENABLE_BACKEND_OPENGLES)
76 static wgpu::BackendType backendType = wgpu::BackendType::OpenGLES;
77 #elif defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
78 static wgpu::BackendType backendType = wgpu::BackendType::OpenGL;
79 #else
80 #    error
81 #endif
82 
83 static CmdBufType cmdBufType = CmdBufType::Terrible;
84 static std::unique_ptr<dawn_native::Instance> instance;
85 static utils::BackendBinding* binding = nullptr;
86 
87 static GLFWwindow* window = nullptr;
88 
89 static dawn_wire::WireServer* wireServer = nullptr;
90 static dawn_wire::WireClient* wireClient = nullptr;
91 static utils::TerribleCommandBuffer* c2sBuf = nullptr;
92 static utils::TerribleCommandBuffer* s2cBuf = nullptr;
93 
CreateCppDawnDevice()94 wgpu::Device CreateCppDawnDevice() {
95     ScopedEnvironmentVar angleDefaultPlatform;
96     if (GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM").first.empty()) {
97         angleDefaultPlatform.Set("ANGLE_DEFAULT_PLATFORM", "swiftshader");
98     }
99 
100     glfwSetErrorCallback(PrintGLFWError);
101     if (!glfwInit()) {
102         return wgpu::Device();
103     }
104 
105     // Create the test window and discover adapters using it (esp. for OpenGL)
106     utils::SetupGLFWWindowHintsForBackend(backendType);
107     glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
108     window = glfwCreateWindow(640, 480, "Dawn window", nullptr, nullptr);
109     if (!window) {
110         return wgpu::Device();
111     }
112 
113     instance = std::make_unique<dawn_native::Instance>();
114     utils::DiscoverAdapter(instance.get(), window, backendType);
115 
116     // Get an adapter for the backend to use, and create the device.
117     dawn_native::Adapter backendAdapter;
118     {
119         std::vector<dawn_native::Adapter> adapters = instance->GetAdapters();
120         auto adapterIt = std::find_if(adapters.begin(), adapters.end(),
121                                       [](const dawn_native::Adapter adapter) -> bool {
122                                           wgpu::AdapterProperties properties;
123                                           adapter.GetProperties(&properties);
124                                           return properties.backendType == backendType;
125                                       });
126         ASSERT(adapterIt != adapters.end());
127         backendAdapter = *adapterIt;
128     }
129 
130     WGPUDevice backendDevice = backendAdapter.CreateDevice();
131     DawnProcTable backendProcs = dawn_native::GetProcs();
132 
133     binding = utils::CreateBinding(backendType, window, backendDevice);
134     if (binding == nullptr) {
135         return wgpu::Device();
136     }
137 
138     // Choose whether to use the backend procs and devices directly, or set up the wire.
139     WGPUDevice cDevice = nullptr;
140     DawnProcTable procs;
141 
142     switch (cmdBufType) {
143         case CmdBufType::None:
144             procs = backendProcs;
145             cDevice = backendDevice;
146             break;
147 
148         case CmdBufType::Terrible: {
149             c2sBuf = new utils::TerribleCommandBuffer();
150             s2cBuf = new utils::TerribleCommandBuffer();
151 
152             dawn_wire::WireServerDescriptor serverDesc = {};
153             serverDesc.procs = &backendProcs;
154             serverDesc.serializer = s2cBuf;
155 
156             wireServer = new dawn_wire::WireServer(serverDesc);
157             c2sBuf->SetHandler(wireServer);
158 
159             dawn_wire::WireClientDescriptor clientDesc = {};
160             clientDesc.serializer = c2sBuf;
161 
162             wireClient = new dawn_wire::WireClient(clientDesc);
163             procs = dawn_wire::client::GetProcs();
164             s2cBuf->SetHandler(wireClient);
165 
166             auto deviceReservation = wireClient->ReserveDevice();
167             wireServer->InjectDevice(backendDevice, deviceReservation.id,
168                                      deviceReservation.generation);
169 
170             cDevice = deviceReservation.device;
171         } break;
172     }
173 
174     dawnProcSetProcs(&procs);
175     procs.deviceSetUncapturedErrorCallback(cDevice, PrintDeviceError, nullptr);
176     return wgpu::Device::Acquire(cDevice);
177 }
178 
GetSwapChainImplementation()179 uint64_t GetSwapChainImplementation() {
180     return binding->GetSwapChainImplementation();
181 }
182 
GetPreferredSwapChainTextureFormat()183 wgpu::TextureFormat GetPreferredSwapChainTextureFormat() {
184     DoFlush();
185     return static_cast<wgpu::TextureFormat>(binding->GetPreferredSwapChainTextureFormat());
186 }
187 
GetSwapChain(const wgpu::Device & device)188 wgpu::SwapChain GetSwapChain(const wgpu::Device& device) {
189     wgpu::SwapChainDescriptor swapChainDesc;
190     swapChainDesc.implementation = GetSwapChainImplementation();
191     return device.CreateSwapChain(nullptr, &swapChainDesc);
192 }
193 
CreateDefaultDepthStencilView(const wgpu::Device & device)194 wgpu::TextureView CreateDefaultDepthStencilView(const wgpu::Device& device) {
195     wgpu::TextureDescriptor descriptor;
196     descriptor.dimension = wgpu::TextureDimension::e2D;
197     descriptor.size.width = 640;
198     descriptor.size.height = 480;
199     descriptor.size.depthOrArrayLayers = 1;
200     descriptor.sampleCount = 1;
201     descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
202     descriptor.mipLevelCount = 1;
203     descriptor.usage = wgpu::TextureUsage::RenderAttachment;
204     auto depthStencilTexture = device.CreateTexture(&descriptor);
205     return depthStencilTexture.CreateView();
206 }
207 
InitSample(int argc,const char ** argv)208 bool InitSample(int argc, const char** argv) {
209     for (int i = 1; i < argc; i++) {
210         if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
211             i++;
212             if (i < argc && std::string("d3d12") == argv[i]) {
213                 backendType = wgpu::BackendType::D3D12;
214                 continue;
215             }
216             if (i < argc && std::string("metal") == argv[i]) {
217                 backendType = wgpu::BackendType::Metal;
218                 continue;
219             }
220             if (i < argc && std::string("null") == argv[i]) {
221                 backendType = wgpu::BackendType::Null;
222                 continue;
223             }
224             if (i < argc && std::string("opengl") == argv[i]) {
225                 backendType = wgpu::BackendType::OpenGL;
226                 continue;
227             }
228             if (i < argc && std::string("opengles") == argv[i]) {
229                 backendType = wgpu::BackendType::OpenGLES;
230                 continue;
231             }
232             if (i < argc && std::string("vulkan") == argv[i]) {
233                 backendType = wgpu::BackendType::Vulkan;
234                 continue;
235             }
236             fprintf(stderr,
237                     "--backend expects a backend name (opengl, opengles, metal, d3d12, null, "
238                     "vulkan)\n");
239             return false;
240         }
241         if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) {
242             i++;
243             if (i < argc && std::string("none") == argv[i]) {
244                 cmdBufType = CmdBufType::None;
245                 continue;
246             }
247             if (i < argc && std::string("terrible") == argv[i]) {
248                 cmdBufType = CmdBufType::Terrible;
249                 continue;
250             }
251             fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
252             return false;
253         }
254         if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
255             printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
256             printf("  BACKEND is one of: d3d12, metal, null, opengl, opengles, vulkan\n");
257             printf("  COMMAND_BUFFER is one of: none, terrible\n");
258             return false;
259         }
260     }
261     return true;
262 }
263 
DoFlush()264 void DoFlush() {
265     if (cmdBufType == CmdBufType::Terrible) {
266         bool c2sSuccess = c2sBuf->Flush();
267         bool s2cSuccess = s2cBuf->Flush();
268 
269         ASSERT(c2sSuccess && s2cSuccess);
270     }
271     glfwPollEvents();
272 }
273 
ShouldQuit()274 bool ShouldQuit() {
275     return glfwWindowShouldClose(window);
276 }
277 
GetGLFWWindow()278 GLFWwindow* GetGLFWWindow() {
279     return window;
280 }
281