blob: 4271867007deed060f646ce66fbf03b251fad1b0 [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
28BackendBinding* CreateMetalBinding();
29
30namespace backend {
31 void RegisterSynchronousErrorCallback(nxtDevice device, void(*)(const char*, void*), void* userData);
32
33 namespace opengl {
34 void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
35 void HACKCLEAR();
36 }
37}
38
39class OpenGLBinding : public BackendBinding {
40 public:
41 void SetupGLFWWindowHints() override {
42 #ifdef __APPLE__
43 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
44 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
45 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
46 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
47 #else
48 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
49 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
50 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
51 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
52 #endif
53 }
54 void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
55 glfwMakeContextCurrent(window);
56 backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
57 }
58 void SwapBuffers() override {
59 glfwSwapBuffers(window);
60 backend::opengl::HACKCLEAR();
61 }
62};
63
64enum class BackendType {
65 OpenGL,
66 Metal,
67};
68
69enum class CmdBufType {
70 None,
71 Terrible,
Corentin Wallez682a8252017-05-09 15:34:13 +020072 //TODO(cwallez@chromium.org) double terrible cmdbuf
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040073};
74
75static BackendType backendType = BackendType::OpenGL;
76static CmdBufType cmdBufType = CmdBufType::Terrible;
77static BackendBinding* binding = nullptr;
78
79static GLFWwindow* window = nullptr;
80
81static nxt::wire::CommandHandler* wireServer = nullptr;
Corentin Wallez682a8252017-05-09 15:34:13 +020082static nxt::wire::CommandHandler* wireClient = nullptr;
83static nxt::wire::TerribleCommandBuffer* c2sBuf = nullptr;
84static nxt::wire::TerribleCommandBuffer* s2cBuf = nullptr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040085
86void HandleSynchronousError(const char* errorMessage, void* userData) {
87 std::cerr << errorMessage << std::endl;
88
89 if (userData != nullptr) {
90 auto wireServer = reinterpret_cast<nxt::wire::CommandHandler*>(userData);
91 wireServer->OnSynchronousError();
92 }
93}
94
95void GetProcTableAndDevice(nxtProcTable* procs, nxt::Device* device) {
96 switch (backendType) {
97 case BackendType::OpenGL:
98 binding = new OpenGLBinding;
99 break;
100 case BackendType::Metal:
101 #if defined(__APPLE__)
102 binding = CreateMetalBinding();
103 #else
104 fprintf(stderr, "Metal backend no present on this platform\n");
105 #endif
106 break;
107 }
108
109 if (!glfwInit()) {
110 return;
111 }
112
113 binding->SetupGLFWWindowHints();
114 window = glfwCreateWindow(640, 480, "NXT window", nullptr, nullptr);
115 if (!window) {
116 return;
117 }
118
119 binding->SetWindow(window);
120
121 nxtDevice backendDevice;
122 nxtProcTable backendProcs;
123 binding->GetProcAndDevice(&backendProcs, &backendDevice);
124
125 switch (cmdBufType) {
126 case CmdBufType::None:
127 *procs = backendProcs;
128 *device = nxt::Device::Acquire(backendDevice);
129 break;
130
131 case CmdBufType::Terrible:
132 {
Corentin Wallez682a8252017-05-09 15:34:13 +0200133 c2sBuf = new nxt::wire::TerribleCommandBuffer();
134 s2cBuf = new nxt::wire::TerribleCommandBuffer();
135
136 wireServer = nxt::wire::NewServerCommandHandler(backendDevice, backendProcs, s2cBuf);
137 c2sBuf->SetHandler(wireServer);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400138
139 nxtDevice clientDevice;
140 nxtProcTable clientProcs;
Corentin Wallez682a8252017-05-09 15:34:13 +0200141 wireClient = nxt::wire::NewClientDevice(&clientProcs, &clientDevice, c2sBuf);
142 s2cBuf->SetHandler(wireClient);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400143
144 *procs = clientProcs;
145 *device = nxt::Device::Acquire(clientDevice);
146 }
147 break;
148 }
149
Corentin Wallez682a8252017-05-09 15:34:13 +0200150 //TODO(cwallez@chromium.org) this will disappear
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400151 backend::RegisterSynchronousErrorCallback(backendDevice, HandleSynchronousError, wireServer);
152}
153
154nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source) {
155 shaderc::Compiler compiler;
156 shaderc::CompileOptions options;
157
158 shaderc_shader_kind kind;
159 switch (stage) {
160 case nxt::ShaderStage::Vertex:
161 kind = shaderc_glsl_vertex_shader;
162 break;
163 case nxt::ShaderStage::Fragment:
164 kind = shaderc_glsl_fragment_shader;
165 break;
166 case nxt::ShaderStage::Compute:
167 kind = shaderc_glsl_compute_shader;
168 break;
169 }
170
171 auto result = compiler.CompileGlslToSpv(source, strlen(source), kind, "myshader?", options);
172 if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
173 std::cerr << result.GetErrorMessage();
174 return {};
175 }
176
177 size_t size = (result.cend() - result.cbegin());
178
179#ifdef DUMP_SPIRV_ASSEMBLY
180 {
181 auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind, "myshader?", options);
182 size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
183
184 char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
185 memcpy(buffer, resultAsm.cbegin(), sizeAsm);
186 buffer[sizeAsm] = '\0';
187 printf("SPIRV ASSEMBLY DUMP START\n%s\nSPIRV ASSEMBLY DUMP END\n", buffer);
188 free(buffer);
189 }
190#endif
191
192#ifdef DUMP_SPIRV_JS_ARRAY
193 printf("SPIRV JS ARRAY DUMP START\n");
194 for (size_t i = 0; i < size; i++) {
195 printf("%#010x", result.cbegin()[i]);
196 if ((i + 1) % 4 == 0) {
197 printf(",\n");
198 } else {
199 printf(", ");
200 }
201 }
202 printf("\n");
203 printf("SPIRV JS ARRAY DUMP END\n");
204#endif
205
206 return device.CreateShaderModuleBuilder()
207 .SetSource(size, result.cbegin())
208 .GetResult();
209}
210
211extern "C" {
212 bool InitUtils(int argc, const char** argv) {
213 for (int i = 0; i < argc; i++) {
214 if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
215 i++;
216 if (i < argc && std::string("opengl") == argv[i]) {
217 backendType = BackendType::OpenGL;
218 continue;
219 }
220 if (i < argc && std::string("metal") == argv[i]) {
221 backendType = BackendType::Metal;
222 continue;
223 }
224 fprintf(stderr, "--backend expects a backend name (opengl, metal)\n");
225 return false;
226 }
227 if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
228 i++;
229 if (i < argc && std::string("none") == argv[i]) {
230 cmdBufType = CmdBufType::None;
231 continue;
232 }
233 if (i < argc && std::string("terrible") == argv[i]) {
234 cmdBufType = CmdBufType::Terrible;
235 continue;
236 }
237 fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
238 return false;
239 }
240 if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
241 printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
242 printf(" BACKEND is one of: opengl, metal\n");
243 printf(" COMMAND_BUFFER is one of: none, terrible\n");
244 return false;
245 }
246 }
247 return true;
248 }
249
250 void GetProcTableAndDevice(nxtProcTable* procs, nxtDevice* device) {
251 nxt::Device cppDevice;
252 GetProcTableAndDevice(procs, &cppDevice);
253 *device = cppDevice.Release();
254 }
255
256 nxtShaderModule CreateShaderModule(nxtDevice device, nxtShaderStage stage, const char* source) {
257 return CreateShaderModule(device, static_cast<nxt::ShaderStage>(stage), source).Release();
258 }
259
260 void SwapBuffers() {
Corentin Wallez682a8252017-05-09 15:34:13 +0200261 if (cmdBufType == CmdBufType::Terrible) {
262 c2sBuf->Flush();
263 s2cBuf->Flush();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400264 }
265 glfwPollEvents();
266 binding->SwapBuffers();
267 }
268
269 bool ShouldQuit() {
270 return glfwWindowShouldClose(window);
271 }
272
273 GLFWwindow* GetWindow() {
274 return window;
275 }
276}