blob: 9d344a117f3fb43acbde830ae91107c27a4bc318 [file] [log] [blame]
Corentin Wallezf07e3bd2017-04-20 14:38:20 -04001// Copyright 2017 The NXT 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 <nxt/nxt.h>
16#include <nxt/nxtcpp.h>
17#include <shaderc/shaderc.hpp>
18#include "GLFW/glfw3.h"
19
20#include "BackendBinding.h"
21#include "../src/wire/TerribleCommandBuffer.h"
22
23#include <cstring>
24#include <iostream>
25#include <sstream>
26#include <iomanip>
27
Corentin Wallez583e9a82017-05-29 11:30:29 -070028#ifdef _WIN32
29 #include <Windows.h>
30#else
31 #include <unistd.h>
32#endif
33
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040034BackendBinding* CreateMetalBinding();
35
36namespace backend {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040037 namespace opengl {
38 void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
39 void HACKCLEAR();
40 }
41}
42
43class OpenGLBinding : public BackendBinding {
44 public:
45 void SetupGLFWWindowHints() override {
46 #ifdef __APPLE__
47 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
48 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
49 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
50 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
51 #else
52 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
53 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
54 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
55 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
56 #endif
57 }
58 void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
59 glfwMakeContextCurrent(window);
60 backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
61 }
62 void SwapBuffers() override {
63 glfwSwapBuffers(window);
64 backend::opengl::HACKCLEAR();
65 }
66};
67
Corentin Wallez79a62bf2017-05-24 16:04:55 +020068namespace backend {
69 namespace null {
70 void Init(nxtProcTable* procs, nxtDevice* device);
71 }
72}
73
74class NullBinding : public BackendBinding {
75 public:
76 void SetupGLFWWindowHints() override {
77 }
78 void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
79 backend::null::Init(procs, device);
80 }
81 void SwapBuffers() override {
82 }
83};
84
85
Corentin Wallez4b410a32017-04-20 14:42:36 -040086void PrintDeviceError(const char* message, nxt::CallbackUserdata) {
87 std::cout << "Device error: " << message << std::endl;
88}
89
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040090enum class BackendType {
91 OpenGL,
92 Metal,
Corentin Wallez79a62bf2017-05-24 16:04:55 +020093 Null,
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040094};
95
96enum class CmdBufType {
97 None,
98 Terrible,
Corentin Wallez682a8252017-05-09 15:34:13 +020099 //TODO(cwallez@chromium.org) double terrible cmdbuf
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400100};
101
102static BackendType backendType = BackendType::OpenGL;
103static CmdBufType cmdBufType = CmdBufType::Terrible;
104static BackendBinding* binding = nullptr;
105
106static GLFWwindow* window = nullptr;
107
108static nxt::wire::CommandHandler* wireServer = nullptr;
Corentin Wallez682a8252017-05-09 15:34:13 +0200109static nxt::wire::CommandHandler* wireClient = nullptr;
110static nxt::wire::TerribleCommandBuffer* c2sBuf = nullptr;
111static nxt::wire::TerribleCommandBuffer* s2cBuf = nullptr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400112
Corentin Wallez583e9a82017-05-29 11:30:29 -0700113nxt::Device CreateCppNXTDevice() {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400114 switch (backendType) {
115 case BackendType::OpenGL:
116 binding = new OpenGLBinding;
117 break;
118 case BackendType::Metal:
119 #if defined(__APPLE__)
120 binding = CreateMetalBinding();
121 #else
122 fprintf(stderr, "Metal backend no present on this platform\n");
123 #endif
124 break;
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200125 case BackendType::Null:
126 binding = new NullBinding;
127 break;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400128 }
129
130 if (!glfwInit()) {
Corentin Wallez583e9a82017-05-29 11:30:29 -0700131 return nxt::Device();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400132 }
133
134 binding->SetupGLFWWindowHints();
135 window = glfwCreateWindow(640, 480, "NXT window", nullptr, nullptr);
136 if (!window) {
Corentin Wallez583e9a82017-05-29 11:30:29 -0700137 return nxt::Device();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400138 }
139
140 binding->SetWindow(window);
141
142 nxtDevice backendDevice;
143 nxtProcTable backendProcs;
144 binding->GetProcAndDevice(&backendProcs, &backendDevice);
145
Corentin Wallez583e9a82017-05-29 11:30:29 -0700146 nxtDevice cDevice = nullptr;
147 nxtProcTable procs;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400148 switch (cmdBufType) {
149 case CmdBufType::None:
Corentin Wallez583e9a82017-05-29 11:30:29 -0700150 procs = backendProcs;
151 cDevice = backendDevice;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400152 break;
153
154 case CmdBufType::Terrible:
155 {
Corentin Wallez682a8252017-05-09 15:34:13 +0200156 c2sBuf = new nxt::wire::TerribleCommandBuffer();
157 s2cBuf = new nxt::wire::TerribleCommandBuffer();
158
159 wireServer = nxt::wire::NewServerCommandHandler(backendDevice, backendProcs, s2cBuf);
160 c2sBuf->SetHandler(wireServer);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400161
162 nxtDevice clientDevice;
163 nxtProcTable clientProcs;
Corentin Wallez682a8252017-05-09 15:34:13 +0200164 wireClient = nxt::wire::NewClientDevice(&clientProcs, &clientDevice, c2sBuf);
165 s2cBuf->SetHandler(wireClient);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400166
Corentin Wallez583e9a82017-05-29 11:30:29 -0700167 procs = clientProcs;
168 cDevice = clientDevice;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400169 }
170 break;
171 }
172
Corentin Wallez583e9a82017-05-29 11:30:29 -0700173 nxtSetProcs(&procs);
174 procs.deviceSetErrorCallback(cDevice, PrintDeviceError, 0);
175 return nxt::Device::Acquire(cDevice);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400176}
177
178nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source) {
179 shaderc::Compiler compiler;
180 shaderc::CompileOptions options;
181
182 shaderc_shader_kind kind;
183 switch (stage) {
184 case nxt::ShaderStage::Vertex:
185 kind = shaderc_glsl_vertex_shader;
186 break;
187 case nxt::ShaderStage::Fragment:
188 kind = shaderc_glsl_fragment_shader;
189 break;
190 case nxt::ShaderStage::Compute:
191 kind = shaderc_glsl_compute_shader;
192 break;
193 }
194
195 auto result = compiler.CompileGlslToSpv(source, strlen(source), kind, "myshader?", options);
196 if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
197 std::cerr << result.GetErrorMessage();
198 return {};
199 }
200
201 size_t size = (result.cend() - result.cbegin());
202
203#ifdef DUMP_SPIRV_ASSEMBLY
204 {
205 auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind, "myshader?", options);
206 size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
207
208 char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
209 memcpy(buffer, resultAsm.cbegin(), sizeAsm);
210 buffer[sizeAsm] = '\0';
211 printf("SPIRV ASSEMBLY DUMP START\n%s\nSPIRV ASSEMBLY DUMP END\n", buffer);
212 free(buffer);
213 }
214#endif
215
216#ifdef DUMP_SPIRV_JS_ARRAY
217 printf("SPIRV JS ARRAY DUMP START\n");
218 for (size_t i = 0; i < size; i++) {
219 printf("%#010x", result.cbegin()[i]);
220 if ((i + 1) % 4 == 0) {
221 printf(",\n");
222 } else {
223 printf(", ");
224 }
225 }
226 printf("\n");
227 printf("SPIRV JS ARRAY DUMP END\n");
228#endif
229
230 return device.CreateShaderModuleBuilder()
231 .SetSource(size, result.cbegin())
232 .GetResult();
233}
234
Kai Ninomiya68df8b02017-05-16 14:04:22 -0700235void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
236 *renderPass = device.CreateRenderPassBuilder()
237 .SetAttachmentCount(1)
238 .AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
239 .SetSubpassCount(1)
240 .SubpassSetColorAttachment(0, 0, 0)
241 .GetResult();
242 *framebuffer = device.CreateFramebufferBuilder()
243 .SetRenderPass(*renderPass)
244 .SetDimensions(640, 480)
245 .GetResult();
246}
247
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400248extern "C" {
249 bool InitUtils(int argc, const char** argv) {
250 for (int i = 0; i < argc; i++) {
251 if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
252 i++;
253 if (i < argc && std::string("opengl") == argv[i]) {
254 backendType = BackendType::OpenGL;
255 continue;
256 }
257 if (i < argc && std::string("metal") == argv[i]) {
258 backendType = BackendType::Metal;
259 continue;
260 }
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200261 if (i < argc && std::string("null") == argv[i]) {
262 backendType = BackendType::Null;
263 continue;
264 }
265 fprintf(stderr, "--backend expects a backend name (opengl, metal, null)\n");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400266 return false;
267 }
268 if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
269 i++;
270 if (i < argc && std::string("none") == argv[i]) {
271 cmdBufType = CmdBufType::None;
272 continue;
273 }
274 if (i < argc && std::string("terrible") == argv[i]) {
275 cmdBufType = CmdBufType::Terrible;
276 continue;
277 }
278 fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
279 return false;
280 }
281 if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
282 printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200283 printf(" BACKEND is one of: opengl, metal, null\n");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400284 printf(" COMMAND_BUFFER is one of: none, terrible\n");
285 return false;
286 }
287 }
288 return true;
289 }
290
Corentin Wallez583e9a82017-05-29 11:30:29 -0700291 nxtDevice CreateNXTDevice() {
292 return CreateCppNXTDevice().Release();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400293 }
294
295 nxtShaderModule CreateShaderModule(nxtDevice device, nxtShaderStage stage, const char* source) {
296 return CreateShaderModule(device, static_cast<nxt::ShaderStage>(stage), source).Release();
297 }
298
Corentin Wallez583e9a82017-05-29 11:30:29 -0700299 void DoSwapBuffers() {
Corentin Wallez682a8252017-05-09 15:34:13 +0200300 if (cmdBufType == CmdBufType::Terrible) {
301 c2sBuf->Flush();
302 s2cBuf->Flush();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400303 }
304 glfwPollEvents();
305 binding->SwapBuffers();
306 }
307
Corentin Wallez583e9a82017-05-29 11:30:29 -0700308#ifdef _WIN32
309 void USleep(uint64_t usecs) {
310 Sleep(usecs / 1000);
311 }
312#else
313 void USleep(uint64_t usecs) {
314 usleep(usecs);
315 }
316#endif
317
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400318 bool ShouldQuit() {
319 return glfwWindowShouldClose(window);
320 }
321
Corentin Wallez583e9a82017-05-29 11:30:29 -0700322 GLFWwindow* GetGLFWWindow() {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400323 return window;
324 }
325}