blob: fe8266db6d87321890afb4c46c8e20e5b5b114b4 [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 Wallez4b410a32017-04-20 14:42:36 -040062void PrintDeviceError(const char* message, nxt::CallbackUserdata) {
63 std::cout << "Device error: " << message << std::endl;
64}
65
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040066enum class BackendType {
67 OpenGL,
68 Metal,
69};
70
71enum class CmdBufType {
72 None,
73 Terrible,
Corentin Wallez682a8252017-05-09 15:34:13 +020074 //TODO(cwallez@chromium.org) double terrible cmdbuf
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040075};
76
77static BackendType backendType = BackendType::OpenGL;
78static CmdBufType cmdBufType = CmdBufType::Terrible;
79static BackendBinding* binding = nullptr;
80
81static GLFWwindow* window = nullptr;
82
83static nxt::wire::CommandHandler* wireServer = nullptr;
Corentin Wallez682a8252017-05-09 15:34:13 +020084static nxt::wire::CommandHandler* wireClient = nullptr;
85static nxt::wire::TerribleCommandBuffer* c2sBuf = nullptr;
86static nxt::wire::TerribleCommandBuffer* s2cBuf = nullptr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040087
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040088void GetProcTableAndDevice(nxtProcTable* procs, nxt::Device* device) {
89 switch (backendType) {
90 case BackendType::OpenGL:
91 binding = new OpenGLBinding;
92 break;
93 case BackendType::Metal:
94 #if defined(__APPLE__)
95 binding = CreateMetalBinding();
96 #else
97 fprintf(stderr, "Metal backend no present on this platform\n");
98 #endif
99 break;
100 }
101
102 if (!glfwInit()) {
103 return;
104 }
105
106 binding->SetupGLFWWindowHints();
107 window = glfwCreateWindow(640, 480, "NXT window", nullptr, nullptr);
108 if (!window) {
109 return;
110 }
111
112 binding->SetWindow(window);
113
114 nxtDevice backendDevice;
115 nxtProcTable backendProcs;
116 binding->GetProcAndDevice(&backendProcs, &backendDevice);
117
118 switch (cmdBufType) {
119 case CmdBufType::None:
120 *procs = backendProcs;
121 *device = nxt::Device::Acquire(backendDevice);
122 break;
123
124 case CmdBufType::Terrible:
125 {
Corentin Wallez682a8252017-05-09 15:34:13 +0200126 c2sBuf = new nxt::wire::TerribleCommandBuffer();
127 s2cBuf = new nxt::wire::TerribleCommandBuffer();
128
129 wireServer = nxt::wire::NewServerCommandHandler(backendDevice, backendProcs, s2cBuf);
130 c2sBuf->SetHandler(wireServer);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400131
132 nxtDevice clientDevice;
133 nxtProcTable clientProcs;
Corentin Wallez682a8252017-05-09 15:34:13 +0200134 wireClient = nxt::wire::NewClientDevice(&clientProcs, &clientDevice, c2sBuf);
135 s2cBuf->SetHandler(wireClient);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400136
137 *procs = clientProcs;
138 *device = nxt::Device::Acquire(clientDevice);
139 }
140 break;
141 }
142
Corentin Wallez4b410a32017-04-20 14:42:36 -0400143 procs->deviceSetErrorCallback(device->Get(), PrintDeviceError, 0);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400144}
145
146nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source) {
147 shaderc::Compiler compiler;
148 shaderc::CompileOptions options;
149
150 shaderc_shader_kind kind;
151 switch (stage) {
152 case nxt::ShaderStage::Vertex:
153 kind = shaderc_glsl_vertex_shader;
154 break;
155 case nxt::ShaderStage::Fragment:
156 kind = shaderc_glsl_fragment_shader;
157 break;
158 case nxt::ShaderStage::Compute:
159 kind = shaderc_glsl_compute_shader;
160 break;
161 }
162
163 auto result = compiler.CompileGlslToSpv(source, strlen(source), kind, "myshader?", options);
164 if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
165 std::cerr << result.GetErrorMessage();
166 return {};
167 }
168
169 size_t size = (result.cend() - result.cbegin());
170
171#ifdef DUMP_SPIRV_ASSEMBLY
172 {
173 auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind, "myshader?", options);
174 size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
175
176 char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
177 memcpy(buffer, resultAsm.cbegin(), sizeAsm);
178 buffer[sizeAsm] = '\0';
179 printf("SPIRV ASSEMBLY DUMP START\n%s\nSPIRV ASSEMBLY DUMP END\n", buffer);
180 free(buffer);
181 }
182#endif
183
184#ifdef DUMP_SPIRV_JS_ARRAY
185 printf("SPIRV JS ARRAY DUMP START\n");
186 for (size_t i = 0; i < size; i++) {
187 printf("%#010x", result.cbegin()[i]);
188 if ((i + 1) % 4 == 0) {
189 printf(",\n");
190 } else {
191 printf(", ");
192 }
193 }
194 printf("\n");
195 printf("SPIRV JS ARRAY DUMP END\n");
196#endif
197
198 return device.CreateShaderModuleBuilder()
199 .SetSource(size, result.cbegin())
200 .GetResult();
201}
202
203extern "C" {
204 bool InitUtils(int argc, const char** argv) {
205 for (int i = 0; i < argc; i++) {
206 if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
207 i++;
208 if (i < argc && std::string("opengl") == argv[i]) {
209 backendType = BackendType::OpenGL;
210 continue;
211 }
212 if (i < argc && std::string("metal") == argv[i]) {
213 backendType = BackendType::Metal;
214 continue;
215 }
216 fprintf(stderr, "--backend expects a backend name (opengl, metal)\n");
217 return false;
218 }
219 if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
220 i++;
221 if (i < argc && std::string("none") == argv[i]) {
222 cmdBufType = CmdBufType::None;
223 continue;
224 }
225 if (i < argc && std::string("terrible") == argv[i]) {
226 cmdBufType = CmdBufType::Terrible;
227 continue;
228 }
229 fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
230 return false;
231 }
232 if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
233 printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
234 printf(" BACKEND is one of: opengl, metal\n");
235 printf(" COMMAND_BUFFER is one of: none, terrible\n");
236 return false;
237 }
238 }
239 return true;
240 }
241
242 void GetProcTableAndDevice(nxtProcTable* procs, nxtDevice* device) {
243 nxt::Device cppDevice;
244 GetProcTableAndDevice(procs, &cppDevice);
245 *device = cppDevice.Release();
246 }
247
248 nxtShaderModule CreateShaderModule(nxtDevice device, nxtShaderStage stage, const char* source) {
249 return CreateShaderModule(device, static_cast<nxt::ShaderStage>(stage), source).Release();
250 }
251
252 void SwapBuffers() {
Corentin Wallez682a8252017-05-09 15:34:13 +0200253 if (cmdBufType == CmdBufType::Terrible) {
254 c2sBuf->Flush();
255 s2cBuf->Flush();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400256 }
257 glfwPollEvents();
258 binding->SwapBuffers();
259 }
260
261 bool ShouldQuit() {
262 return glfwWindowShouldClose(window);
263 }
264
265 GLFWwindow* GetWindow() {
266 return window;
267 }
268}