blob: 7c563c475a0a1988e7b04ca92df93892d1b8e105 [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
Corentin Wallez1bd219d2017-06-19 12:53:38 -040015#include "utils/BackendBinding.h"
16#include "../src/wire/TerribleCommandBuffer.h"
17
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040018#include <nxt/nxt.h>
19#include <nxt/nxtcpp.h>
20#include <shaderc/shaderc.hpp>
21#include "GLFW/glfw3.h"
22
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040023#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 Wallez4b410a32017-04-20 14:42:36 -040034void PrintDeviceError(const char* message, nxt::CallbackUserdata) {
35 std::cout << "Device error: " << message << std::endl;
36}
37
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040038enum class CmdBufType {
39 None,
40 Terrible,
Corentin Wallez682a8252017-05-09 15:34:13 +020041 //TODO(cwallez@chromium.org) double terrible cmdbuf
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040042};
43
Austin Engfc2bac72017-06-05 17:08:55 -040044#if defined(__APPLE__)
Corentin Wallez1bd219d2017-06-19 12:53:38 -040045static utils::BackendType backendType = utils::BackendType::Metal;
Austin Engfc2bac72017-06-05 17:08:55 -040046#elif defined(_WIN32)
Corentin Wallez1bd219d2017-06-19 12:53:38 -040047static utils::BackendType backendType = utils::BackendType::D3D12;
Austin Engfc2bac72017-06-05 17:08:55 -040048#else
Corentin Wallez1bd219d2017-06-19 12:53:38 -040049static utils::BackendType backendType = utils::BackendType::OpenGL;
Austin Engfc2bac72017-06-05 17:08:55 -040050#endif
51
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040052static CmdBufType cmdBufType = CmdBufType::Terrible;
Corentin Wallez1bd219d2017-06-19 12:53:38 -040053static utils::BackendBinding* binding = nullptr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040054
55static GLFWwindow* window = nullptr;
56
57static nxt::wire::CommandHandler* wireServer = nullptr;
Corentin Wallez682a8252017-05-09 15:34:13 +020058static nxt::wire::CommandHandler* wireClient = nullptr;
59static nxt::wire::TerribleCommandBuffer* c2sBuf = nullptr;
60static nxt::wire::TerribleCommandBuffer* s2cBuf = nullptr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040061
Corentin Wallez583e9a82017-05-29 11:30:29 -070062nxt::Device CreateCppNXTDevice() {
Corentin Wallez1bd219d2017-06-19 12:53:38 -040063 binding = utils::CreateBinding(backendType);
64 if (binding == nullptr) {
65 return nxt::Device();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040066 }
67
68 if (!glfwInit()) {
Corentin Wallez583e9a82017-05-29 11:30:29 -070069 return nxt::Device();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040070 }
71
72 binding->SetupGLFWWindowHints();
73 window = glfwCreateWindow(640, 480, "NXT window", nullptr, nullptr);
74 if (!window) {
Corentin Wallez583e9a82017-05-29 11:30:29 -070075 return nxt::Device();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040076 }
77
78 binding->SetWindow(window);
79
80 nxtDevice backendDevice;
81 nxtProcTable backendProcs;
82 binding->GetProcAndDevice(&backendProcs, &backendDevice);
83
Corentin Wallez583e9a82017-05-29 11:30:29 -070084 nxtDevice cDevice = nullptr;
85 nxtProcTable procs;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040086 switch (cmdBufType) {
87 case CmdBufType::None:
Corentin Wallez583e9a82017-05-29 11:30:29 -070088 procs = backendProcs;
89 cDevice = backendDevice;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040090 break;
91
92 case CmdBufType::Terrible:
93 {
Corentin Wallez682a8252017-05-09 15:34:13 +020094 c2sBuf = new nxt::wire::TerribleCommandBuffer();
95 s2cBuf = new nxt::wire::TerribleCommandBuffer();
96
97 wireServer = nxt::wire::NewServerCommandHandler(backendDevice, backendProcs, s2cBuf);
98 c2sBuf->SetHandler(wireServer);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040099
100 nxtDevice clientDevice;
101 nxtProcTable clientProcs;
Corentin Wallez682a8252017-05-09 15:34:13 +0200102 wireClient = nxt::wire::NewClientDevice(&clientProcs, &clientDevice, c2sBuf);
103 s2cBuf->SetHandler(wireClient);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400104
Corentin Wallez583e9a82017-05-29 11:30:29 -0700105 procs = clientProcs;
106 cDevice = clientDevice;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400107 }
108 break;
109 }
110
Corentin Wallez583e9a82017-05-29 11:30:29 -0700111 nxtSetProcs(&procs);
112 procs.deviceSetErrorCallback(cDevice, PrintDeviceError, 0);
113 return nxt::Device::Acquire(cDevice);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400114}
115
116nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source) {
117 shaderc::Compiler compiler;
118 shaderc::CompileOptions options;
119
120 shaderc_shader_kind kind;
121 switch (stage) {
122 case nxt::ShaderStage::Vertex:
123 kind = shaderc_glsl_vertex_shader;
124 break;
125 case nxt::ShaderStage::Fragment:
126 kind = shaderc_glsl_fragment_shader;
127 break;
128 case nxt::ShaderStage::Compute:
129 kind = shaderc_glsl_compute_shader;
130 break;
131 }
132
133 auto result = compiler.CompileGlslToSpv(source, strlen(source), kind, "myshader?", options);
134 if (result.GetCompilationStatus() != shaderc_compilation_status_success) {
135 std::cerr << result.GetErrorMessage();
136 return {};
137 }
138
139 size_t size = (result.cend() - result.cbegin());
140
141#ifdef DUMP_SPIRV_ASSEMBLY
142 {
143 auto resultAsm = compiler.CompileGlslToSpvAssembly(source, strlen(source), kind, "myshader?", options);
144 size_t sizeAsm = (resultAsm.cend() - resultAsm.cbegin());
145
146 char* buffer = reinterpret_cast<char*>(malloc(sizeAsm + 1));
147 memcpy(buffer, resultAsm.cbegin(), sizeAsm);
148 buffer[sizeAsm] = '\0';
149 printf("SPIRV ASSEMBLY DUMP START\n%s\nSPIRV ASSEMBLY DUMP END\n", buffer);
150 free(buffer);
151 }
152#endif
153
154#ifdef DUMP_SPIRV_JS_ARRAY
155 printf("SPIRV JS ARRAY DUMP START\n");
156 for (size_t i = 0; i < size; i++) {
157 printf("%#010x", result.cbegin()[i]);
158 if ((i + 1) % 4 == 0) {
159 printf(",\n");
160 } else {
161 printf(", ");
162 }
163 }
164 printf("\n");
165 printf("SPIRV JS ARRAY DUMP END\n");
166#endif
167
168 return device.CreateShaderModuleBuilder()
169 .SetSource(size, result.cbegin())
170 .GetResult();
171}
172
Kai Ninomiya68df8b02017-05-16 14:04:22 -0700173void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
174 *renderPass = device.CreateRenderPassBuilder()
175 .SetAttachmentCount(1)
176 .AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
177 .SetSubpassCount(1)
178 .SubpassSetColorAttachment(0, 0, 0)
179 .GetResult();
180 *framebuffer = device.CreateFramebufferBuilder()
181 .SetRenderPass(*renderPass)
182 .SetDimensions(640, 480)
183 .GetResult();
184}
185
Corentin Wallez001c2ea2017-06-05 13:12:16 -0400186nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage) {
Austin Eng5a67d192017-06-01 13:37:47 -0400187 nxt::Buffer buffer = device.CreateBufferBuilder()
Austin Eng39c901d2017-06-12 17:33:44 -0400188 .SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)
189 .SetInitialUsage(nxt::BufferUsageBit::TransferDst)
Austin Eng5a67d192017-06-01 13:37:47 -0400190 .SetSize(size)
191 .GetResult();
192 buffer.SetSubData(0, size / sizeof(uint32_t), reinterpret_cast<const uint32_t*>(data));
193 buffer.FreezeUsage(usage);
194 return buffer;
195}
196
Corentin Wallez931e6e82017-06-16 18:51:14 -0400197bool InitUtils(int argc, const char** argv) {
198 for (int i = 0; i < argc; i++) {
199 if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) {
200 i++;
Corentin Wallez1bd219d2017-06-19 12:53:38 -0400201 if (i < argc && std::string("d3d12") == argv[i]) {
202 backendType = utils::BackendType::D3D12;
Corentin Wallez931e6e82017-06-16 18:51:14 -0400203 continue;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400204 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400205 if (i < argc && std::string("metal") == argv[i]) {
Corentin Wallez1bd219d2017-06-19 12:53:38 -0400206 backendType = utils::BackendType::Metal;
Corentin Wallez931e6e82017-06-16 18:51:14 -0400207 continue;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400208 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400209 if (i < argc && std::string("null") == argv[i]) {
Corentin Wallez1bd219d2017-06-19 12:53:38 -0400210 backendType = utils::BackendType::Null;
Corentin Wallez931e6e82017-06-16 18:51:14 -0400211 continue;
212 }
Corentin Wallez1bd219d2017-06-19 12:53:38 -0400213 if (i < argc && std::string("opengl") == argv[i]) {
214 backendType = utils::BackendType::OpenGL;
215 continue;
216 }
217 if (i < argc && std::string("vulkan") == argv[i]) {
218 backendType = utils::BackendType::Vulkan;
219 continue;
220 }
221 fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n");
Corentin Wallez931e6e82017-06-16 18:51:14 -0400222 return false;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400223 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400224 if (std::string("-c") == argv[i] || std::string("--comand-buffer") == argv[i]) {
225 i++;
226 if (i < argc && std::string("none") == argv[i]) {
227 cmdBufType = CmdBufType::None;
228 continue;
229 }
230 if (i < argc && std::string("terrible") == argv[i]) {
231 cmdBufType = CmdBufType::Terrible;
232 continue;
233 }
234 fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n");
235 return false;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400236 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400237 if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) {
238 printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]);
Corentin Wallez1bd219d2017-06-19 12:53:38 -0400239 printf(" BACKEND is one of: d3d12, metal, null, opengl, vulkan\n");
Corentin Wallez931e6e82017-06-16 18:51:14 -0400240 printf(" COMMAND_BUFFER is one of: none, terrible\n");
241 return false;
242 }
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400243 }
Corentin Wallez931e6e82017-06-16 18:51:14 -0400244 return true;
245}
246
247void DoSwapBuffers() {
248 if (cmdBufType == CmdBufType::Terrible) {
249 c2sBuf->Flush();
250 s2cBuf->Flush();
251 }
252 glfwPollEvents();
253 binding->SwapBuffers();
254}
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400255
Corentin Wallez583e9a82017-05-29 11:30:29 -0700256#ifdef _WIN32
Corentin Wallez931e6e82017-06-16 18:51:14 -0400257void USleep(uint64_t usecs) {
258 Sleep(usecs / 1000);
259}
Corentin Wallez583e9a82017-05-29 11:30:29 -0700260#else
Corentin Wallez931e6e82017-06-16 18:51:14 -0400261void USleep(uint64_t usecs) {
262 usleep(usecs);
263}
Corentin Wallez583e9a82017-05-29 11:30:29 -0700264#endif
265
Corentin Wallez931e6e82017-06-16 18:51:14 -0400266bool ShouldQuit() {
267 return glfwWindowShouldClose(window);
268}
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400269
Corentin Wallez931e6e82017-06-16 18:51:14 -0400270GLFWwindow* GetGLFWWindow() {
271 return window;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400272}