Skip to content
conversy edited this page Aug 24, 2022 · 15 revisions

This is a porting guide to support MGL in an Opengl4.6 app. As Michael said, "the 4.6 path is narrow", so you need to use the core GL4.6 and GLSL4.6 functionalities only... but this will also give you the benefits of A-AZDO (almost "almost zero-driver overhead", as there are still few missing pieces, such as bindless_texture).

Note: it's not working perfectly yet but more and more is working.

Integrating MGL in your app:

Have a look at https://github.com/openglonmetal/MGL/blob/main/test_mgl/main.cpp, especially functions main_sdl or main_glfw to see how to create and use an MGL context with SDL or GLFW. Un-intuitively, you must open a legacy OpenGL 4.1 context (and not a Metal one), as MGL will rely on it to grab some default values. After that, you should create an MGL context, and make it available to SDL or GLFW callback functions (either with a global variable, or with a user-provided void* object passed to SDL or GLFW).

You can enable Metal capturing, this is very helpful to find bugs, and also to explore how your app is rendered! To do so, uncomment out the code at the end of MTLRenderer.m (around line 3990). Do not forget to create an Info.plist file as per https://stackoverflow.com/a/64172784, and set export METAL_DEVICE_WRAPPER_TYPE=1. This will create an MGL.gputrace directory that you can analyse with

open -a xcode /path/to/MGL.gputrace

Porting guide:

  • no need for glUniformBlockBinding or glShaderStorageBlockBinding, don't call that
  • if you have code like this:
glVertexAttribPointer(w->prev_loc, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET((1)*vi_size)); // with non-null buffer offset

you should precede it with something like this:

glBindVertexBuffer(w->prev_loc, _coords_vbo, 0, 1*vi_size);
  • there is no implementation of glBlitFramebuffer, glClearBufferv, glGet* added
  • blending seems broken(?) fixed
  • no need to glEnable(GL_PRIMITIVE_RESTART), nor glPrimitiveRestartIndex, as Metal defines it by default to 0xFFFF or 0xFFFFFFFF
  • use GL_RGBA8 and not GL_RGBA as internalFormat e.g. in glTextureImage2D(GL_TEXTURE_2D, 0, GL_RGBA8...
  • render buffer should be GL_RGBA (there is no GL_RGB render buffer in metal)
  • once created with glBufferData, an immutable buffer cannot be changed as a whole with a subsequent glBufferData, you must use glBufferSubData, MGL is (rightly) picky about it
  • I had to use GL_TEXTURE0, and not directly GL_TEXTURE1
  • it's worst than that: as per this SPIRV-Cross behavior, explicit binding of samplers is not taken into account, so your texture code must be able to handle implicit binding of samplers.
  • I had to define a blend equation e.g. glBlendEquation(GL_FUNC_ADD); fixed
  • variables in shaders must be initialized, it seems there is a bug when a variable is declared, not initialized, and set in sub-blocks like conditionals (it seems to create a tmp variable in the scope of the block, not updating the declared one)
  • there is no support for single global uniforms, you must use UBOs. This is a limitation of the glslang compiler, there is an option to support them, but I could not make it work, supposedly vulkan only (see GL_EXT_vulkan_glsl_relaxed extension)
  • in and out variables in all shader stages must be explicitly laid out with layout(xxx)
  • I have an issue when enabling multiple vertex attributes on the same buffer object, it messes up the content: I came to the conclusion that it was impossible to have two calls to glBindVertexBuffer with the same vbo, but different binding_index and stride, as the last call will erase the stride of the first one. It seems there is a mismatch between OpenGL and Metal here. So I changed my code and split my single vbo into two vbos, and setup the attributes accordingly, which gives the correct result.
  • for ARB_multi_draw_indirect, you must use a specific draw_ids buffer, it's not possible to use the trick with using the baseInstance field of the command in the command buffer as an attribute
Clone this wiki locally