blob: 4ab6f8b39b7d0c0e6f42ea94c3d3c52ec882bd92 [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 {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040031 namespace opengl {
32 void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
33 void HACKCLEAR();
34 }
35}
36
37class OpenGLBinding : public BackendBinding {
38 public:
39 void SetupGLFWWindowHints() override {
40 #ifdef __APPLE__
41 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
42 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
43 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
44 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
45 #else
46 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
47 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
48 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
49 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
50 #endif
51 }
52 void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
53 glfwMakeContextCurrent(window);
54 backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
55 }
56 void SwapBuffers() override {
57 glfwSwapBuffers(window);
58 backend::opengl::HACKCLEAR();
59 }
60};
61
Corentin Wallez79a62bf2017-05-24 16:04:55 +020062namespace backend {
63 namespace null {
64 void Init(nxtProcTable* procs, nxtDevice* device);
65 }
66}
67
68class NullBinding : public BackendBinding {
69 public:
70 void SetupGLFWWindowHints() override {
71 }
72 void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
73 backend::null::Init(procs, device);
74 }
75 void SwapBuffers() override {
76 }
77};
78
79
Corentin Wallez4b410a32017-04-20 14:42:36 -040080void PrintDeviceError(const char* message, nxt::CallbackUserdata) {
81 std::cout << "Device error: " << message << std::endl;
82}
83
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040084enum class BackendType {
85 OpenGL,
86 Metal,
Corentin Wallez79a62bf2017-05-24 16:04:55 +020087 Null,
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040088};
89
90enum class CmdBufType {
91 None,
92 Terrible,
Corentin Wallez682a8252017-05-09 15:34:13 +020093 //TODO(cwallez@chromium.org) double terrible cmdbuf
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040094};
95
96static BackendType backendType = BackendType::OpenGL;
97static CmdBufType cmdBufType = CmdBufType::Terrible;
98static BackendBinding* binding = nullptr;
99
100static GLFWwindow* window = nullptr;
101
102static nxt::wire::CommandHandler* wireServer = nullptr;
Corentin Wallez682a8252017-05-09 15:34:13 +0200103static nxt::wire::CommandHandler* wireClient = nullptr;
104static nxt::wire::TerribleCommandBuffer* c2sBuf = nullptr;
105static nxt::wire::TerribleCommandBuffer* s2cBuf = nullptr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400106
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400107void GetProcTableAndDevice(nxtProcTable* procs, nxt::Device* device) {
108 switch (backendType) {
109 case BackendType::OpenGL:
110 binding = new OpenGLBinding;
111 break;
112 case BackendType::Metal:
113 #if defined(__APPLE__)
114 binding = CreateMetalBinding();
115 #else
116 fprintf(stderr, "Metal backend no present on this platform\n");
117 #endif
118 break;
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200119 case BackendType::Null:
120 binding = new NullBinding;
121 break;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400122 }
123
124 if (!glfwInit()) {
125 return;
126 }
127
128 binding->SetupGLFWWindowHints();
129 window = glfwCreateWindow(640, 480, "NXT window", nullptr, nullptr);
130 if (!window) {
131 return;
132 }
133
134 binding->SetWindow(window);
135
136 nxtDevice backendDevice;
137 nxtProcTable backendProcs;
138 binding->GetProcAndDevice(&backendProcs, &backendDevice);
139
140 switch (cmdBufType) {
141 case CmdBufType::None:
142 *procs = backendProcs;
143 *device = nxt::Device::Acquire(backendDevice);
144 break;
145
146 case CmdBufType::Terrible:
147 {
Corentin Wallez682a8252017-05-09 15:34:13 +0200148 c2sBuf = new nxt::wire::TerribleCommandBuffer();
149 s2cBuf = new nxt::wire::TerribleCommandBuffer();
150
151 wireServer = nxt::wire::NewServerCommandHandler(backendDevice, backendProcs, s2cBuf);
152 c2sBuf->SetHandler(wireServer);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400153
154 nxtDevice clientDevice;
155 nxtProcTable clientProcs;
Corentin Wallez682a8252017-05-09 15:34:13 +0200156 wireClient = nxt::wire::NewClientDevice(&clientProcs, &clientDevice, c2sBuf);
157 s2cBuf->SetHandler(wireClient);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400158
159 *procs = clientProcs;
160 *device = nxt::Device::Acquire(clientDevice);
161 }
162 break;
163 }
164
Corentin Wallez4b410a32017-04-20 14:42:36 -0400165 procs->deviceSetErrorCallback(device->Get(), PrintDeviceError, 0);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400166}
167
168nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source) {
169 shaderc::Compiler compiler;
170 shaderc::CompileOptions options;
171
172 shaderc_shader_kind kind;
173 switch (stage) {
174 case nxt::ShaderStage::Vertex:
175 kind = shaderc_glsl_vertex_shader;
176 break;
177 case nxt::ShaderStage::Fragment:
178 kind = shaderc_glsl_fragment_shader;
179 break;
180 case nxt::ShaderStage::Compute:
181 kind = shaderc_glsl_compute_shader;
182 break;
183 }
184
185 auto result = compiler.CompileGlslToSpv(source, strlen(source), kind, "myshader?", options);
186 if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
187 std::cerr << result.GetErrorMessage();
188 return {};
189 }
190
191 size_t size = (result.cend() - result.cbegin());
192
193#ifdef DUMP_SPIRV_ASSEMBLY
194 {
195 auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind, "myshader?", options);
196 size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
197
198 char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
199 memcpy(buffer, resultAsm.cbegin(), sizeAsm);
200 buffer[sizeAsm] = '\0';
201 printf("SPIRV ASSEMBLY DUMP START\n%s\nSPIRV ASSEMBLY DUMP END\n", buffer);
202 free(buffer);
203 }
204#endif
205
206#ifdef DUMP_SPIRV_JS_ARRAY
207 printf("SPIRV JS ARRAY DUMP START\n");
208 for (size_t i = 0; i < size; i++) {
209 printf("%#010x", result.cbegin()[i]);
210 if ((i + 1) % 4 == 0) {
211 printf(",\n");
212 } else {
213 printf(", ");
214 }
215 }
216 printf("\n");
217 printf("SPIRV JS ARRAY DUMP END\n");
218#endif
219
220 return device.CreateShaderModuleBuilder()
221 .SetSource(size, result.cbegin())
222 .GetResult();
223}
224
Kai Ninomiya68df8b02017-05-16 14:04:22 -0700225void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
226 *renderPass = device.CreateRenderPassBuilder()
227 .SetAttachmentCount(1)
228 .AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
229 .SetSubpassCount(1)
230 .SubpassSetColorAttachment(0, 0, 0)
231 .GetResult();
232 *framebuffer = device.CreateFramebufferBuilder()
233 .SetRenderPass(*renderPass)
234 .SetDimensions(640, 480)
235 .GetResult();
236}
237
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400238extern "C" {
239 bool InitUtils(int argc, const char** argv) {
240 for (int i = 0; i < argc; i++) {
241 if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
242 i++;
243 if (i < argc && std::string("opengl") == argv[i]) {
244 backendType = BackendType::OpenGL;
245 continue;
246 }
247 if (i < argc && std::string("metal") == argv[i]) {
248 backendType = BackendType::Metal;
249 continue;
250 }
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200251 if (i < argc && std::string("null") == argv[i]) {
252 backendType = BackendType::Null;
253 continue;
254 }
255 fprintf(stderr, "--backend expects a backend name (opengl, metal, null)\n");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400256 return false;
257 }
258 if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
259 i++;
260 if (i < argc && std::string("none") == argv[i]) {
261 cmdBufType = CmdBufType::None;
262 continue;
263 }
264 if (i < argc && std::string("terrible") == argv[i]) {
265 cmdBufType = CmdBufType::Terrible;
266 continue;
267 }
268 fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
269 return false;
270 }
271 if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
272 printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200273 printf(" BACKEND is one of: opengl, metal, null\n");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400274 printf(" COMMAND_BUFFER is one of: none, terrible\n");
275 return false;
276 }
277 }
278 return true;
279 }
280
281 void GetProcTableAndDevice(nxtProcTable* procs, nxtDevice* device) {
282 nxt::Device cppDevice;
283 GetProcTableAndDevice(procs, &cppDevice);
284 *device = cppDevice.Release();
285 }
286
287 nxtShaderModule CreateShaderModule(nxtDevice device, nxtShaderStage stage, const char* source) {
288 return CreateShaderModule(device, static_cast<nxt::ShaderStage>(stage), source).Release();
289 }
290
291 void SwapBuffers() {
Corentin Wallez682a8252017-05-09 15:34:13 +0200292 if (cmdBufType == CmdBufType::Terrible) {
293 c2sBuf->Flush();
294 s2cBuf->Flush();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400295 }
296 glfwPollEvents();
297 binding->SwapBuffers();
298 }
299
300 bool ShouldQuit() {
301 return glfwWindowShouldClose(window);
302 }
303
304 GLFWwindow* GetWindow() {
305 return window;
306 }
307}