blob: 85ee67843942c2c7a8466af63a7e4a0ae2002851 [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();
Austin Engfc2bac72017-06-05 17:08:55 -040035BackendBinding* CreateD3D12Binding();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040036
37namespace backend {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040038 namespace opengl {
39 void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
40 void HACKCLEAR();
41 }
42}
43
44class OpenGLBinding : public BackendBinding {
45 public:
46 void SetupGLFWWindowHints() override {
47 #ifdef __APPLE__
48 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
49 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
50 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
51 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
52 #else
53 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
54 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
55 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
56 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
57 #endif
58 }
59 void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
60 glfwMakeContextCurrent(window);
61 backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
62 }
63 void SwapBuffers() override {
64 glfwSwapBuffers(window);
65 backend::opengl::HACKCLEAR();
66 }
67};
68
Corentin Wallez79a62bf2017-05-24 16:04:55 +020069namespace backend {
70 namespace null {
71 void Init(nxtProcTable* procs, nxtDevice* device);
72 }
73}
74
75class NullBinding : public BackendBinding {
76 public:
77 void SetupGLFWWindowHints() override {
78 }
79 void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
80 backend::null::Init(procs, device);
81 }
82 void SwapBuffers() override {
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,
Austin Engfc2bac72017-06-05 17:08:55 -040093 D3D12,
Corentin Wallez79a62bf2017-05-24 16:04:55 +020094 Null,
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040095};
96
97enum class CmdBufType {
98 None,
99 Terrible,
Corentin Wallez682a8252017-05-09 15:34:13 +0200100 //TODO(cwallez@chromium.org) double terrible cmdbuf
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400101};
102
Austin Engfc2bac72017-06-05 17:08:55 -0400103#if defined(__APPLE__)
104static BackendType backendType = BackendType::Metal;
105#elif defined(_WIN32)
106static BackendType backendType = BackendType::D3D12;
107#else
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400108static BackendType backendType = BackendType::OpenGL;
Austin Engfc2bac72017-06-05 17:08:55 -0400109#endif
110
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400111static CmdBufType cmdBufType = CmdBufType::Terrible;
112static BackendBinding* binding = nullptr;
113
114static GLFWwindow* window = nullptr;
115
116static nxt::wire::CommandHandler* wireServer = nullptr;
Corentin Wallez682a8252017-05-09 15:34:13 +0200117static nxt::wire::CommandHandler* wireClient = nullptr;
118static nxt::wire::TerribleCommandBuffer* c2sBuf = nullptr;
119static nxt::wire::TerribleCommandBuffer* s2cBuf = nullptr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400120
Corentin Wallez583e9a82017-05-29 11:30:29 -0700121nxt::Device CreateCppNXTDevice() {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400122 switch (backendType) {
123 case BackendType::OpenGL:
124 binding = new OpenGLBinding;
125 break;
126 case BackendType::Metal:
127 #if defined(__APPLE__)
128 binding = CreateMetalBinding();
129 #else
Austin Engfc2bac72017-06-05 17:08:55 -0400130 fprintf(stderr, "Metal backend not present on this platform\n");
131 #endif
132 break;
133 case BackendType::D3D12:
134 #if defined(_WIN32)
135 binding = CreateD3D12Binding();
136 #else
137 fprintf(stderr, "D3D12 backend not present on this platform\n");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400138 #endif
139 break;
Corentin Wallez79a62bf2017-05-24 16:04:55 +0200140 case BackendType::Null:
141 binding = new NullBinding;
142 break;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400143 }
144
145 if (!glfwInit()) {
Corentin Wallez583e9a82017-05-29 11:30:29 -0700146 return nxt::Device();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400147 }
148
149 binding->SetupGLFWWindowHints();
150 window = glfwCreateWindow(640, 480, "NXT window", nullptr, nullptr);
151 if (!window) {
Corentin Wallez583e9a82017-05-29 11:30:29 -0700152 return nxt::Device();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400153 }
154
155 binding->SetWindow(window);
156
157 nxtDevice backendDevice;
158 nxtProcTable backendProcs;
159 binding->GetProcAndDevice(&backendProcs, &backendDevice);
160
Corentin Wallez583e9a82017-05-29 11:30:29 -0700161 nxtDevice cDevice = nullptr;
162 nxtProcTable procs;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400163 switch (cmdBufType) {
164 case CmdBufType::None:
Corentin Wallez583e9a82017-05-29 11:30:29 -0700165 procs = backendProcs;
166 cDevice = backendDevice;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400167 break;
168
169 case CmdBufType::Terrible:
170 {
Corentin Wallez682a8252017-05-09 15:34:13 +0200171 c2sBuf = new nxt::wire::TerribleCommandBuffer();
172 s2cBuf = new nxt::wire::TerribleCommandBuffer();
173
174 wireServer = nxt::wire::NewServerCommandHandler(backendDevice, backendProcs, s2cBuf);
175 c2sBuf->SetHandler(wireServer);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400176
177 nxtDevice clientDevice;
178 nxtProcTable clientProcs;
Corentin Wallez682a8252017-05-09 15:34:13 +0200179 wireClient = nxt::wire::NewClientDevice(&clientProcs, &clientDevice, c2sBuf);
180 s2cBuf->SetHandler(wireClient);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400181
Corentin Wallez583e9a82017-05-29 11:30:29 -0700182 procs = clientProcs;
183 cDevice = clientDevice;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400184 }
185 break;
186 }
187
Corentin Wallez583e9a82017-05-29 11:30:29 -0700188 nxtSetProcs(&procs);
189 procs.deviceSetErrorCallback(cDevice, PrintDeviceError, 0);
190 return nxt::Device::Acquire(cDevice);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400191}
192
193nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source) {
194 shaderc::Compiler compiler;
195 shaderc::CompileOptions options;
196
197 shaderc_shader_kind kind;
198 switch (stage) {
199 case nxt::ShaderStage::Vertex:
200 kind = shaderc_glsl_vertex_shader;
201 break;
202 case nxt::ShaderStage::Fragment:
203 kind = shaderc_glsl_fragment_shader;
204 break;
205 case nxt::ShaderStage::Compute:
206 kind = shaderc_glsl_compute_shader;
207 break;
208 }
209
210 auto result = compiler.CompileGlslToSpv(source, strlen(source), kind, "myshader?", options);
211 if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
212 std::cerr << result.GetErrorMessage();
213 return {};
214 }
215
216 size_t size = (result.cend() - result.cbegin());
217
218#ifdef DUMP_SPIRV_ASSEMBLY
219 {
220 auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind, "myshader?", options);
221 size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
222
223 char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
224 memcpy(buffer, resultAsm.cbegin(), sizeAsm);
225 buffer[sizeAsm] = '\0';
226 printf("SPIRV ASSEMBLY DUMP START\n%s\nSPIRV ASSEMBLY DUMP END\n", buffer);
227 free(buffer);
228 }
229#endif
230
231#ifdef DUMP_SPIRV_JS_ARRAY
232 printf("SPIRV JS ARRAY DUMP START\n");
233 for (size_t i = 0; i < size; i++) {
234 printf("%#010x", result.cbegin()[i]);
235 if ((i + 1) % 4 == 0) {
236 printf(",\n");
237 } else {
238 printf(", ");
239 }
240 }
241 printf("\n");
242 printf("SPIRV JS ARRAY DUMP END\n");
243#endif
244
245 return device.CreateShaderModuleBuilder()
246 .SetSource(size, result.cbegin())
247 .GetResult();
248}
249
Kai Ninomiya68df8b02017-05-16 14:04:22 -0700250void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
251 *renderPass = device.CreateRenderPassBuilder()
252 .SetAttachmentCount(1)
253 .AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
254 .SetSubpassCount(1)
255 .SubpassSetColorAttachment(0, 0, 0)
256 .GetResult();
257 *framebuffer = device.CreateFramebufferBuilder()
258 .SetRenderPass(*renderPass)
259 .SetDimensions(640, 480)
260 .GetResult();
261}
262
Corentin Wallez001c2ea2017-06-05 13:12:16 -0400263nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage) {
Austin Eng5a67d192017-06-01 13:37:47 -0400264 nxt::Buffer buffer = device.CreateBufferBuilder()
Austin Eng39c901d2017-06-12 17:33:44 -0400265 .SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)
266 .SetInitialUsage(nxt::BufferUsageBit::TransferDst)
Austin Eng5a67d192017-06-01 13:37:47 -0400267 .SetSize(size)
268 .GetResult();
269 buffer.SetSubData(0, size / sizeof(uint32_t), reinterpret_cast<const uint32_t*>(data));
270 buffer.FreezeUsage(usage);
271 return buffer;
272}
273
Corentin Wallez931e6e82017-06-16 18:51:14 -0400274bool InitUtils(int argc, const char** argv) {
275 for (int i = 0; i < argc; i++) {
276 if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
277 i++;
278 if (i < argc && std::string("opengl") == argv[i]) {
279 backendType = BackendType::OpenGL;
280 continue;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400281 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400282 if (i < argc && std::string("metal") == argv[i]) {
283 backendType = BackendType::Metal;
284 continue;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400285 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400286 if (i < argc && std::string("d3d12") == argv[i]) {
287 backendType = BackendType::D3D12;
288 continue;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400289 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400290 if (i < argc && std::string("null") == argv[i]) {
291 backendType = BackendType::Null;
292 continue;
293 }
294 fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null)\n");
295 return false;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400296 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400297 if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
298 i++;
299 if (i < argc && std::string("none") == argv[i]) {
300 cmdBufType = CmdBufType::None;
301 continue;
302 }
303 if (i < argc && std::string("terrible") == argv[i]) {
304 cmdBufType = CmdBufType::Terrible;
305 continue;
306 }
307 fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
308 return false;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400309 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400310 if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
311 printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
312 printf(" BACKEND is one of: opengl, metal, d3d12, null\n");
313 printf(" COMMAND_BUFFER is one of: none, terrible\n");
314 return false;
315 }
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400316 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400317 return true;
318}
319
320void DoSwapBuffers() {
321 if (cmdBufType == CmdBufType::Terrible) {
322 c2sBuf->Flush();
323 s2cBuf->Flush();
324 }
325 glfwPollEvents();
326 binding->SwapBuffers();
327}
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400328
Corentin Wallez583e9a82017-05-29 11:30:29 -0700329#ifdef _WIN32
Corentin Wallez931e6e82017-06-16 18:51:14 -0400330void USleep(uint64_t usecs) {
331 Sleep(usecs / 1000);
332}
Corentin Wallez583e9a82017-05-29 11:30:29 -0700333#else
Corentin Wallez931e6e82017-06-16 18:51:14 -0400334void USleep(uint64_t usecs) {
335 usleep(usecs);
336}
Corentin Wallez583e9a82017-05-29 11:30:29 -0700337#endif
338
Corentin Wallez931e6e82017-06-16 18:51:14 -0400339bool ShouldQuit() {
340 return glfwWindowShouldClose(window);
341}
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400342
Corentin Wallez931e6e82017-06-16 18:51:14 -0400343GLFWwindow* GetGLFWWindow() {
344 return window;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400345}