xrd-scene-renderer.c 23.6 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * xrdesktop
 * Copyright 2019 Collabora Ltd.
 * Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
 * SPDX-License-Identifier: MIT
 */

#include "xrd-scene-renderer.h"

10 11
#include <graphene.h>

12
#include <gulkan.h>
13
#include <gxr.h>
14

15 16 17 18 19 20
#include "xrd-controller.h"
#include "xrd-scene-pointer.h"
#include "xrd-scene-pointer-tip.h"

#include "graphene-ext.h"

21
typedef struct {
22 23
  graphene_point3d_t position;
  graphene_point_t   uv;
24
} XrdSceneVertex;
25

26 27
typedef struct {
  float position[4];
28
  float color[3];
29 30 31 32 33 34 35 36
  float radius;
} XrdSceneLight;

typedef struct {
  XrdSceneLight lights[2];
  int active_lights;
} XrdSceneLights;

37 38
struct _XrdSceneRenderer
{
39
  GulkanRenderer parent;
40

41 42
  VkSampleCountFlagBits sample_count;
  float render_scale;
43 44 45 46 47 48 49 50

  VkShaderModule shader_modules[PIPELINE_COUNT * 2];
  VkPipeline pipelines[PIPELINE_COUNT];
  VkDescriptorSetLayout descriptor_set_layout;
  VkPipelineLayout pipeline_layout;
  VkPipelineCache pipeline_cache;

  GulkanFrameBuffer *framebuffer[2];
51
  GulkanRenderPass *render_pass;
52

53 54 55 56
  gpointer scene_client;

  XrdSceneLights lights;
  GulkanUniformBuffer *lights_buffer;
57

58 59
  GxrContext *context;

60 61 62 63 64 65
  void
  (*render_eye) (uint32_t         eye,
                 VkCommandBuffer  cmd_buffer,
                 VkPipelineLayout pipeline_layout,
                 VkPipeline      *pipelines,
                 gpointer         data);
66 67

  void (*update_lights) (gpointer data);
68 69
};

70
G_DEFINE_TYPE (XrdSceneRenderer, xrd_scene_renderer, GULKAN_TYPE_RENDERER)
71 72 73 74 75 76 77 78 79 80 81 82 83 84

static void
xrd_scene_renderer_finalize (GObject *gobject);

static void
xrd_scene_renderer_class_init (XrdSceneRendererClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  object_class->finalize = xrd_scene_renderer_finalize;
}

static void
xrd_scene_renderer_init (XrdSceneRenderer *self)
{
85
  self->render_scale = 1.0f;
86
  self->render_eye = NULL;
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
  self->scene_client = NULL;

  self->lights.active_lights = 0;
  graphene_vec4_t position;
  graphene_vec4_init (&position, 0, 0, 0, 1);

  graphene_vec4_t color;
  graphene_vec4_init (&color,.078f, .471f, .675f, 1);

  for (uint32_t i = 0; i < 2; i++)
    {
      graphene_vec4_to_float (&position, self->lights.lights[i].position);
      graphene_vec4_to_float (&color, self->lights.lights[i].color);
      self->lights.lights[i].radius = 0.1f;
    }
102 103 104 105

  self->descriptor_set_layout = VK_NULL_HANDLE;
  self->pipeline_layout = VK_NULL_HANDLE;
  self->pipeline_cache = VK_NULL_HANDLE;
106 107

  self->context = NULL;
108 109 110 111 112 113
}

static void
xrd_scene_renderer_finalize (GObject *gobject)
{
  XrdSceneRenderer *self = XRD_SCENE_RENDERER (gobject);
114

115 116 117
  GulkanClient *gc = gxr_context_get_gulkan (self->context);

  VkDevice device = gulkan_client_get_device_handle (gc);
118 119 120 121 122
  if (device != VK_NULL_HANDLE)
    vkDeviceWaitIdle (device);

  if (device != VK_NULL_HANDLE)
    {
123 124
      g_object_unref (self->lights_buffer);

125 126 127 128 129 130 131 132 133 134 135 136
      for (uint32_t eye = 0; eye < 2; eye++)
        g_object_unref (self->framebuffer[eye]);

      vkDestroyPipelineLayout (device, self->pipeline_layout, NULL);
      vkDestroyDescriptorSetLayout (device, self->descriptor_set_layout, NULL);
      for (uint32_t i = 0; i < PIPELINE_COUNT; i++)
        vkDestroyPipeline (device, self->pipelines[i], NULL);

      for (uint32_t i = 0; i < G_N_ELEMENTS (self->shader_modules); i++)
        vkDestroyShaderModule (device, self->shader_modules[i], NULL);

      vkDestroyPipelineCache (device, self->pipeline_cache, NULL);
137 138 139

      if (self->render_pass)
        g_object_unref (self->render_pass);
140
    }
141

142 143
  g_object_unref (self->context);

144 145 146 147 148
  G_OBJECT_CLASS (xrd_scene_renderer_parent_class)->finalize (gobject);
}

