tonarino / just-gl

Run an OpenGL application on Linux, and nothing more.
1 stars 0 forks source link

Find a working GBM + GL program (in any language) #11

Open mbernat opened 11 months ago

mbernat commented 11 months ago

I'm struggling a bit with the GL setup. I think it's a bit too much work to figure all these pieces from the first principles, certainly for me, so I decided to get some C program working first and then port it to Rust.

I found this [1] which looks promising but fails in encoder initialization. I also tried kmscube [2] but that fails when adding a framebuffer with "Invalid argument".

It would be great if anyone could get either one of these or any other similar program running, so we have some real example to learn from.

[1] https://github.com/eyelash/tutorials/blob/master/drm-gbm.c [2] https://gitlab.freedesktop.org/mesa/kmscube/

PabloMansanet commented 11 months ago

Hey, thanks for finding these! I'm trying to run them too.

Where does the first one fail for you exactly? This is my ltrace log when calling it (getting a segfault in gbm_surface_lock_front_buffer)

open("/dev/dri/card0", 524290, 030265524410)     = 3
drmModeGetResources(3, 0x56359b67003d, 0, 0x7fee54403bf2) = 0x56359c1469a0
drmModeGetConnector(3, 308, 308, 1)              = 0x56359c146c00
printf("resolution: %ix%i\n", 1920, 1080)        = 22
drmModeGetEncoder(3, 307, 307, 0)                = 0x56359c147dd0
drmModeGetCrtc(3, 98, 98, 32)                    = 0x56359c147df0
drmModeFreeEncoder(0x56359c147dd0, 0, 0, 0)      = 0
drmModeFreeConnector(0x56359c146c00, 0x56359c147dc0, 0x5630ff4daaa7, 4) = 4
drmModeFreeResources(0x56359c1469a0, 0x56359c146bf0, 0x5630ff4da806, 2) = 4
gbm_create_device(3, 0x56359c146990, 0x5630ff4dab06, 4) = 0x56359c147f80
eglGetDisplay(0x56359c147f80, 0x7fee54585013, 0, 0x7fee54589b50) = 0x56359c26ac20
eglInitialize(0x56359c26ac20, 0, 0, 0)           = 1
eglBindAPI(0x30a2, 0, 0, 0)                      = 1
eglChooseConfig(0x56359c26ac20, 0x7fffc2d6a790, 0x7fffc2d6a788, 1) = 1
eglCreateContext(0x56359c26ac20, 0x56359c26a9c0, 0, 0) = 0x56359c273ad0
gbm_surface_create(0x56359c147f80, 1920, 1080, 0) = 0x56359c2803d0
eglCreateWindowSurface(0x56359c26ac20, 0x56359c26a9c0, 0x56359c2803d0, 0) = 0
eglMakeCurrent(0x56359c26ac20, 0, 0, 0x56359c273ad0) = 1
glClearColor(0x56359c26ac30, 0, 1, 0)            = 0x7fee445b4010
glClear(0x4000, 0, 1, 0)                         = 0
eglSwapBuffers(0x56359c26ac20, 0, 0, 65)         = 0
gbm_surface_lock_front_buffer(0x56359c2803d0, 0, 1, 0 <no return ...>
--- SIGSEGV (Segmentation fault) ---
PabloMansanet commented 11 months ago

Looking at the trace above, the first "obvious" failure I can spot is eglCreateWindowSurface returning a null pointer; everything after that is probably nonsensical.

mbernat commented 11 months ago

For me it fails with "no encoders found", which I've never seen before. I'll see if I can get it to work. But in the meantime I've tried three other programs and all fail at different points, either at FB creation or GBM surface creation.

But you got pretty far in the execution, so I guess this approach is more or less correct and might be worth porting.

PabloMansanet commented 11 months ago

For me it fails with "no encoders found", which I've never seen before. I'll see if I can get it to work. But in the meantime I've tried three other programs and all fail at different points, either at FB creation or GBM surface creation.

But you got pretty far in the execution, so I guess this approach is more or less correct and might be worth porting.

Hmmm... I got pretty far in the literal sense but I wouldn't trust that snippet too much; it does no error checking whatsoever and seems to happily pass null/invalid pointers along. The issues may come from earlier than we think. But yeah, it's good to sanity check against :).

