Libretro/Retroarch is a generic "game system" that can execute "cores". Each core is an emulator, or a virtual machine (like there's a "Mame" core, a "dosbox" core, etc Doesn't need to be an emulator too, some games are relased as "cores" ). The infrastructure provides for all window and input management, the core has to specify its desired resolution and has a callback method to render the scene (simplifying a lot). Audio, input, etc are unified for all cores. Cores are actually just dll/so with specific callback functions (obviously they can rely on external files). Most important callbacks are "init" (that inizialize the core) and "run" (which is called every frame and should render the scene).Also, cores come in two variant: the classic variant draw graphics on a generic "ram buffer" that's then sent to the screen (like old 8 bit system), while the opengl variant is opengl-aware and receive an opengl framebuffer onto which to render. (this is becouse opengl is so ubuquitous that they consider skipping a layer of abstraction for performances).The main gotcha of the opengl core is that you have to render not on the screen but on a framebuffer that is provided to you by libretro infrastructure (so that it can render its own gui on top etc). This shouldn't be a huge deal since, once bound, rendering on the framebuffer should be pretty transparent.
... ... glBindFramebuffer(RARCH_GL_FRAMEBUFFER, hw_render.get_current_framebuffer()); glClearColor(0.3, 0.4, 0.5, 1.0); glViewport(0, 0, width, height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); doJavaCall(); // here, the java side is called. glUseProgram(prog); glEnable(GL_DEPTH_TEST); ... ...
System.out.println("****************CHIAMATO DOCALL***************"); Configuration.DEBUG.set(true); System.out.println("Context: "+WGL.wglGetCurrentContext()); System.out.println("Device: "+WGL.wglGetCurrentDC()); System.out.println("lolTest: "+org.lwjgl.opengl.GL11.class); // ensure class has initializers done System.out.println("OK"); String s = org.lwjgl.opengl.GL11.glGetString(org.lwjgl.opengl.GL11.GL_VERSION); System.out.println("Version is "+s);
calling doCall****************CHIAMATO DOCALL***************[LWJGL] Version: 3.2.3 SNAPSHOT[LWJGL] OS: Windows 10 v10.0[LWJGL] JRE: 13.0.1 amd64[LWJGL] JVM: OpenJDK 64-Bit Client VM v13.0.1+9 by AdoptOpenJDK[LWJGL] Loading JNI library: lwjgl[LWJGL] Module: org.lwjgl[LWJGL] Loaded from org.lwjgl.librarypath: C:\Users\niclugat\AppData\Local\Temp\lwjglniclugat\3.2.3-SNAPSHOT\lwjgl.dll[LWJGL] Loading JNI library: lwjgl_opengl[LWJGL] Module: org.lwjgl.opengl[LWJGL] Loaded from org.lwjgl.librarypath: C:\Users\niclugat\AppData\Local\Temp\lwjglniclugat\3.2.3-SNAPSHOT\lwjgl_opengl.dll[LWJGL] Loading library: opengl32[LWJGL] Module: org.lwjgl.opengl[LWJGL] opengl32.dll not found in org.lwjgl.librarypath=C:\Users\niclugat\AppData\Local\Temp\lwjglniclugat\3.2.3-SNAPSHOT[LWJGL] Loaded from system paths: C:\WINDOWS\SYSTEM32\OPENGL32.dll[LWJGL] Loading library: jemalloc[LWJGL] Module: org.lwjgl.jemalloc[LWJGL] Loaded from org.lwjgl.librarypath: C:\Users\niclugat\AppData\Local\Temp\lwjglniclugat\3.2.3-SNAPSHOT\jemalloc.dll[LWJGL] MemoryUtil allocator: JEmallocAllocatorContext: 131072Device: 251730347lolTest: class org.lwjgl.opengl.GL11OK
WGL seems to be looking at function pointer and calling native "callPPI" style functions (this is black magic to me), while GL stuff seems to be using regular native functions like "static native void glClearColor" in GL11C.
funcAddr = APIUtil.apiGetFunctionAddress(GL.getFunctionProvider(), "glClearColor");JNI.callV(funcAddr, 0f, 1f, 0f, 0f);
OpenGL functions are called using static methods. However, OpenGL function addresses are specific to the context that is bound to the current thread. Normally, this would require a thread-local lookup on each method call, which is not terribly expensive, but it adds up and also affects the optimization of surrounding code. Unfortunately, Hotspot cannot hoist the lookup outside of loops, etc. That's why LWJGL handles OpenGL calls differently, to avoid the thread-local lookup completely without sacrificing correctness. This is indeed black magic (i.e. nasty hack that messes with JVM internals), see the ThreadLocalUtil class for more details.
1) The first capabilities instance encountered is stored in a static write-once holder. This is optimistically assumed to be compatible with all other (if any) instances we encounter, which is indeed the case for the vast majority of programs. If an incompatible instance is encountered, there is a fall back to the thread-local lookup.
A callback to grab OpenGL symbols is exposed via retro_hw_get_proc_address_t. Use this to retrieve symbols and extensions.