10

[OpenGL and Vulkan Interoperability on Linux] Part 7: Reusing a Vulkan vertex bu...

 3 years ago
source link: https://eleni.mutantstargoat.com/hikiko/vk-gl-interop-7/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

[OpenGL and Vulkan Interoperability on Linux] Part 7: Reusing a Vulkan vertex buffer from OpenGL

This is the 7th post on OpenGL and Vulkan Interoperability with EXT_external_objects. It’s about another EXT_external_objects use case implemented for Piglit as part of my work for Igalia‘s graphics team. In this case a vertex buffer is allocated and filled with data from Vulkan and then it’s used from OpenGL to render a pattern on screen.

The vk-vert-buf-update-errors test is implemented in Piglit‘s tests/spec/ext_external_objects/vk_vert_buf_update_errors.c and:

  • Creates an external vertex buffer with Vulkan and fills it with vertices that could form the white quads of a chess board
  • Imports the buffer in OpenGL and uses it as the vertex array at rendering
  • Attempts to overwrite the buffer data with new geometry
  • Validates that the geometry remained unchanged and renders a red-blue chessboard using OpenGL and the vertices

chess.png


Step 1: An external Vulkan vertex buffer is created and filled with chess board quads

In piglit_init we call vk_init to initialize the Vulkan structs and there we create a Vulkan vertex buffer:

We fill it with quads that would correspond to the white quads of a chess board:

To do so we mapped the buffer’s memory and we generated the quads with gen_checkerboard_quads:

#define QUAD_SIZE (2.0 / 8.0)
#define ADD_QUAD_VERT(a, b) do {vptr->x = a; vptr->y = b; vptr++;} while(0)
static void
gen_checkerboard_quads(struct Vec2 *vptr)
int i, j;
struct Vec2 pos;
for (i = 0; i < 8; i++) {
pos.x = -1 + (i % 2) * QUAD_SIZE;
pos.y = -1 + i * QUAD_SIZE;
for (j = 0; j < 4; j++) {
ADD_QUAD_VERT(pos.x, pos.y);
ADD_QUAD_VERT(pos.x + QUAD_SIZE, pos.y);
ADD_QUAD_VERT(pos.x + QUAD_SIZE, pos.y + QUAD_SIZE);
ADD_QUAD_VERT(pos.x, pos.y);
ADD_QUAD_VERT(pos.x + QUAD_SIZE, pos.y + QUAD_SIZE);
ADD_QUAD_VERT(pos.x, pos.y + QUAD_SIZE);
pos.x += QUAD_SIZE * 2.0;

Now the vertex buffer is ready to be imported in OpenGL.


Step 2: The external Vulkan quad is imported in OpenGL

To import the vertex buffer we’ll do something similar to what we did in Part 5 to import the pixel buffer, but this time the target will be GL_ARRAY_BUFFER instead of GL_PIXEL_UNPACK_BUFFER:

After these steps the buffer is ready to be used by OpenGL. (We’ve explained gl_gen_buf_from_mem_obj in Part 5 and gl_create_mem_obj_from_vk_mem in Part 2).


Step 3: Using the external vertex buffer to draw a chessboard pattern with OpenGL

We bind the buffer as GL_ARRAY_BUFFER and we call glDrawArrays like we would call it with an OpenGL allocated vertex array:

glUseProgram(gl_prog);
/* We are going to use the Vulkan allocated vertex buffer
* in an OpenGL shader that paints the pixels blue.
* As the vertices are set to render quads following a checkerboard
* pattern (quad, no geometry, quad, no geometry) we should
* see a checkerboard pattern where the color is blue when
* we have geometry and red (framebuffer color) where there's no
* geometry.
glBindBuffer(GL_ARRAY_BUFFER, gl_vk_vb);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, WHITE_VERTS);
glBindBuffer(GL_ARRAY_BUFFER, 0);

We are using gl_prog to paint the vertices blue after we have cleared the framebuffer to red. The vertex and pixel shaders used to build gl_prog are quite minimal:

piglit_present_results shows the chess board pattern on screen.


Step 4: An attempt to overwrite the buffer should return Invalid Operation Error

Just to make sure that the reused vertex buffer cannot be overwritten by OpenGL we perform a check that calling glBufferSubData will return an error:

static float uninteresting_data[WHITE_VERTS * 2];
/* Checking that calling glBufferSubData with random vertices returns
* invalid operation error.
glBindBuffer(GL_ARRAY_BUFFER, gl_vk_vb);
glBufferSubData(GL_ARRAY_BUFFER, 0, vk_vb.mobj.mem_sz, uninteresting_data);
if (glGetError() != GL_INVALID_OPERATION) {
fprintf(stderr, "glBufferSubData should return GL_INVALID_OPERATION error!\n");
return PIGLIT_FAIL;

Then, we clear the framebuffer to red and use the same vertex data to perform another drawing:

At this point, the vertex data should be the ones written by Vulkan and piglit_present_results must display a red-blue chess board pattern.

And that’s it!

This test case was written to validate that we can create and fill a vertex buffer from Vulkan and use it to render with OpenGL. But also to see that we aren’t allowed to overwrite the external vertex buffer’s content from OpenGL!


Links:


Coming soon:

Next post will be about using an external vertex buffer to draw once from OpenGL and once from Vulkan to make sure it can be re-used several times. Stay tuned!




and see you next time!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK