Skip to content
Snippets Groups Projects
Commit 09418085 authored by Antonio Ospite's avatar Antonio Ospite
Browse files

Add a test for glDrawVkImageNV

parent a6cbaf15
No related branches found
No related tags found
No related merge requests found
# Collection of examples about how to render to OpenGL textures from Vulkan
The examples can be built with the following commands:
```
$ meson build/
$ ninja -C build/
```
## test-glDrawVkImageNV
```
./build/test-glDrawVkImageNV
```
**NOTE**: The `glDrawVkImageNV` implementation on NVIDIA proprietary drivers seems to be broken when used from EGL with the X11 backend. This workaround seems to avoid the crash:
```
env -u DISPLAY ./build/test-glDrawVkImageNV
```
project('vulkan-render-to-texture', 'cpp',
default_options : ['warning_level=3', 'cpp_std=c++11' ],
version : '0.1')
vulkan_dep = dependency('vulkan')
egl_dep = dependency('egl')
gl_dep = dependency('GL')
deps = [ vulkan_dep, egl_dep, gl_dep ]
executable('test-glDrawVkImageNV',
[
'test-glDrawVkImageNV.cpp',
'vulkan-render-to-opengl-texture-glDrawVkImageNV.cpp',
'external/Vulkan/examples/renderheadless/renderheadless.cpp',
'external/Vulkan/base/VulkanTools.cpp' ],
include_directories : [
'external/Vulkan/base',
'external/Vulkan/data',
'external/Vulkan/examples/renderheadless' ],
dependencies: deps,
install : false)
/*
* test-glDrawVkImageNV - Render to an OpenGL texture from Vulkan with glDrawVkImageNV
*
* Copyright 2021, Collabora Ltd
* Author: Antonio Ospite <antonio.ospite@collabora.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <EGL/egl.h>
#include "vulkan-render-to-opengl-texture-glDrawVkImageNV.h"
int main (void)
{
init ();
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!eglInitialize(display, NULL, NULL)) {
switch(eglGetError()){
case EGL_BAD_DISPLAY:
fprintf(stderr, "Failed to initialize EGL Display: EGL_BAD_DISPLAY\n");
break;
case EGL_NOT_INITIALIZED:
fprintf(stderr, "Failed to initialize EGL Display: EGL_NOT_INITIALIZED\n");
break;
default:
fprintf(stderr, "Failed to initialize EGL Display: unknown erro\n");
break;
}
exit (EXIT_FAILURE);
}
eglBindAPI(EGL_OPENGL_API);
EGLint configAttribs[11] = {
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_CONFORMANT, EGL_OPENGL_BIT,
EGL_NONE
};
EGLint numConfigs = 0;
EGLConfig eglConfig = nullptr;
if(!eglChooseConfig(display, configAttribs, &eglConfig, 1, &numConfigs)){
switch(eglGetError()){
case EGL_BAD_DISPLAY:
fprintf(stderr, "Failed to configure EGL Display: EGL_BAD_DISPLAY\n");
break;
case EGL_BAD_ATTRIBUTE:
fprintf(stderr, "Failed to configure EGL Display: EGL_BAD_ATTRIBUTE\n");
break;
case EGL_NOT_INITIALIZED:
fprintf(stderr, "Failed to configure EGL Display: EGL_NOT_INITIALIZED\n");
break;
case EGL_BAD_PARAMETER:
fprintf(stderr, "Failed to configure EGL Display: EGL_BAD_PARAMETER\n");
break;
default:
fprintf(stderr, "Failed to configure EGL Display: unknown error\n");
break;
}
exit (EXIT_FAILURE);
}
EGLContext context = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT, NULL);
if (context == EGL_NO_CONTEXT) {
fprintf(stderr, "Failed to initialize EGL context: EGL_NO_CONTEXT\n");
exit (EXIT_FAILURE);
}
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context);
const GLubyte* vendor = glGetString(GL_VENDOR);
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
const GLubyte* glslVer = glGetString(GL_SHADING_LANGUAGE_VERSION);
fprintf(stdout, "OpenGL Context: %s : %s (%s - GLSL: %s)\n", vendor, renderer, version, glslVer);
fprintf(stdout, "Info: Checking for required extensions:\n");
const char* NV_DRAW_VULKAN_EXT_STR = "GL_NV_draw_vulkan_image";
int numberOfExtensions;
glGetIntegerv(GL_NUM_EXTENSIONS, &numberOfExtensions);
for (int i = 0; i < numberOfExtensions; i++) {
const char * extStr = (const char*)glGetStringi(GL_EXTENSIONS, i);
if (strcmp(extStr, NV_DRAW_VULKAN_EXT_STR) == 0) {
fprintf(stdout, "Info: \t%s supported\n", NV_DRAW_VULKAN_EXT_STR);
fn_glDrawVkImageNV = (PFNGLDRAWVKIMAGENVPROC)eglGetProcAddress("glDrawVkImageNV");
fn_glWaitVkSemaphoreNV = (PFNGLWAITVKSEMAPHORENVPROC)eglGetProcAddress("glWaitVkSemaphoreNV");
fn_glSignalVkSemaphoreNV = (PFNGLSIGNALVKSEMAPHORENVPROC)eglGetProcAddress("glSignalVkSemaphoreNV");
}
}
if (fn_glDrawVkImageNV == NULL) {
fprintf(stderr, "Failed to find the %s extension!\n", NV_DRAW_VULKAN_EXT_STR);
exit(EXIT_FAILURE);
}
glEnable (GL_DEBUG_OUTPUT);
glDebugMessageCallback (debug_callback, NULL);
GLuint scene_texture;
glGenTextures (1, &scene_texture);
glBindTexture (GL_TEXTURE_2D, scene_texture);
glTexStorage2D (GL_TEXTURE_2D, 1, GL_RGB8, width, height);
glBindTexture (GL_TEXTURE_2D, 0);
uint32_t frame_count = 10;
while (frame_count-- > 0) {
glViewport (0, 0, width, height);
// Render scene into the target texture
draw_screen (scene_texture, width, height);
}
deinit ();
exit (EXIT_SUCCESS);
}
/*
* vulkan-render-to-texture-glDrawVkImageNV - Render to an OpenGL texture from Vulkan with glDrawVkImageNV
*
* Copyright 2021, Collabora Ltd
* Author: Antonio Ospite <antonio.ospite@collabora.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <stdio.h>
#include <stdlib.h>
#include "vulkan-render-to-opengl-texture-glDrawVkImageNV.h"
#include "renderheadless.h"
PFNGLDRAWVKIMAGENVPROC fn_glDrawVkImageNV;
PFNGLWAITVKSEMAPHORENVPROC fn_glWaitVkSemaphoreNV;
PFNGLSIGNALVKSEMAPHORENVPROC fn_glSignalVkSemaphoreNV;
int width = 1024;
int height = 1024;
#define SCREENSHOT_MAX_FILENAME 256
static char screenshot_filename[SCREENSHOT_MAX_FILENAME];
static GLubyte *pixels = NULL;
static const size_t format_nchannels = 3;
static unsigned int nframes = 0;
VulkanExample* vkExInstance = NULL;
VkImage vkImage = NULL;
VkSemaphore vkRenderDone = NULL;
VkSemaphore vkPresentDone = NULL;
/*
* Take screenshot with glReadPixels and save to a file in PPM format.
*
* - filename: file path to save to, without extension
* - width: screen width in pixels
* - height: screen height in pixels
* - pixels: intermediate buffer to avoid repeated mallocs across multiple calls.
*/
static void
screenshot_ppm (const char *filename, int image_width,
int image_height, size_t nchannels, GLubyte ** image_pixels)
{
int i, j;
size_t cur;
FILE *f = fopen (filename, "w");
fprintf (f, "P3\n%d %d\n%d\n", image_width, image_height, 255);
glReadPixels (0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE,
*image_pixels);
for (i = 0; i < image_height; i++) {
for (j = 0; j < image_width; j++) {
cur = nchannels * (i * image_width + j);
fprintf (f, "%3d %3d %3d ", (*image_pixels)[cur],
(*image_pixels)[cur + 1], (*image_pixels)[cur + 2]);
}
fprintf (f, "\n");
}
fclose (f);
}
void
init (void)
{
pixels = (GLubyte *)malloc(format_nchannels * sizeof (GLubyte) * width * height);
if (pixels == NULL) {
fprintf(stderr, "allocating pixels failed\n");
exit(EXIT_FAILURE);
}
vkExInstance = vulkan_example_init(width, height);
fprintf (stdout, "Info: %s\n", "init completed");
}
void
deinit (void)
{
vulkan_example_deinit(vkExInstance);
free (pixels);
}
static void
draw_scene (void)
{
auto vkData = vulkan_example_render(vkExInstance);
vkRenderDone = std::get<0>(vkData);
vkPresentDone = std::get<1>(vkData);
vkImage = std::get<2>(vkData);
}
void
draw_screen (GLuint target_texture, int width, int height)
{
//fprintf (stdout, "Info: Render start: %d\n", nframes);
draw_scene ();
/* Offscreen rendering framebuffer. */
static GLuint scene_fbo;
glGenFramebuffers (1, &scene_fbo);
glBindFramebuffer (GL_FRAMEBUFFER, scene_fbo);
glBindTexture (GL_TEXTURE_2D, target_texture);
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
target_texture, 0);
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers (1, DrawBuffers);
/* Sanity check. */
if (glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
fprintf (stderr, "glCheckFramebufferStatus() failed.");
return;
}
glClearColor(0.7f, 0.0f, 0.7f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
fn_glWaitVkSemaphoreNV((GLuint64)vkRenderDone);
//fprintf (stdout, "Info: %s\n", "GPU Copy start");
fn_glDrawVkImageNV((GLuint64)vkImage, 0.0f,
0.0f, 0.0f, width, height, // dest coords
0.0f, // z??
0.0f, 0.0f, 1.0f, 1.0f); // source s, t coords
glFlush ();
#if 1
snprintf (screenshot_filename, SCREENSHOT_MAX_FILENAME,
"frame-%05d.ppm", nframes);
screenshot_ppm (screenshot_filename, width, height, format_nchannels, &pixels);
#endif
fn_glSignalVkSemaphoreNV((GLuint64)vkPresentDone);
//fprintf (stdout, "Info: %s\n", "GPU Copy end");
nframes++;
}
void
error_callback (int error, const char *description)
{
(void) error;
fprintf (stderr, "Error: %s\n", description);
}
void GLAPIENTRY
debug_callback (GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar * message, const void *userParam)
{
(void) source;
(void) id;
(void) length;
(void) userParam;
fprintf (stderr,
"GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type, severity,
message);
}
/*
* vulkan-render-to-texture-glDrawVkImageNV - Render to an OpenGL texture from Vulkan with glDrawVkImageNV
*
* Copyright 2021, Collabora Ltd
* Author: Antonio Ospite <antonio.ospite@collabora.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef VULKAN_RENDER_TO_OPENGL_TEXTURE_H
#define VULKAN_RENDER_TO_OPENGL_TEXTURE_H
#define GL_GLEXT_PROTOTYPES 1
#include <GL/gl.h>
#include <GL/glext.h>
#ifdef __cplusplus
extern "C" {
#endif
extern PFNGLDRAWVKIMAGENVPROC fn_glDrawVkImageNV;
extern PFNGLWAITVKSEMAPHORENVPROC fn_glWaitVkSemaphoreNV;
extern PFNGLSIGNALVKSEMAPHORENVPROC fn_glSignalVkSemaphoreNV;
extern int width;
extern int height;
void init (void);
void deinit (void);
void draw_screen (GLuint target_texture, int width, int height);
void error_callback (int error, const char *description);
void GLAPIENTRY debug_callback (GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar * message, const void *userParam);
#ifdef __cplusplus
}
#endif
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment