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