blob: 9edab258a53b5d73698b8c4a0f633b02efb8a05d [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 Wallez001c2ea2017-06-05 13:12:16 -0400248nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage) {
Austin Eng5a67d192017-06-01 13:37:47 -0400249 nxt::Buffer buffer = device.CreateBufferBuilder()
250 .SetAllowedUsage(nxt::BufferUsageBit::Mapped | usage)
251 .SetInitialUsage(nxt::BufferUsageBit::Mapped)
252 .SetSize(size)
253 .GetResult();
254 buffer.SetSubData(0, size / sizeof(uint32_t), reinterpret_cast<const uint32_t*>(data));
255 buffer.FreezeUsage(usage);
256 return buffer;
257}
258
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400259extern "C" {
260 bool InitUtils(int argc, const char** argv) {
261 for (int i = 0; i < argc; i++) {
262 if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
263 i++;
264 if (i < argc && std::string("opengl") == argv[i]) {
265 backendType = BackendType::OpenGL;
266 continue;
267 }
268 if (i < argc && std::string("metal") == argv[i]) {
269 backendType = BackendType::Metal;
270 continue;
271 }
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200272 if (i < argc && std::string("null") == argv[i]) {
273 backendType = BackendType::Null;
274 continue;
275 }
276 fprintf(stderr, "--backend expects a backend name (opengl, metal, null)\n");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400277 return false;
278 }
279 if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
280 i++;
281 if (i < argc && std::string("none") == argv[i]) {
282 cmdBufType = CmdBufType::None;
283 continue;
284 }
285 if (i < argc && std::string("terrible") == argv[i]) {
286 cmdBufType = CmdBufType::Terrible;
287 continue;
288 }
289 fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
290 return false;
291 }
292 if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
293 printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200294 printf(" BACKEND is one of: opengl, metal, null\n");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400295 printf(" COMMAND_BUFFER is one of: none, terrible\n");
296 return false;
297 }
298 }
299 return true;
300 }
301
Corentin Wallez583e9a82017-05-29 11:30:29 -0700302 nxtDevice CreateNXTDevice() {
303 return CreateCppNXTDevice().Release();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400304 }
305
306 nxtShaderModule CreateShaderModule(nxtDevice device, nxtShaderStage stage, const char* source) {
307 return CreateShaderModule(device, static_cast<nxt::ShaderStage>(stage), source).Release();
308 }
309
Corentin Wallez583e9a82017-05-29 11:30:29 -0700310 void DoSwapBuffers() {
Corentin Wallez682a8252017-05-09 15:34:13 +0200311 if (cmdBufType == CmdBufType::Terrible) {
312 c2sBuf->Flush();
313 s2cBuf->Flush();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400314 }
315 glfwPollEvents();
316 binding->SwapBuffers();
317 }
318
Corentin Wallez583e9a82017-05-29 11:30:29 -0700319#ifdef _WIN32
320 void USleep(uint64_t usecs) {
321 Sleep(usecs / 1000);
322 }
323#else
324 void USleep(uint64_t usecs) {
325 usleep(usecs);
326 }
327#endif
328
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400329 bool ShouldQuit() {
330 return glfwWindowShouldClose(window);
331 }
332
Corentin Wallez583e9a82017-05-29 11:30:29 -0700333 GLFWwindow* GetGLFWWindow() {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400334 return window;
335 }
336}