static XrdSceneRenderer *singleton = NULL;

149
XrdSceneRenderer *xrd_scene_renderer_get_instance (void)
150 151
{
  if (singleton == NULL)
Lubosz Sarnecki's avatar
Lubosz Sarnecki committed
152
    singleton = (XrdSceneRenderer*) g_object_new (XRD_TYPE_SCENE_RENDERER, 0);
153 154 155 156

  return singleton;
}

157 158 159 160 161
void xrd_scene_renderer_destroy_instance (void)
{
  g_clear_object (&singleton);
}

162
static gboolean
163
_init_framebuffers (XrdSceneRenderer *self)
164
{
165 166 167 168 169 170 171 172 173 174
  VkExtent2D extent;
  gxr_context_get_render_dimensions (self->context, &extent);

  extent.width = (uint32_t) (self->render_scale * (float) extent.width);
  extent.height = (uint32_t) (self->render_scale * (float) extent.height);

  gulkan_renderer_set_extent (GULKAN_RENDERER (self), extent);

  if (!gxr_context_init_framebuffers (self->context, extent, self->sample_count,
                                      self->framebuffer, &self->render_pass))
175
    return FALSE;
176

177
  return TRUE;
178 179
}

180
static gboolean
181 182 183
_init_shaders (XrdSceneRenderer *self)
{
  const char *shader_names[PIPELINE_COUNT] = {
184
    "window", "window", "pointer", "pointer", "pointer", "device_model"
185 186 187 188 189 190 191 192 193
  };
  const char *stage_names[2] = {"vert", "frag"};

  for (int32_t i = 0; i < PIPELINE_COUNT; i++)
    for (int32_t j = 0; j < 2; j++)
      {
        char path[1024];
        sprintf (path, "/shaders/%s.%s.spv", shader_names[i], stage_names[j]);

194 195 196
        if (!gulkan_renderer_create_shader_module (GULKAN_RENDERER (self),
                                                   path,
                                                  &self->shader_modules[i * 2 + j]))
197
          return FALSE;
198
      }
199
  return TRUE;
200 201 202
}

/* Create a descriptor set layout compatible with all shaders. */
203
static gboolean
204 205 206 207
_init_descriptor_layout (XrdSceneRenderer *self)
{
  VkDescriptorSetLayoutCreateInfo info = {
    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
208
    .bindingCount = 4,
209
    .pBindings = (VkDescriptorSetLayoutBinding[]) {
210
      // mvp buffer
211 212 213 214
      {
        .binding = 0,
        .descriptorCount = 1,
        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
215
        .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
216
      },
217
      // Window and device texture
218 219 220 221 222
      {
        .binding = 1,
        .descriptorCount = 1,
        .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
223
      },
224
      // Window buffer
225 226 227 228 229 230
      {
        .binding = 2,
        .descriptorCount = 1,
        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
      },
231 232 233 234 235 236 237
      // Lights buffer
      {
        .binding = 3,
        .descriptorCount = 1,
        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
      },
238 239 240
    }
  };

241 242
  GulkanClient *gc = gxr_context_get_gulkan (self->context);
  VkDevice device = gulkan_client_get_device_handle (gc);
243
  VkResult res = vkCreateDescriptorSetLayout (device,
244 245
                                             &info, NULL,
                                             &self->descriptor_set_layout);
246
  vk_check_error ("vkCreateDescriptorSetLayout", res, FALSE);
247

248
  return TRUE;
249 250
}

