| 614 | } |
| 615 | |
| 616 | void OpenGLInterop::render(float) |
| 617 | { |
| 618 | if (!prepared) |
| 619 | { |
| 620 | return; |
| 621 | } |
| 622 | |
| 623 | ApiVulkanSample::prepare_frame(); |
| 624 | // RENDER |
| 625 | float time = static_cast<float>(timer.elapsed()); |
| 626 | // The GL shader animates the image, so provide the time as input |
| 627 | glProgramUniform1f(gl_data->program, 1, time); |
| 628 | |
| 629 | // Wait (on the GPU side) for the Vulkan semaphore to be signaled |
| 630 | GLenum srcLayout = GL_LAYOUT_COLOR_ATTACHMENT_EXT; |
| 631 | glWaitSemaphoreEXT(gl_data->gl_ready, 0, nullptr, 1, &gl_data->color, &srcLayout); |
| 632 | |
| 633 | // Draw to the framebuffer |
| 634 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 635 | |
| 636 | // Once drawing is complete, signal the Vulkan semaphore indicating |
| 637 | // it can continue with it's render |
| 638 | GLenum dstLayout = GL_LAYOUT_SHADER_READ_ONLY_EXT; |
| 639 | glSignalSemaphoreEXT(gl_data->gl_complete, 0, nullptr, 1, &gl_data->color, &dstLayout); |
| 640 | |
| 641 | // When using synchronization across multiple GL context, or in this case |
| 642 | // across OpenGL and another API, it's critical that an operation on a |
| 643 | // synchronization object that will be waited on in another context or API |
| 644 | // is flushed to the GL server. |
| 645 | // |
| 646 | // Failure to flush the operation can cause the GL driver to sit and wait for |
| 647 | // sufficient additional commands in the buffer before it flushes automatically |
| 648 | // but depending on how the waits and signals are structured, this may never |
| 649 | // occur. |
| 650 | glFlush(); |
| 651 | // RENDER |
| 652 | |
| 653 | std::array<VkPipelineStageFlags, 2> waitStages{{VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT}}; |
| 654 | std::array<VkSemaphore, 2> waitSemaphores{{semaphores.acquired_image_ready, sharedSemaphores.gl_complete}}; |
| 655 | |
| 656 | std::array<VkSemaphore, 2> signalSemaphores{{semaphores.render_complete, sharedSemaphores.gl_ready}}; |
| 657 | // Command buffer to be submitted to the queue |
| 658 | submit_info.waitSemaphoreCount = vkb::to_u32(waitSemaphores.size()); |
| 659 | submit_info.pWaitSemaphores = waitSemaphores.data(); |
| 660 | submit_info.pWaitDstStageMask = waitStages.data(); |
| 661 | submit_info.signalSemaphoreCount = vkb::to_u32(signalSemaphores.size()); |
| 662 | submit_info.pSignalSemaphores = signalSemaphores.data(); |
| 663 | submit_info.commandBufferCount = 1; |
| 664 | submit_info.pCommandBuffers = &draw_cmd_buffers[current_buffer]; |
| 665 | |
| 666 | // Submit to queue |
| 667 | VK_CHECK(vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE)); |
| 668 | |
| 669 | ApiVulkanSample::submit_frame(); |
| 670 | } |
| 671 | |
| 672 | void OpenGLInterop::view_changed() |
| 673 | { |