gl_vk_simple_interop

Форк
0
418 строк · 13.2 Кб
1
/*
2
 * Copyright (c) 2019-2024, NVIDIA CORPORATION.  All rights reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 *
16
 * SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION
17
 * SPDX-License-Identifier: Apache-2.0
18
 */
19

20

21
//--------------------------------------------------------------------------------------------------
22
// Very simple Vulkan-OpenGL example:
23
// - The vertex buffer is allocated with Vulkan, but used by OpenGL to render
24
// - The animation is updating the buffer allocated by Vulkan, and the changes are
25
//   reflected in the OGL render.
26
//
27

28
#ifdef WIN32
29
#include <accctrl.h>
30
#include <aclapi.h>
31
#endif
32

33
#include <array>
34
#include <chrono>
35
#include <iostream>
36
#include <vulkan/vulkan_core.h>
37

38
#define IMGUI_DEFINE_MATH_OPERATORS
39

40
#include "backends/imgui_impl_glfw.h"
41
#include "imgui/imgui_helper.h"
42
#include "imgui/backends/imgui_impl_gl.h"
43

44
#include "compute.hpp"
45
#include "nvgl/contextwindow_gl.hpp"
46
#include "nvgl/extensions_gl.hpp"
47
#include "nvpsystem.hpp"
48
#include "nvvkhl/appbase_vkpp.hpp"
49
#include "nvvk/commands_vk.hpp"
50
#include "nvvk/context_vk.hpp"
51

52
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
53

54
int const SAMPLE_SIZE_WIDTH  = 1200;
55
int const SAMPLE_SIZE_HEIGHT = 900;
56

57
// Default search path for shaders
58
std::vector<std::string> defaultSearchPaths{
59
    "./",
60
    "../",
61
    std::string(PROJECT_NAME),
62
    std::string("SPV_" PROJECT_NAME),
63
    NVPSystem::exePath() + PROJECT_RELDIRECTORY,
64
    NVPSystem::exePath() + std::string(PROJECT_RELDIRECTORY),
65
};
66

67
// An array of 3 vectors which represents 3 vertices
68
struct Vertex
69
{
70
  glm::vec3 pos;
71
  glm::vec2 uv;
72
};
73

74
// The triangle
75
static std::vector<Vertex> g_vertexDataVK = {{{-1.0f, -1.0f, 0.0f}, {0, 0}},
76
                                             {{1.0f, -0.0f, 0.0f}, {1, 0}},
77
                                             {{0.0f, 1.0f, 0.0f}, {0.5, 1}}};
78

79

80
//--------------------------------------------------------------------------------------------------
81
//
82
//
83
class InteropExample : public nvvkhl::AppBase
84
{
85
public:
86
  void prepare(uint32_t queueIdxCompute)
87
  {
88
    m_alloc.init(m_device, m_physicalDevice);
89

90
    createShaders();   // Create the GLSL shaders
91
    createBufferVK();  // Create the vertex buffer
92

93
    // Initialize the Vulkan compute shader
94
    m_compute.setup(m_device, m_physicalDevice, m_graphicsQueueIndex, queueIdxCompute, m_alloc);
95
    m_compute.update({1024, 1024});  // Initial size
96
  }
97

98
  void destroy() override
99
  {
100
    m_device.waitIdle();
101
    m_bufferVk.destroy(m_alloc);
102
    m_compute.destroy();
103

104
    ImGui_ImplGlfw_Shutdown();
105
    ImGui::ShutdownGL();
106
    AppBase::destroy();
107
  }
108

109
  //--------------------------------------------------------------------------------------------------
110
  // Create the vertex buffer with Vulkan
111
  //
112
  void createBufferVK()
113
  {
114
    m_bufferVk.bufVk = m_alloc.createBuffer(g_vertexDataVK.size() * sizeof(Vertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
115
                                            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
116

117
    createBufferGL(m_alloc, m_bufferVk);
118

119
    // Same as usual
120
    int pos_loc = 0;
121
    int uv_loc  = 1;
122
    glCreateVertexArrays(1, &m_vertexArray);
123
    glEnableVertexArrayAttrib(m_vertexArray, pos_loc);
124
    glEnableVertexArrayAttrib(m_vertexArray, uv_loc);
125

126
    glVertexArrayAttribFormat(m_vertexArray, pos_loc, 3, GL_FLOAT, GL_FALSE, offsetof(Vertex, pos));
127
    glVertexArrayAttribBinding(m_vertexArray, pos_loc, 0);
128
    glVertexArrayAttribFormat(m_vertexArray, uv_loc, 2, GL_FLOAT, GL_FALSE, offsetof(Vertex, uv));
129
    glVertexArrayAttribBinding(m_vertexArray, uv_loc, 0);
130

131
    glVertexArrayVertexBuffer(m_vertexArray, 0, m_bufferVk.oglId, 0, sizeof(Vertex));
132
  }
133

134
  //--------------------------------------------------------------------------------------------------
135
  //
136
  //
137
  void onWindowRefresh()
138
  {
139
    // Compute FPS
140
    static float fps = 0.f;
141
    {
142
      static float frameNumber{0};
143
      static auto  tStart = std::chrono::high_resolution_clock::now();
144
      auto         tEnd   = std::chrono::high_resolution_clock::now();
145
      auto         tDiff  = std::chrono::duration<float>(tEnd - tStart).count();
146
      frameNumber++;
147
      if(tDiff > 1.f)
148
      {
149
        tStart = tEnd;
150
        fps    = frameNumber / tDiff;
151
        LOGI("FPS: %f\n", fps);
152
        frameNumber = 0;
153
      }
154
    }
155

156
    // Input GUI
157
    ImGui::NewFrame();
158
    ImGui::SetNextWindowSize(ImGuiH::dpiScaled(350, 0), ImGuiCond_FirstUseEver);
159
    if(ImGui::Begin("gl_vk_simple_interop"))
160
    {
161
      ImGui::Text("FPS: %.3f", fps);
162

163
      int textureWidth  = int(m_compute.m_textureTarget.imgSize.width);
164
      int textureHeight = int(m_compute.m_textureTarget.imgSize.height);
165
      // The slider max of 16384 here is somewhat arbitrary; Ctrl-click to set
166
      // it to a larger value. It's set to 16K so that casually sliding the
167
      // sliders won't run out of memory on most GPUs.
168
      // Use glGetIntegerv(GL_MAX_TEXTURE_SIZE) to get the maximum texture size.
169
      ImGui::SliderInt("Texture Width", &textureWidth, 1, 16384, "%d", ImGuiSliderFlags_Logarithmic);
170
      ImGui::SliderInt("Texture Height", &textureHeight, 1, 16384, "%d", ImGuiSliderFlags_Logarithmic);
171
      const VkExtent2D newSize = {uint32_t(textureWidth), uint32_t(textureHeight)};
172
      // Did the size change?
173
      if(0 != memcmp(&newSize, &m_compute.m_textureTarget.imgSize, sizeof(VkExtent2D)))
174
      {
175
        // Recreate the interop texture:
176
        m_compute.update(newSize);
177
      }
178
    }
179
    ImGui::End();
180

181
    glViewport(0, 0, m_size.width, m_size.height);
182

183
    // Signal Vulkan it can use the texture
184
    GLenum dstLayout = GL_LAYOUT_SHADER_READ_ONLY_EXT;
185
    glSignalSemaphoreEXT(m_compute.m_semaphores.glReady, 0, nullptr, 1, &m_compute.m_textureTarget.oglId, &dstLayout);
186

187
    // Invoke Vulkan
188
    m_compute.buildCommandBuffers();
189
    m_compute.submit();
190

191
    // Wait (on the GPU side) for the Vulkan semaphore to be signaled (finished compute)
192
    GLenum srcLayout = GL_LAYOUT_COLOR_ATTACHMENT_EXT;
193
    glWaitSemaphoreEXT(m_compute.m_semaphores.glComplete, 0, nullptr, 1, &m_compute.m_textureTarget.oglId, &srcLayout);
194

195
    // Issue OpenGL commands to draw a triangle using this texture
196
    glBindVertexArray(m_vertexArray);
197
    glBindTextureUnit(0, m_compute.m_textureTarget.oglId);
198
    glUseProgram(m_programID);
199
    glDrawArrays(GL_TRIANGLES, 0, 3);
200
    glBindTextureUnit(0, 0);
201

202
    // Draw GUI
203
    ImGui::Render();
204
    ImGui::RenderDrawDataGL(ImGui::GetDrawData());
205
    ImGui::EndFrame();
206
  }
207

208
  //--------------------------------------------------------------------------------------------------
209
  //
210
  //
211
  void animate()
212
  {
213
    static auto startTime   = std::chrono::high_resolution_clock::now();
214
    auto        currentTime = std::chrono::high_resolution_clock::now();
215
    float       t           = std::chrono::duration<float>(currentTime - startTime).count() * 0.5f;
216
    // Modify the buffer and upload it in the Vulkan allocated buffer
217
    g_vertexDataVK[0].pos.x = sinf(t);
218
    g_vertexDataVK[1].pos.y = cosf(t);
219
    g_vertexDataVK[2].pos.x = -sinf(t);
220

221
    void* mapped = m_alloc.map(m_bufferVk.bufVk);
222
    // This works because the buffer was created with
223
    // VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
224
    memcpy(mapped, g_vertexDataVK.data(), g_vertexDataVK.size() * sizeof(Vertex));
225
    m_alloc.unmap(m_bufferVk.bufVk);
226
  }
227

228
  //--------------------------------------------------------------------------------------------------
229
  // Creating the OpenGL shaders
230
  //
231
  GLuint createShaders()
232
  {
233
    // OpenGL - Create shaders
234
    char buf[512];
235
    int  len = 0;
236

237
    // OpenGL 4.2 Core
238
    GLuint        vs  = glCreateShader(GL_VERTEX_SHADER);
239
    GLchar const* vss = {R"(
240
      #version 450
241
      layout(location = 0) in vec3 inVertex;
242
      layout(location = 1) in vec2 inUV;
243
      layout (location = 0) out vec2 outUV;
244

245
      void main()
246
      {
247
        outUV = inUV;
248
        gl_Position = vec4(inVertex, 1.0f);
249
      }
250
    )"};
251

252
    glShaderSource(vs, 1, &vss, nullptr);
253
    glCompileShader(vs);
254
    glGetShaderInfoLog(vs, 512, (GLsizei*)&len, buf);
255

256
    GLuint        fs  = glCreateShader(GL_FRAGMENT_SHADER);
257
    GLchar const* fss = {R"(
258
      #version 450
259
      layout (location = 0) in vec2 inUV;
260
      layout(location = 0) out vec4 fragColor;
261
            
262
      uniform sampler2D myTextureSampler;
263

264
      void main()
265
      {
266
        vec3 color = texture( myTextureSampler, inUV ).rgb;
267
        fragColor = vec4(color,1);
268
      }
269
            
270
    )"};
271

272
    glShaderSource(fs, 1, &fss, nullptr);
273
    glCompileShader(fs);
274
    glGetShaderInfoLog(fs, 512, (GLsizei*)&len, buf);
275

276
    GLuint mSH2D = glCreateProgram();
277
    glAttachShader(mSH2D, vs);
278
    glAttachShader(mSH2D, fs);
279
    glLinkProgram(mSH2D);
280

281
    m_programID = mSH2D;
282
    return mSH2D;
283
  }
284

285
  //--------------------------------------------------------------------------------------------------
286
  // Initialization of the GUI
287
  // - Need to be call after the device creation
288
  //
289
  void initUI(int width, int height)
290
  {
291
    m_size.width  = width;
292
    m_size.height = height;
293

294
    // UI
295
    ImGuiH::Init(width, height, this, ImGuiH::FONT_PROPORTIONAL_SCALED);
296
    ImGui::InitGL();
297
  }
298

299
  //- Override the default resize
300
  void onFramebufferSize(int w, int h) override
301
  {
302
    m_size.width               = w;
303
    m_size.height              = h;
304
    ImGui::GetIO().DisplaySize = ImVec2(float(w), float(h));
305
  }
306

307
  virtual void onMouseMotion(int x, int y) override { ImGuiH::mouse_pos(x, y); }
308
  virtual void onMouseButton(int button, int action, int mods) override { ImGuiH::mouse_button(button, action); }
309
  virtual void onMouseWheel(int delta) override { ImGuiH::mouse_wheel(delta); }
310
  virtual void onKeyboard(int key, int /*scancode*/, int action, int mods) override
311
  {
312
    ImGuiH::key_button(key, action, mods);
313
  }
314
  virtual void onKeyboardChar(unsigned char key) override { ImGuiH::key_char(key); }
315

316
private:
317
  nvvk::BufferVkGL                       m_bufferVk;
318
  nvvk::ExportResourceAllocatorDedicated m_alloc;
319

320
  GLuint m_vertexArray = 0;  // VAO
321
  GLuint m_programID   = 0;  // Shader program
322

323
  ComputeImageVk m_compute;  // Compute in Vulkan
324
};
325

326
//--------------------------------------------------------------------------------------------------
327
//
328
//
329
int main(int argc, char** argv)
330
{
331
  // setup some basic things for the sample, logging file for example
332
  NVPSystem system(PROJECT_NAME);
333

334
  nvprintSetBreakpoints(true);  // DEBUG
335
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
336
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
337
  // Create window with graphics context
338
  GLFWwindow* window = glfwCreateWindow(SAMPLE_SIZE_WIDTH, SAMPLE_SIZE_HEIGHT, PROJECT_NAME, NULL, NULL);
339
  if(window == nullptr)
340
    return 1;
341
  glfwMakeContextCurrent(window);
342
  glfwSwapInterval(1);  // Enable vsync
343

344
  nvvk::ContextCreateInfo deviceInfo;
345
  deviceInfo.addInstanceExtension(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
346
  deviceInfo.addInstanceExtension(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME);
347
  deviceInfo.addDeviceExtension(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
348
  deviceInfo.addDeviceExtension(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
349
#ifdef WIN32
350
  deviceInfo.addDeviceExtension(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
351
  deviceInfo.addDeviceExtension(VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME);
352
#else
353
  deviceInfo.addDeviceExtension(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
354
  deviceInfo.addDeviceExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
355
#endif
356

357
  // Creating the Vulkan instance and device
358
  nvvk::Context vkctx;
359
  if(!vkctx.init(deviceInfo))
360
  {
361
    LOGE("Could not initialize the Vulkan instance and device! See the above messages for more info.\n");
362
    return EXIT_FAILURE;
363
  }
364

365

366
  InteropExample      example;
367
  nvgl::ContextWindow contextWindowGL;
368

369
  // Loading all OpenGL symbols
370
  load_GL(nvgl::ContextWindow::sysGetProcAddress);
371
  if(!has_GL_EXT_semaphore)
372
  {
373
    LOGE("GL_EXT_semaphore Not Available !\n");
374
    return EXIT_FAILURE;
375
  }
376

377
  example.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex);
378

379
  // Printing which GPU we are using for Vulkan
380
  LOGI("using %s\n", example.getPhysicalDevice().getProperties().deviceName.data());
381

382
  // Initialize the window, UI ..
383
  example.initUI(SAMPLE_SIZE_WIDTH, SAMPLE_SIZE_HEIGHT);
384

385
  // Prepare the example
386
  example.prepare(vkctx.m_queueGCT.familyIndex);
387

388

389
  // GLFW Callback
390
  example.setupGlfwCallbacks(window);
391
  ImGui_ImplGlfw_InitForOpenGL(window, false);
392

393
  // Main loop
394
  while(!glfwWindowShouldClose(window))
395
  {
396
    glfwPollEvents();
397
    int w, h;
398
    glfwGetWindowSize(window, &w, &h);
399
    if(w == 0 || h == 0)
400
      continue;
401

402
    glClearColor(0.5f, 0.0f, 0.0f, 0.0f);
403
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
404

405
    example.animate();
406
    example.onWindowRefresh();
407

408
    glfwSwapBuffers(window);
409
  }
410

411
  example.destroy();
412
  vkctx.deinit();
413

414
  glfwDestroyWindow(window);
415
  glfwTerminate();
416

417
  return EXIT_SUCCESS;
418
}
419

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.