mbernat commented 11 months ago

Yeah, I don't really trust it either, it's just for inspiration :)

Meanwhile, I got the encoders to work, they do not process them correctly and here's what I've got.

open("/dev/dri/card1", 524290, 06207617510)                                                                          = 3
drmModeGetResources(3, 0x561118f4e03d, 0, 0x7feaa4ccfbf2)                                                            = 0x561119e1c960
drmModeGetConnector(3, 88, 88, 3)                                                                                    = 0x561119e1cac0
drmModeFreeConnector(0x561119e1cac0, 0x561119e1ca90, 0x561119e1cac0, 4)                                              = 4
drmModeGetConnector(3, 91, 91, 1)                                                                                    = 0x561119e1cc60
drmModeFreeConnector(0x561119e1cc60, 0x561119e1cc30, 0x561119e1cc60, 6)                                              = 4
drmModeGetConnector(3, 95, 95, 2)                                                                                    = 0x561119e1ce00
drmModeFreeConnector(0x561119e1ce00, 0x561119e1cdd0, 0x561119e1ce00, 0)                                              = 4
drmModeGetConnector(3, 98, 98, 3)                                                                                    = 0x561119e1cfd0
printf("resolution: %ix%i\n", 1920, 1080resolution: 1920x1080
)                                                                            = 22
drmModeGetEncoder(3, 97, 97, 0)                                                                                      = 0x561119e1cee0
drmModeFreeEncoder(0x561119e1cee0, 0, 0, 32)                                                                         = 2
drmModeFreeConnector(0x561119e1cfd0, 0x561119e1ced0, 2, 0)                                                           = 4
drmModeFreeResources(0x561119e1c960, 0x561119e1cfc0, 0x561478f0501c, 4)                                              = 4
gbm_create_device(3, 0x561119e1c950, 0x561478f051cc, 5)                                                              = 0x561119e1e990
eglGetDisplay(0x561119e1e990, 0x561119e1cf70, 0, 0)                                                                  = 0x561119e1cf80
eglInitialize(0x561119e1cf80, 0, 0, 0)                                                                               = 1
eglBindAPI(0x30a2, 0, 1, 0)                                                                                          = 1
eglChooseConfig(0x561119e1cf80, 0x7ffc321f1dd0, 0x7ffc321f1dc8, 1)                                                   = 1
eglCreateContext(0x561119e1cf80, 0xcaf348, 0, 0)                                                                     = 0x561119ec3951
gbm_surface_create(0x561119e1e990, 1920, 1080, 0)                                                                    = 0
eglCreateWindowSurface(0x561119e1cf80, 0xcaf348, 0, 0 <no return ...>
--- SIGSEGV (Segmentation fault) ---

It looks like gbm_surface_create succeeded, which is interisting because it failed for me when I used it from just-gl. I wonder what the difference is.

PabloMansanet commented 11 months ago

It looks like gbm_surface_create succeeded, which is interisting because it failed for me when I used it from just-gl. I wonder what the difference is.

Hmm I don't think it did, unless I'm misreading. In your last trace gbm_surface_create is returning a null pointer (which probably explains the segfault when using it right after).

mbernat commented 11 months ago

Yeah, you're right. So it's the same as in my Rust code.

I wonder how well GBM surfaces are supported. Glutin is using them in the GBM backend but some other apps just use framebuffers directly and don't bother with these surfaces at all.

PabloMansanet commented 11 months ago

Yeah, no idea. Also pretty puzzling why gbm_surface_create worked for me but eglCreateWindowSurface failed immediately after 🤔.

I'll look for more well behaved examples...

PabloMansanet commented 11 months ago

(By the way, KMSCube fails for me with the same error that you get. Interestingly using ltrace causes a different core dump, which makes me think there's some UB involved if ltrace causes it to behave that differently).

mbernat commented 11 months ago

In your case eglCreateWindowSurface didn't fail, you got all the way to gbm_surface_lock_front_buffer. Or did you mean something else?

I haven't read the kmscube code yet but maybe it's using a slightly different approach, so the dump being different could be fine. Not saying there's no UB tho :)

PabloMansanet commented 11 months ago

In your case eglCreateWindowSurface didn't fail, you got all the way to gbm_surface_lock_front_buffer. Or did you mean something else?

I think we're using different definitions of failure 😄

eglCreateWindowSurface didn't crash, but it returned a null pointer, which according to the docs means it failed:

If eglCreatePlatformWindowSurface fails to create a window surface, EGL_NO_SURFACE is returned.

The program carries on passing the null pointer to things that expect a surface pointer, so basically anything else in the trace after that point is undefined behaviour.

mbernat commented 11 months ago

I see, same as in my case before. I need to start reading these traces more carefully :)

I just tried ltrace on kmscube and this time gbm_surface_create succeeded, to my surprise. So those surfaces are hopefully fine, you just need to initialize everything correctly.

I think kmscube is our best bet going forward, it looks more or less polished. The other programs I've seen are toy examples that cut too many corners.

PabloMansanet commented 11 months ago

Agreed, I'll take a deeper dive at the kmscube source later. Would be good to hear what the rest of the team gets when running it on their setups :) (cc @strohel @bschwind)

strohel commented 11 months ago

Let me try kmscube on the desktop machine we have here at Prague office later today.

mbernat commented 11 months ago

So, turns out nvidia simply does not implement gbm_surface_create but luckily there is also gbm_surface_create_with_modifiers that it does implement and passing that surface to glutin seems to work (or at least not crash).

I'm not really sure how to use that glutin object to do something useful but that's for another issue.

mbernat commented 11 months ago

I couldn't get any program working with the nvidia driver but turns out things run with nouveau. They don't run great, but they launch and usually also draw something. Unfortunately, nouveau doesn't allow modesetting while Xorg is running but maybe that can be disabled. And I can survive in a tty for a bit too.

So this partially resolves the issue but I'm really sad how each app breaks differently on every combination of HW + driver :(

PabloMansanet commented 11 months ago

I couldn't get any program working with the nvidia driver but turns out things run with nouveau. They don't run great, but they launch and usually also draw something. Unfortunately, nouveau doesn't allow modesetting while Xorg is running but maybe that can be disabled. And I can survive in a tty for a bit too.

So this partially resolves the issue but I'm really sad how each app breaks differently on every combination of HW + driver :(

Oh damn, nouveau doesn't give me much confidence 😄 I don't think I've ever dealt with nouveau in a context that didn't boil down to "disable nouveau"

mbernat commented 11 months ago

True but for the moment I'm happy that at least something kind of works :smile:

strohel commented 11 months ago

Let me try kmscube on the desktop machine we have here at Prague office later today.

Okay I tried remotely, though I was not present to see if that draws anything on the screen :see_no_evil:.

I'm using git master of https://gitlab.freedesktop.org/mesa/kmscube/

When running for the first time, it may have worked. It printed this:

[tonari@pragueripper-1 build]$ ./kmscube
Using display 0x56307d9cef10 with EGL version 1.5
===================================
EGL information:
  version: "1.5"
  vendor: "NVIDIA"
  client extensions: "EGL_EXT_platform_base EGL_EXT_device_base EGL_EXT_device_enumeration EGL_EXT_device_query EGL_KHR_client_get_all_proc_addresses EGL_EXT_client_extensions EGL_KHR_debug EGL_KHR_platform_x11 EGL_EXT_platform_x11 EGL_EXT_platform_device EGL_MESA_platform_surfaceless EGL_EXT_explicit_device EGL_KHR_platform_wayland EGL_EXT_platform_wayland EGL_KHR_platform_gbm EGL_MESA_platform_gbm EGL_EXT_platform_xcb"
  display extensions: "EGL_EXT_buffer_age EGL_EXT_client_sync EGL_EXT_create_context_robustness EGL_EXT_image_dma_buf_import EGL_EXT_image_dma_buf_import_modifiers EGL_MESA_image_dma_buf_export EGL_EXT_output_base EGL_EXT_output_drm EGL_EXT_protected_content EGL_EXT_stream_consumer_egloutput EGL_EXT_stream_acquire_mode EGL_EXT_sync_reuse EGL_IMG_context_priority EGL_KHR_config_attribs EGL_KHR_create_context_no_error EGL_KHR_context_flush_control EGL_KHR_create_context EGL_KHR_fence_sync EGL_KHR_get_all_proc_addresses EGL_KHR_partial_update EGL_KHR_swap_buffers_with_damage EGL_KHR_no_config_context EGL_KHR_gl_colorspace EGL_KHR_gl_renderbuffer_image EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_3D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_image EGL_KHR_image_base EGL_KHR_reusable_sync EGL_KHR_stream EGL_KHR_stream_attrib EGL_KHR_stream_consumer_gltexture EGL_KHR_stream_cross_process_fd EGL_KHR_stream_fifo EGL_KHR_stream_producer_eglsurface EGL_KHR_surfaceless_context EGL_KHR_wait_sync EGL_NV_nvrm_fence_sync EGL_NV_quadruple_buffer EGL_NV_stream_consumer_eglimage EGL_NV_stream_cross_display EGL_NV_stream_cross_object EGL_NV_stream_cross_process EGL_NV_stream_cross_system EGL_NV_stream_dma EGL_NV_stream_flush EGL_NV_stream_metadata EGL_NV_stream_remote EGL_NV_stream_reset EGL_NV_stream_socket EGL_NV_stream_socket_inet EGL_NV_stream_socket_unix EGL_NV_stream_sync EGL_NV_stream_fifo_next EGL_NV_stream_fifo_synchronous EGL_NV_stream_consumer_gltexture_yuv EGL_NV_stream_attrib EGL_NV_stream_origin EGL_NV_system_time EGL_NV_output_drm_flip_event EGL_NV_triple_buffer EGL_NV_robustness_video_memory_purge EGL_EXT_present_opaque EGL_WL_bind_wayland_display EGL_WL_wayland_eglstream"
===================================
OpenGL ES 2.x information:
  version: "OpenGL ES 3.2 NVIDIA 530.41.03"
  shading language version: "OpenGL ES GLSL ES 3.20"
  vendor: "NVIDIA Corporation"
  renderer: "NVIDIA GeForce RTX 3060/PCIe/SSE2"
  extensions: "GL_EXT_base_instance GL_EXT_blend_func_extended GL_EXT_blend_minmax GL_EXT_buffer_storage GL_EXT_clear_texture GL_EXT_clip_control GL_EXT_clip_cull_distance GL_EXT_color_buffer_float GL_EXT_color_buffer_half_float GL_EXT_conservative_depth GL_EXT_copy_image GL_EXT_depth_clamp GL_EXT_debug_label GL_EXT_discard_framebuffer GL_EXT_disjoint_timer_query GL_EXT_draw_buffers_indexed GL_EXT_draw_elements_base_vertex GL_EXT_EGL_image_array GL_EXT_EGL_image_storage GL_EXT_EGL_image_external_wrap_modes GL_EXT_float_blend GL_EXT_frag_depth GL_EXT_geometry_point_size GL_EXT_geometry_shader GL_EXT_gpu_shader5 GL_EXT_map_buffer_range GL_EXT_multi_draw_indirect GL_EXT_multisample_compatibility GL_EXT_multisampled_render_to_texture GL_EXT_multisampled_render_to_texture2 GL_EXT_multiview_texture_multisample GL_EXT_multiview_timer_query GL_EXT_occlusion_query_boolean GL_EXT_polygon_offset_clamp GL_EXT_post_depth_coverage GL_EXT_primitive_bounding_box GL_EXT_raster_multisample GL_EXT_render_snorm GL_EXT_robustness GL_EXT_separate_shader_objects GL_EXT_shader_group_vote GL_EXT_shader_implicit_conversions GL_EXT_shader_integer_mix GL_EXT_shader_io_blocks GL_EXT_shader_non_constant_global_initializers GL_EXT_shader_texture_lod GL_EXT_shadow_samplers GL_EXT_sparse_texture GL_EXT_sparse_texture2 GL_EXT_sRGB GL_EXT_sRGB_write_control GL_EXT_tessellation_point_size GL_EXT_tessellation_shader GL_EXT_texture_border_clamp GL_EXT_texture_buffer GL_EXT_texture_compression_bptc GL_EXT_texture_compression_dxt1 GL_EXT_texture_compression_rgtc GL_EXT_texture_compression_s3tc GL_EXT_texture_cube_map_array GL_EXT_texture_filter_anisotropic GL_EXT_texture_filter_minmax GL_EXT_texture_format_BGRA8888 GL_EXT_texture_mirror_clamp_to_edge GL_EXT_texture_norm16 GL_EXT_texture_query_lod GL_EXT_texture_rg GL_EXT_texture_shadow_lod GL_EXT_texture_sRGB_R8 GL_EXT_texture_sRGB_decode GL_EXT_texture_storage GL_EXT_texture_view GL_EXT_draw_transform_feedback GL_EXT_unpack_subimage GL_EXT_window_rectangles GL_KHR_context_flush_control GL_KHR_debug GL_EXT_memory_object GL_EXT_memory_object_fd GL_NV_memory_object_sparse GL_KHR_parallel_shader_compile GL_KHR_no_error GL_KHR_robust_buffer_access_behavior GL_KHR_robustness GL_EXT_semaphore GL_EXT_semaphore_fd GL_NV_timeline_semaphore GL_KHR_shader_subgroup GL_KHR_texture_compression_astc_ldr GL_KHR_texture_compression_astc_sliced_3d GL_KHR_texture_compression_astc_hdr GL_NV_bgr GL_NV_bindless_texture GL_NV_blend_equation_advanced GL_NV_blend_equation_advanced_coherent GL_NVX_blend_equation_advanced_multi_draw_buffers GL_NV_blend_minmax_factor GL_NV_clip_space_w_scaling GL_NV_compute_shader_derivatives GL_NV_conditional_render GL_NV_conservative_raster GL_NV_conservative_raster_pre_snap_triangles GL_NV_copy_buffer GL_NV_copy_image GL_NV_draw_buffers GL_NV_draw_instanced GL_NV_draw_texture GL_NV_draw_vulkan_image GL_NV_EGL_stream_consumer_external GL_NV_explicit_attrib_location GL_NV_fbo_color_attachments GL_NV_fill_rectangle GL_NV_fragment_coverage_to_color GL_NV_fragment_shader_barycentric GL_NV_fragment_shader_interlock GL_NV_framebuffer_blit GL_NV_framebuffer_mixed_samples GL_NV_framebuffer_multisample GL_NV_generate_mipmap_sRGB GL_NV_geometry_shader_passthrough GL_NV_instanced_arrays GL_NV_internalformat_sample_query GL_NV_gpu_shader5 GL_NV_image_formats GL_NV_memory_attachment GL_NV_mesh_shader GL_NV_occlusion_query_samples GL_NV_non_square_matrices GL_NV_pack_subimage GL_NV_packed_float GL_NV_packed_float_linear GL_NV_path_rendering GL_NV_path_rendering_shared_edge GL_NV_pixel_buffer_object GL_NV_polygon_mode GL_NV_primitive_shading_rate GL_NV_read_buffer GL_NV_read_depth GL_NV_read_depth_stencil GL_NV_read_stencil GL_NV_representative_fragment_test GL_NV_sample_locations GL_NV_sample_mask_override_coverage GL_NV_scissor_exclusive GL_NV_shader_atomic_fp16_vector GL_NV_shader_noperspective_interpolation GL_NV_shader_subgroup_partitioned GL_NV_shader_texture_footprint GL_NV_shading_rate_image GL_NV_shadow_samplers_array GL_NV_shadow_samplers_cube GL_NV_sRGB_formats GL_NV_stereo_view_rendering GL_NV_texture_array GL_NV_texture_barrier GL_NV_texture_border_clamp GL_NV_texture_compression_latc GL_NV_texture_compression_s3tc GL_NV_texture_compression_s3tc_update GL_NV_texture_dirty_tile_map GL_NV_timer_query GL_NV_viewport_array GL_NV_viewport_array2 GL_NV_viewport_swizzle GL_KHR_blend_equation_advanced GL_KHR_blend_equation_advanced_coherent GL_OES_compressed_ETC1_RGB8_texture GL_EXT_compressed_ETC1_RGB8_sub_texture GL_OES_depth24 GL_OES_depth32 GL_OES_depth_texture GL_OES_depth_texture_cube_map GL_OES_copy_image GL_OES_draw_buffers_indexed GL_OES_draw_elements_base_vertex GL_OES_texture_border_clamp GL_OES_tessellation_point_size GL_OES_tessellation_shader GL_OES_texture_buffer GL_OES_geometry_point_size GL_OES_geometry_shader GL_OES_gpu_shader5 GL_OES_shader_io_blocks GL_OES_texture_view GL_OES_primitive_bounding_box GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_EGL_image_external_essl3 GL_OES_EGL_sync GL_OES_element_index_uint GL_OES_fbo_render_mipmap GL_OES_get_program_binary GL_OES_mapbuffer GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_EXT_read_format_bgra GL_OES_sample_shading GL_OES_sample_variables GL_OES_shader_image_atomic GL_OES_shader_multisample_interpolation GL_OES_standard_derivatives GL_OES_surfaceless_context GL_OES_texture_cube_map_array GL_OES_texture_npot GL_OES_texture_float GL_OES_texture_float_linear GL_OES_texture_half_float GL_OES_texture_half_float_linear GL_OES_texture_stencil8 GL_OES_texture_storage_multisample_2d_array GL_OES_vertex_array_object GL_OES_vertex_half_float GL_OES_viewport_array GL_OVR_multiview GL_OVR_multiview2 GL_OVR_multiview_multisampled_render_to_texture GL_ANDROID_extension_pack_es31a "
===================================

Ctrl+C didn't work, so I had to shoot it down using SIGKILL from another terminal.

Trying to run it afterwards always fails:

[tonari@pragueripper-1 build]$ ./kmscube -n 60
no connected connector!
failed to initialize legacy DRM

I also see related info/warns/errors in dmesg:

[Tue Dec 19 17:30:57 2023] NVRM: GPU at PCI:0000:01:00: GPU-fa394e6b-edf8-1552-dfb3-9dd5937a1c41
[Tue Dec 19 17:30:57 2023] NVRM: Xid (PCI:0000:01:00): 56, pid='<unknown>', name=<unknown>, CMDre 00000007 00000200 00000001 00000005 0000001d
[Tue Dec 19 17:32:12 2023] nvidia-modeset: ERROR: GPU:0: Idling display engine timed out: 0x0000c67d:0:0:1051
[Tue Dec 19 17:32:44 2023] nvidia-modeset: ERROR: GPU:0: Idling display engine timed out: 0x0000c67e:6:0:1060
[Tue Dec 19 17:32:52 2023] nvidia-modeset: ERROR: GPU:0: Idling display engine timed out: 0x0000c67e:7:0:1060
[Tue Dec 19 17:32:55 2023] [drm:nv_drm_atomic_commit [nvidia_drm]] *ERROR* [nvidia-drm] [GPU ID 0x00000100] Flip event timeout on head 0
[Tue Dec 19 17:33:03 2023] nvidia-modeset: ERROR: GPU:0: Idling display engine timed out: 0x0000c67d:0:0:1051
[Tue Dec 19 17:33:35 2023] nvidia-modeset: ERROR: GPU:0: Idling display engine timed out: 0x0000c67e:6:0:1060
[Tue Dec 19 17:33:43 2023] nvidia-modeset: ERROR: GPU:0: Idling display engine timed out: 0x0000c67e:7:0:1060
[Tue Dec 19 17:33:43 2023] [drm:nv_drm_master_drop [nvidia_drm]] *ERROR* [nvidia-drm] [GPU ID 0x00000100] nv_drm_atomic_helper_disable_all failed with error code -22 !
[Tue Dec 19 17:34:33 2023] [drm:nv_drm_atomic_commit [nvidia_drm]] *ERROR* [nvidia-drm] [GPU ID 0x00000100] Failed to apply atomic modeset.  Error code: -22

FWIW kmscube has many commanline options, among them some interesting ones:

    -A, --atomic             use atomic modesetting and fencing
    -f, --format=FOURCC      framebuffer format
    -O, --offscreen          use offscreen rendering (e.g. for render nodes)
    -x, --surfaceless        use surfaceless mode, instead of gbm surface
skywhale commented 11 months ago

I tried to follow @strohel but I couldn't get kmscube to work either. drmModeAddFB2WithModifiers and drmModeAddFB2 fail with return code of -22 with "Invalid parameters" error message. Reboot didn't help. Very curious why it seemed to have worked for the first time with @strohel

I then loaded nouveau driver for the card, following @mbernat's report, and I was able to get the kmscube example to work and render the nicely colorful cube.

With nouveau, @mbernat's gl branch also worked, but I had to change create_surface_with_modifiers() with create_surface(); otherwise it was complaining about non-implemented function.