251
static gboolean
252 253 254 255 256 257 258 259 260 261
_init_pipeline_layout (XrdSceneRenderer *self)
{
  VkPipelineLayoutCreateInfo info = {
    .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
    .setLayoutCount = 1,
    .pSetLayouts = &self->descriptor_set_layout,
    .pushConstantRangeCount = 0,
    .pPushConstantRanges = NULL
  };

262 263 264
  GulkanClient *gc = gxr_context_get_gulkan (self->context);

  VkResult res = vkCreatePipelineLayout (gulkan_client_get_device_handle (gc),
265
                                        &info, NULL, &self->pipeline_layout);
266
  vk_check_error ("vkCreatePipelineLayout", res, FALSE);
267

268
  return TRUE;
269 270
}

271
static gboolean
272 273 274 275 276
_init_pipeline_cache (XrdSceneRenderer *self)
{
  VkPipelineCacheCreateInfo info = {
    .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO
  };
277 278 279 280

  GulkanClient *gc = gxr_context_get_gulkan (self->context);

  VkResult res = vkCreatePipelineCache (gulkan_client_get_device_handle (gc),
281
                                       &info, NULL, &self->pipeline_cache);
282
  vk_check_error ("vkCreatePipelineCache", res, FALSE);
283

284
  return TRUE;
285 286
}

287
typedef struct __attribute__((__packed__)) {
288 289 290 291 292 293 294
  VkPrimitiveTopology                           topology;
  uint32_t                                      stride;
  const VkVertexInputAttributeDescription      *attribs;
  uint32_t                                      attrib_count;
  const VkPipelineDepthStencilStateCreateInfo  *depth_stencil_state;
  const VkPipelineColorBlendAttachmentState    *blend_attachments;
  const VkPipelineRasterizationStateCreateInfo *rasterization_state;
295
} XrdPipelineConfig;
296

297
static gboolean
298
_init_graphics_pipelines (XrdSceneRenderer *self)
299
{
300
  XrdPipelineConfig config[PIPELINE_COUNT] = {
301 302 303
    // PIPELINE_WINDOWS
    {
      .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
304
      .stride = sizeof (XrdSceneVertex),
305 306
      .attribs = (VkVertexInputAttributeDescription []) {
        {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
307
        {1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof (XrdSceneVertex, uv)},
308
      },
309 310 311 312 313
      .attrib_count = 2,
      .depth_stencil_state = &(VkPipelineDepthStencilStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
          .depthTestEnable = VK_TRUE,
          .depthWriteEnable = VK_TRUE,
314
          .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL
315 316 317 318
      },
      .blend_attachments = &(VkPipelineColorBlendAttachmentState) {
        .blendEnable = VK_FALSE,
        .colorWriteMask = 0xf
319 320 321 322 323 324 325
      },
      .rasterization_state = &(VkPipelineRasterizationStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
          .polygonMode = VK_POLYGON_MODE_FILL,
          .cullMode = VK_CULL_MODE_BACK_BIT,
          .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
          .lineWidth = 1.0f
326 327 328 329 330
      }
    },
    // PIPELINE_TIP
    {
      .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
331
      .stride = sizeof (XrdSceneVertex),
332 333
      .attribs = (VkVertexInputAttributeDescription []) {
        {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
334
        {1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof (XrdSceneVertex, uv)},
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
      },
      .attrib_count = 2,
      .depth_stencil_state = &(VkPipelineDepthStencilStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
          .depthTestEnable = VK_FALSE,
          .depthWriteEnable = VK_FALSE
      },
      .blend_attachments = &(VkPipelineColorBlendAttachmentState) {
        .blendEnable = VK_TRUE,
        .colorBlendOp = VK_BLEND_OP_ADD,
        .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
        .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
        .alphaBlendOp = VK_BLEND_OP_ADD,
        .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
        .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
        .colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
                          VK_COLOR_COMPONENT_G_BIT |
                          VK_COLOR_COMPONENT_B_BIT,
353 354 355 356 357 358
      },
      .rasterization_state = &(VkPipelineRasterizationStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
          .polygonMode = VK_POLYGON_MODE_FILL,
          .cullMode = VK_CULL_MODE_BACK_BIT,
          .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE
359
      }
360 361 362 363 364 365 366 367 368
    },
    // PIPELINE_POINTER
    {
      .topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
      .stride = sizeof (float) * 6,
      .attribs = (VkVertexInputAttributeDescription []) {
        {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
        {1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof (float) * 3},
      },
369 370
      .depth_stencil_state = &(VkPipelineDepthStencilStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
371 372 373
          .depthTestEnable = VK_TRUE,
          .depthWriteEnable = VK_TRUE,
          .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL
374 375 376 377 378
      },
      .attrib_count = 2,
      .blend_attachments = &(VkPipelineColorBlendAttachmentState) {
        .blendEnable = VK_FALSE,
        .colorWriteMask = 0xf
379 380 381 382 383
      },
      .rasterization_state = &(VkPipelineRasterizationStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
          .polygonMode = VK_POLYGON_MODE_LINE,
          .cullMode = VK_CULL_MODE_BACK_BIT,
384 385 386 387 388 389 390 391 392 393 394 395 396
          .lineWidth = 4.0f
      }
    },
    // PIPELINE_SELECTION
    {
      .topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
      .stride = sizeof (float) * 6,
      .attribs = (VkVertexInputAttributeDescription []) {
        {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
        {1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof (float) * 3},
      },
      .depth_stencil_state = &(VkPipelineDepthStencilStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
397 398 399
          .depthTestEnable = VK_TRUE,
          .depthWriteEnable = VK_TRUE,
          .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
      },
      .attrib_count = 2,
      .blend_attachments = &(VkPipelineColorBlendAttachmentState) {
        .blendEnable = VK_FALSE,
        .colorWriteMask = 0xf
      },
      .rasterization_state = &(VkPipelineRasterizationStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
          .polygonMode = VK_POLYGON_MODE_LINE,
          .lineWidth = 2.0f
      }
    },
    // PIPELINE_BACKGROUND
    {
      .topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
      .stride = sizeof (float) * 6,
      .attribs = (VkVertexInputAttributeDescription []) {
        {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
        {1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof (float) * 3},
      },
      .depth_stencil_state = &(VkPipelineDepthStencilStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
422 423 424
          .depthTestEnable = VK_TRUE,
          .depthWriteEnable = VK_TRUE,
          .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL
425 426 427 428 429 430 431 432 433 434
      },
      .attrib_count = 2,
      .blend_attachments = &(VkPipelineColorBlendAttachmentState) {
        .blendEnable = VK_FALSE,
        .colorWriteMask = 0xf
      },
      .rasterization_state = &(VkPipelineRasterizationStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
          .polygonMode = VK_POLYGON_MODE_LINE,
          .lineWidth = 1.0f
435
      }
436 437 438 439
    },
    // PIPELINE_DEVICE_MODELS
    {
      .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
440
      .stride = gxr_context_get_model_vertex_stride (self->context),
441 442
      .attribs = (VkVertexInputAttributeDescription []) {
        {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0},
443
        {1, 0, VK_FORMAT_R32G32B32_SFLOAT,
444
          gxr_context_get_model_normal_offset (self->context)},
445
        {2, 0, VK_FORMAT_R32G32_SFLOAT,
446
          gxr_context_get_model_uv_offset (self->context)},
447
      },
448 449
      .depth_stencil_state = &(VkPipelineDepthStencilStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
450 451 452
          .depthTestEnable = VK_TRUE,
          .depthWriteEnable = VK_TRUE,
          .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL
453 454 455 456 457
      },
      .attrib_count = 3,
      .blend_attachments = &(VkPipelineColorBlendAttachmentState) {
        .blendEnable = VK_FALSE,
        .colorWriteMask = 0xf
458 459 460 461 462 463
      },
      .rasterization_state = &(VkPipelineRasterizationStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
          .polygonMode = VK_POLYGON_MODE_FILL,
          .cullMode = VK_CULL_MODE_BACK_BIT,
          .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE
464
      }
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    }
  };

  for (uint32_t i = 0; i < PIPELINE_COUNT; i++)
    {
      VkGraphicsPipelineCreateInfo pipeline_info = {
        .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
        .layout = self->pipeline_layout,
        .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
          .pVertexAttributeDescriptions = config[i].attribs,
          .vertexBindingDescriptionCount = 1,
          .pVertexBindingDescriptions = &(VkVertexInputBindingDescription) {
            .binding = 0,
            .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
            .stride = config[i].stride
          },
          .vertexAttributeDescriptionCount = config[i].attrib_count
        },
        .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
        .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
          .topology = config[i].topology,
          .primitiveRestartEnable = VK_FALSE
        },
        .pViewportState = &(VkPipelineViewportStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
          .viewportCount = 1,
          .scissorCount = 1
        },
494
        .pRasterizationState = config[i].rasterization_state,
495 496
        .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
497
          .rasterizationSamples = self->sample_count,
498 499 500 501
          .minSampleShading = 0.0f,
          .pSampleMask = &(uint32_t) { 0xFFFFFFFF },
          .alphaToCoverageEnable = VK_FALSE
        },
502
        .pDepthStencilState = config[i].depth_stencil_state,
503 504 505 506 507
        .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
          .logicOpEnable = VK_FALSE,
          .attachmentCount = 1,
          .blendConstants = {0,0,0,0},
508
          .pAttachments = config[i].blend_attachments,
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
        },
        .stageCount = 2,
        .pStages = (VkPipelineShaderStageCreateInfo []) {
          {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
            .stage = VK_SHADER_STAGE_VERTEX_BIT,
            .module = self->shader_modules[i * 2],
            .pName = "main"
          },
          {
            .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
            .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
            .module = self->shader_modules[i * 2 + 1],
            .pName = "main"
          }
        },
525
        .renderPass = gulkan_render_pass_get_handle (self->render_pass),
526 527 528 529 530 531 532 533 534 535 536
        .pDynamicState = &(VkPipelineDynamicStateCreateInfo) {
          .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
          .dynamicStateCount = 2,
          .pDynamicStates = (VkDynamicState[]) {
            VK_DYNAMIC_STATE_VIEWPORT,
            VK_DYNAMIC_STATE_SCISSOR,
          }
        },
        .subpass = VK_NULL_HANDLE
      };

537 538 539
      GulkanClient *gc = gxr_context_get_gulkan (self->context);

      VkDevice device = gulkan_client_get_device_handle (gc);
540 541 542 543
      VkResult res;
      res = vkCreateGraphicsPipelines (device, self->pipeline_cache, 1,
                                      &pipeline_info, NULL,
                                      &self->pipelines[i]);
544
      vk_check_error ("vkCreateGraphicsPipelines", res, FALSE);
545 546
    }

547
  return TRUE;
548 549
}

550
gboolean
551 552
xrd_scene_renderer_init_vulkan (XrdSceneRenderer *self,
                                GxrContext       *context)
553
{
554 555 556 557 558 559 560 561 562
  if (self->context)
    {
      g_warning ("Scene Renderer: Vulkan already initialized.\n");
      g_object_unref (self->context);
    }

  self->context = context;
  g_object_ref (self->context);

563 564 565
  gulkan_renderer_set_client (GULKAN_RENDERER (self),
                              gxr_context_get_gulkan (context));

566
  if (gxr_context_get_api (context) == GXR_API_OPENVR)
567
    self->sample_count = VK_SAMPLE_COUNT_4_BIT;
568
  else
569
    self->sample_count = VK_SAMPLE_COUNT_1_BIT;
570

571
  if (!_init_framebuffers (self))
572
    return FALSE;
573 574

  if (!_init_shaders (self))
575
    return FALSE;
576

577 578 579

  GulkanClient *gc = gxr_context_get_gulkan (context);
  GulkanDevice *device = gulkan_client_get_device (gc);
580 581 582 583 584

  self->lights_buffer =
    gulkan_uniform_buffer_new (device, sizeof (XrdSceneLights));

  if (!self->lights_buffer)
585
    return FALSE;
586

587
  if (!_init_descriptor_layout (self))
588
    return FALSE;
589
  if (!_init_pipeline_layout (self))
590
    return FALSE;
591
  if (!_init_pipeline_cache (self))
592
    return FALSE;
593
  if (!_init_graphics_pipelines (self))
594
    return FALSE;
595

596
  return TRUE;
597 598 599 600 601 602 603 604
}

VkDescriptorSetLayout *
xrd_scene_renderer_get_descriptor_set_layout (XrdSceneRenderer *self)
{
  return &self->descriptor_set_layout;
}

Lubosz Sarnecki's avatar
Lubosz Sarnecki committed
605
static void
606 607
_render_stereo (XrdSceneRenderer *self, VkCommandBuffer cmd_buffer)
{
608 609
  VkExtent2D extent = gulkan_renderer_get_extent (GULKAN_RENDERER (self));

610 611
  VkViewport viewport = {
    0.0f, 0.0f,
612
    extent.width, extent.height,
613 614 615 616 617
    0.0f, 1.0f
  };
  vkCmdSetViewport (cmd_buffer, 0, 1, &viewport);
  VkRect2D scissor = {
    .offset = {0, 0},
618
    .extent = extent
619 620 621
  };
  vkCmdSetScissor (cmd_buffer, 0, 1, &scissor);

622 623 624 625
  VkClearColorValue black = {
    .float32 = { 0.0f, 0.0f, 0.0f, 1.0f },
  };

626 627
  for (uint32_t eye = 0; eye < 2; eye++)
    {
628 629
      gulkan_render_pass_begin (self->render_pass, extent, black,
                                self->framebuffer[eye], cmd_buffer);
630

631 632
      if (self->render_eye)
        self->render_eye (eye, cmd_buffer, self->pipeline_layout,
633
                          self->pipelines, self->scene_client);
634 635 636 637 638

      vkCmdEndRenderPass (cmd_buffer);
    }
}

639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
void
xrd_scene_renderer_update_lights (XrdSceneRenderer  *self,
                                  GList             *controllers)
{
  self->lights.active_lights = (int) g_list_length (controllers);
  if (self->lights.active_lights > 2)
    {
      g_warning ("Update lights received more than 2 controllers.\n");
      self->lights.active_lights = 2;
    }

  for (int i = 0; i < self->lights.active_lights; i++)
    {
      GList *l = g_list_nth (controllers, (guint) i);
      XrdController *controller = XRD_CONTROLLER (l->data);

      XrdScenePointerTip *scene_tip =
        XRD_SCENE_POINTER_TIP (xrd_controller_get_pointer_tip (controller));

      graphene_point3d_t tip_position;
      xrd_scene_object_get_position (XRD_SCENE_OBJECT (scene_tip), &tip_position);

      self->lights.lights[i].position[0] = tip_position.x;
      self->lights.lights[i].position[1] = tip_position.y;
      self->lights.lights[i].position[2] = tip_position.z;
    }

666 667
  gulkan_uniform_buffer_update (self->lights_buffer,
                                (gpointer) &self->lights);
668 669
}

670 671
static void
_draw (XrdSceneRenderer *self)
672
{
673
  GulkanClient *gc = gxr_context_get_gulkan (self->context);
674 675 676
  GulkanDevice *device = gulkan_client_get_device (gc);

  GulkanQueue *queue = gulkan_device_get_graphics_queue (device);
677

678
  GulkanCmdBuffer *cmd_buffer = gulkan_queue_request_cmd_buffer (queue);
679
  gulkan_cmd_buffer_begin (cmd_buffer);
680

681 682
  self->update_lights (self->scene_client);

683 684 685
  VkCommandBuffer cmd_handle = gulkan_cmd_buffer_get_handle (cmd_buffer);

  _render_stereo (self, cmd_handle);
686

687
  gulkan_queue_submit (queue, cmd_buffer);
688

689
  gulkan_queue_free_cmd_buffer (queue, cmd_buffer);
690
}
691

692
gboolean
693
xrd_scene_renderer_draw (XrdSceneRenderer *self)
694 695
{
  _draw (self);
696

697
  VkExtent2D extent = gulkan_renderer_get_extent (GULKAN_RENDERER (self));
698

699 700
  if (!gxr_context_submit_framebuffers (self->context, self->framebuffer,
                                        extent, self->sample_count))
701
    return FALSE;
702

703
  return TRUE;
704
}
705 706 707 708 709 710 711 712

void
xrd_scene_renderer_set_render_cb (XrdSceneRenderer *self,
                                  void (*render_eye) (uint32_t         eye,
                                                      VkCommandBuffer  cmd_buffer,
                                                      VkPipelineLayout pipeline_layout,
                                                      VkPipeline      *pipelines,
                                                      gpointer         data),
713
                                  gpointer scene_client)
714 715
{
  self->render_eye = render_eye;
716 717 718 719 720 721 722 723 724 725
  self->scene_client = scene_client;
}

void
xrd_scene_renderer_set_update_lights_cb (XrdSceneRenderer *self,
                                         void (*update_lights) (gpointer data),
                                         gpointer scene_client)
{
  self->update_lights = update_lights;
  self->scene_client = scene_client;
726
}
727

728 729 730 731 732
VkBuffer
xrd_scene_renderer_get_lights_buffer_handle (XrdSceneRenderer *self)
{
  return gulkan_uniform_buffer_get_handle (self->lights_buffer);
}
733 734 735 736 737 738

GulkanClient *
xrd_scene_renderer_get_gulkan (XrdSceneRenderer *self)
{
  return gxr_context_get_gulkan (self->context);
}