Low Level Graphics Library (LLGL) is a thin abstraction layer for the modern graphics APIs OpenGL, Direct3D, Vulkan, and Metal

Low Level Graphics Library (LLGL)

License Join the chat at https://gitter.im/LLGL-Project/community

Documentation

Platform Support

Platform CI D3D12 D3D11 Vulkan OpenGL OpenGLES 3 Metal
Windows Windows Build ✔️ ✔️ ✔️ ✔️ N/A N/A
GNU/Linux GNU/Linux Build Status N/A N/A ✔️ ✔️ N/A N/A
macOS macOS Build Status N/A N/A N/A ✔️ N/A ✔️
iOS iOS Build Status N/A N/A N/A N/A ✖️ ✔️
Android N/A N/A ✖️ N/A ✔️ N/A

Build Notes

Build scripts are provided for CMake.

Windows

Visual Studio 2015 or later is required to build LLGL on Windows.

macOS, iOS

Xcode 9 or later is required to build LLGL on macOS and iOS.

GNU/Linux

The following development libraries are required to build LLGL on GNU/Linux:

  • X11: libx11-dev
  • xf86vidmode: libxxf86vm-dev
  • Xrandr: libxrandr-dev

Android

The Android NDK with at least API level 21 is required. The build script to generate project files is currently only supported on GNU/Linux and requires CMake 3.10 or later and the Code::Blocks IDE.

This platform support is currently in an experimental state.

Thin Abstraction Layer

// Unified Interface:
CommandBuffer::DrawIndexed(std::uint32_t numIndices, std::uint32_t firstIndex);

// OpenGL Implementation:
void GLCommandBuffer::DrawIndexed(std::uint32_t numIndices, std::uint32_t firstIndex) {
    const GLintptr indices = (renderState_.indexBufferOffset + firstIndex * renderState_.indexBufferStride);
    glDrawElements(
        renderState_.drawMode,
        static_cast<GLsizei>(numIndices),
        renderState_.indexBufferDataType,
        reinterpret_cast<const GLvoid*>(indices)
    );
}

// Direct3D 11 Implementation
void D3D11CommandBuffer::DrawIndexed(std::uint32_t numIndices, std::uint32_t firstIndex) {
    context_->DrawIndexed(numIndices, firstIndex, 0);
}

// Direct3D 12 Implementation
void D3D12CommandBuffer::DrawIndexed(std::uint32_t numIndices, std::uint32_t firstIndex) {
    commandList_->DrawIndexedInstanced(numIndices, 1, firstIndex, 0, 0);
}

// Vulkan Implementation
void VKCommandBuffer::DrawIndexed(std::uint32_t numIndices, std::uint32_t firstIndex) {
    vkCmdDrawIndexed(commandBuffer_, numIndices, 1, firstIndex, 0, 0);
}

// Metal implementation
void MTCommandBuffer::DrawIndexed(std::uint32_t numIndices, std::uint32_t firstIndex) {
    if (numPatchControlPoints_ > 0) {
        [renderEncoder_
            drawIndexedPatches:             numPatchControlPoints_
            patchStart:                     static_cast<NSUInteger>(firstIndex) / numPatchControlPoints_
            patchCount:                     static_cast<NSUInteger>(numIndices) / numPatchControlPoints_
            patchIndexBuffer:               nil
            patchIndexBufferOffset:         0
            controlPointIndexBuffer:        indexBuffer_
            controlPointIndexBufferOffset:  indexTypeSize_ * (static_cast<NSUInteger>(firstIndex))
            instanceCount:                  1
            baseInstance:                   0
        ];
    } else {
        [renderEncoder_
            drawIndexedPrimitives:  primitiveType_
            indexCount:             static_cast<NSUInteger>(numIndices)
            indexType:              indexType_
            indexBuffer:            indexBuffer_
            indexBufferOffset:      indexTypeSize_ * static_cast<NSUInteger>(firstIndex)
        ];
    }
}
Owner
Lukas Hermanns
Shader Tools Programmer @ Epic Games; Previously @ MA Lighting; Opinions are my own
Lukas Hermanns
Comments
  • Error creating custom surface classes in Mac OS BigSur and Xcode 12.4

    Error creating custom surface classes in Mac OS BigSur and Xcode 12.4

    Hi,

    I am trying to create a Custom Surface Class example using GLFW as mentioned in the documentation. While declaring the

    class CustomSurface : public LLGL::Surface I am getting the errors shown in the screenshot. The errors seems to be pointing to NSObjcRuntime.h and NSObject.h. I am only mildly familiar with Mac environment so any help is appreciated

    Screenshot 2021-07-27 at 12 40 34 AM

    I am unfamiliar with Mac environment so any help is appreciated.

  • Static compile and uniform empty api

    Static compile and uniform empty api

    • Static linking now supports multiple renderers in the same lib.
    • Added empty api for shader uniforms. Note: Static linking will not not compile with current cmake setup. Each renderer api must now have one of the following defines:
    • LLGL_HAS_MODULE_DX11
    • LLGL_HAS_MODULE_DX12
    • LLGL_HAS_MODULE_OPENGL
    • LLGL_HAS_MODULE_OPENGLES3
    • LLGL_HAS_MODULE_VULKAN
    • LLGL_HAS_MODULE_METAL
  • Great library and some questions.

    Great library and some questions.

    Hi, recently I have been using LLGL to replace the ugly underlying API layer in my engine, I am a big fan of LLGL architecture as I hate opengl-like architecture "ex: bgfx", anyways I have some questions about this library.

    1-Why supporting OpenGL? Vulkan is a great successor and run on almost all platforms that OpenGL run on, and can run on mobile devices plus it has DirectX-like structure and a modern API. The reason I dislike OpenGL is it has some sort of legacy function that is still used until now! for example it requires a vertex format for each vertex buffer created! correct me if I am wrong but it is the only API that does that in 2018.

    2-Do I have to create a resource heap for each pair of Texture and sampler in every shader?

    3-Will I need more than one CommandBuffer for my project?

    4-Why is "RenderSystem" / "Renderer" named with these names? shouldn't they be named Context and the "Context" class should be named Device?

    • I kinda prefer DirectX namings + naming anything with "Renderer" can cause huge confusion especially with newcomers.
  • Can't run the examples

    Can't run the examples

    Hi, I'm trying to run the examples, but I can't get it to work.

    I followed the setup instructions to install everything and it all builds fine. (I'm using visual studio 2019)

    When I run the develop build for the PBR example and pick the DirectX12 option in the console I get a "failed to open file: Example.hlsl" error

    I then manually setup the Debugging->Working Directory to point to the project directory, and that fixed the loading issue.

    After that I get a crash on D3D12CommandContext::SetPipelineState

    traced it down to:

    D3D12MipGenerator::CreateComputePSO if (auto blob = DXCreateBlobFromResource(resourceID)) returning null

    /* Load resource from binary data (*.rc file) */
    if (HRSRC resource = FindResource(moduleHandle, MAKEINTRESOURCE(resourceID), RT_RCDATA))
    

    I don't seem to have this .rc file. Did I miss something?

  • License

    License

    Hi,

    I was checking the License more carefully and I noticed that this library is using none of the well-known licenses. Therefore I was here to actually ask if there is a plan on using anyone of them like MIT, Apache or GPL?

    I was planning in using this in one of my projects, but at the current state I'm a bit concerned about consequences in using your code on top of mine.

    Thank you in advance for any clarification given.

  • Question: LLGL_OpenGL , WriteTexture

    Question: LLGL_OpenGL , WriteTexture

    Hi. I found that when write compressed texture to Cubemap texture with extension GL_ARB_direct_state_access you call glCompressedTextureSubImage3D function just like when it is not compressed you call glTextureSubImage3D function. And I checked that why you call this function in page : https://www.khronos.org/opengl/wiki/Cubemap_Texture. It says : "Uploading pixel data for cubemaps is somewhat complicated. If OpenGL 4.5 or ARB_direct_state_access is available, then glTexSubImage3D can be used to upload face data for a particular mipmap level. The third dimension values for glTexSubImage3D represents which face(s) to upload data to. The faces are indexed in the following order: ..."

    But when I use the compressed type write function it seems write nothing to the texture(all is black). So I want to know whether the glCompressedTextureSubImage3D function can use for cubemap texture just as same as the glTextureSubImage3D function ?

  • Use native FindVulkan.cmake

    Use native FindVulkan.cmake

    Backstory: I was trying to build this library under Visual Studio 2019 for Win32 Arch and I found out that Vulkan was not able to be found, with the latest SDK version ( 1.1.130 ). Looking at how you did include Vulkan I found out you're using the old suggested method. Nowadays it's better to use the native FindVulkan.cmake which is provided by any Cmake version that is >= 3.7.

    I doubt someone will build this code with an older CMake version.

    Thank you for the awesome work you're doing. Looking forward on this project.

  • Dx11 bug with caps.features.hasLogicOp.

    Dx11 bug with caps.features.hasLogicOp.

    There is an inconsistency between this lines: DXCode.cpp: caps.features.hasLogicOp = (featureLevel >= D3D_FEATURE_LEVEL_11_1); DX11Types.cpp (function Convert): if (src.logicOp != LogicOp::Disabled) without define LLGL_D3D11_ENABLE_FEATURELEVEL added to compile.

    Value of hasLogicOp can be set to true by D3D_FEATURE_LEVEL_11_1 but the code assumes it's disabled without LLGL_D3D11_ENABLE_FEATURELEVEL

  • reserved identifier violation

    reserved identifier violation

    I would like to point out that an identifier like "__LLGL_COMMAND_BUFFER_H__" does not fit to the expected naming convention of the C++ language standard. Would you like to adjust your selection for unique names?

  • Vulkan swapChainImages and swapChainFrameBuffers not being properly deleted when SwapChain is recreated.

    Vulkan swapChainImages and swapChainFrameBuffers not being properly deleted when SwapChain is recreated.

    I have identified bugs at https://github.com/LukasBanana/LLGL/blob/master/sources/Renderer/Vulkan/VKRenderContext.cpp#L411-L416 and https://github.com/LukasBanana/LLGL/blob/master/sources/Renderer/Vulkan/VKRenderContext.cpp#L465-L470

    the outdated VKPtr and VKPtr don't get deleted, instead a new object is made every time the SwapChain is recreated; this causes it not to be deleted on the GPU.

    I think it should check if one of the objects exists, if it doesn't, it should create one; then it can recreate it. Like this:

    	if (!swapChainImageViews_[i]) {
    		swapChainImageViews_[i] = VKPtr<VkImageView>{device_, vkDestroyImageView};
    	}
    
    	auto result = vkCreateImageView(device_, &createInfo, nullptr, wapChainImageViews_[i].ReleaseAndGetAddressOf());
    	VKThrowIfFailed(result, "failed to create Vulkan swap-chain image view");
    
    	if (!swapChainFramebuffers_[i]) {
    		swapChainFramebuffers_[i] = VKPtr<VkFramebuffer>{device_, vkDestroyFramebuffer};
    	}
    
    	auto result = vkCreateFramebuffer(device_, &createInfo, nullptr, swapChainFramebuffers_[i].ReleaseAndGetAddressOf());
    	VKThrowIfFailed(result, "failed to create Vulkan swap-chain framebuffer");
    
  • Correctly handling Retina displays on the Mac

    Correctly handling Retina displays on the Mac

    I’ve been working on getting Retina support into LLGL. The new code is not done and requires a lot of clean-up but the changes involve re-thinking what SetVideoMode does so I thought you should take a look sooner rather than later.

    In Retina mode the size of the surface and the size of the drawables diverge. An NSWindow is sized in a space that roughly approximates 72 dpi and then the drawables are sized upward to a match the actual dpi of the screen. So I needed to alter SetVideoMode to resize the drawables independently of the surface size. I started by stubbing out Window::AdjustForVideoMode and all of the fullscreen handling (more on fullscreen later).

    Then I added Surface::GetPreferredResolution() so a surface can advertise a preferred resolution that differs from GetContentSize(). Finally I updated OnSetVideoMode for both Metal and OpenGL to resize the drawables appropriately. And that was pretty much it beyond tweaking Info.plist and updating the sample code a bit.

    Basically I’ve pared down SetVideoMode to only update the size of the drawables, roughly equivalent to ResizeBuffer in DirectX. This eliminates the possibility that calling SetVideoMode could generate a resize event while handling a resize event. It also eliminates the code that was trying to re-center the window on every resize event which was making live re-resizing impossible on the Mac.

    (BTW, I tweaked the DirectX versions of OnSetVideoMode to allow arbitrary sizes to match the Mac. On Windows the main use would be to to reduce the size of the drawables for performance reasons.)

    The next step is to get fullscreen working again. Previously SetVideoMode was called at both ends of the process, first to kick the system into fullscreen mode and then to handle the resulting resize event. I want to avoid that recursion by introducing new RenderContext routines for entering and exiting fullscreen mode. Then clean-up, including adding some capability flags.

  • Multi submission of command buffer results in flickering

    Multi submission of command buffer results in flickering

    LLGL::CommandBufferFlags::MultiSubmit seems to imply, that it should be possible to record a command buffer once and resubmit it multiple times to prevent CPU cycles being wasted dispatching draw calls to the GPU while nothing has changed.

    The results of testing out this theory made me wonder whether or not the results I was seeing were intended behaviour. Tested with Vulkan.

        LLGL::CommandBuffer *renderCmd;
        {
            LLGL::CommandBufferDescriptor commandBufferDescriptor{
                    .flags =(LLGL::CommandBufferFlags::MultiSubmit)
            };
            renderCmd = renderSystem->CreateCommandBuffer(commandBufferDescriptor);
        }
        renderCmd->Begin();
        {
            renderCmd->SetViewport(renderContext->GetResolution());
            renderCmd->SetPipelineState(*pipeline);
            renderCmd->SetVertexBuffer(*vertexBuffer);
            renderCmd->SetClearColor(LLGL::ColorRGBAf(0.1f, 0.1f, 0.1f));
    
            renderCmd->BeginRenderPass(*renderContext);
    
            renderCmd->Clear(LLGL::ClearFlags::Color);
            renderCmd->Draw(3, 0);
    
            renderCmd->EndRenderPass();
        }
        renderCmd->End();
        while (window.ProcessEvents()) {
            queue->Submit(*renderCmd);
            renderContext->Present();
        }
    

    This little example produces nothing more than the clear color flashing between black and the gray specified in the command buffer. The triangle, which renders just fine when the command buffer is re-recorded every frame in the main loop, is no where to be seen with this code.

    However, some experimentation revealed even weirder behaviour: Re-recording the command buffer for the first three frames of the application and then continuing to use it works just fine. If the command buffer is altered at a later point in time, it requires only 2 repeated recordings (with a Submit call and a renderContext->Present() in between) for the changes to be displayed without flickering. Re-recording the command buffer less than 3 times for the initial frames of the loop, or less than 2 times at a later point in time will result in flickering back and forth between what seem to be the previously recorded draw calls and what actually should be displayed.

    I think this might be happening because a double buffered swap chain also has two command buffers. When a new frame is forced to render, it will cycle back to the previous command buffer. If the command buffer contents have not been updated in a frame, no new image should be acquired from the swap chain.

    Should it be possible to re-submit command buffers in this way? Am I using LLGL incorrectly?

  • CreateBuffer w. > 1MB bind=VertexBuffer on static build crashes

    CreateBuffer w. > 1MB bind=VertexBuffer on static build crashes

    Not much more to say, built static lib using clang modified your own triangle test code change buffer size to 2MB and crash. Building with clang 12 on win64

  • WebGPU support?

    WebGPU support?

    I would like to offer WebGPU support for LLGL. And almost directly, straight. Every function would be remap. And it was compiled into two files: JS (WebGPU access) and WebAssembly (residual C++).

  • Hosting surfaces on non-Window, and factoring out message loop

    Hosting surfaces on non-Window, and factoring out message loop

    1. The library assumes all rendering in Native top-level windows there are other surfaces the - like composition visuals (IVisual), and swap panels etc.
    2. the main game loop is owned by the the library this should be factored out for the library to be used as a component
    3. UWP support and Core windows support - additionally IVisual, Swap panel in uwp
    4. support Google/Angele/GLES under windows.
  • ShaderReflection without shader initialization

    ShaderReflection without shader initialization

    So I'm trying to generate Shader/Material/Resources using shader reflection. I already did this before and had an hlsl solution.

    Looking through the code I found out you can actually use ShaderProgram::Reflect() to do exactly that, but now I have a minor problem.

    I need to create and initialize a shader whenever I want to use shader reflection to create the actual shader.

    From looking through the code I can see that you only need the shader byte code which is generated using the shader compiler.

    Unfortunately I don't see any way to just compile the shader and use the byte code to reflect.

    Am I missing something? If not could you make this possible by splitting the compiler and reflection from the shader resource?

Direct3D to OpenGL abstraction layer

TOGL Direct3D -> OpenGL translation layer. Taken directly from the DOTA2 source tree; supports: Limited subset of Direct3D 9.0c Bytecode-level HLSL ->

Aug 7, 2022
NVRHI (NVIDIA Rendering Hardware Interface) is a library that implements a common abstraction layer over multiple graphics APIs

NVRHI Introduction NVRHI (NVIDIA Rendering Hardware Interface) is a library that implements a common abstraction layer over multiple graphics APIs (GA

Aug 3, 2022
Legion Low Level Rendering Interface provides a graphics API agnostic rendering interface with minimal CPU overhead and low level access to verbose GPU operations.
Legion Low Level Rendering Interface provides a graphics API agnostic rendering interface with minimal CPU overhead and low level access to verbose GPU operations.

Legion-LLRI Legion-LLRI, or “Legion Low Level Rendering Interface” is a rendering API that aims to provide a graphics API agnostic approach to graphic

Aug 13, 2022
A modern cross-platform low-level graphics library and rendering framework
A modern cross-platform low-level graphics library and rendering framework

Diligent Engine A Modern Cross-Platform Low-Level 3D Graphics Library Diligent Engine is a lightweight cross-platform graphics API abstraction library

Aug 12, 2022
A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input

GLFW Introduction GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan application development. It provides a simple, platf

Aug 17, 2022
Deno gl - WIP Low-level OpenGL (GLFW) bindings and WebGL API implementation for Deno.

deno_gl WIP Low-level OpenGL (GLFW) bindings and WebGL API implementation for Deno. Building Make dist directory if it doesn't exist. Build gl helper

Jun 11, 2022
OpenGL®-Starter is a template for your upcoming OpenGL Projects which has been compiled to run the most basic Hello World OpenGL Program from LearnOpenGL.com.
OpenGL®-Starter is a template for your upcoming OpenGL Projects which has been compiled to run the most basic Hello World OpenGL Program from LearnOpenGL.com.

OpenGL®-Starter OpenGL®-Starter is a template for your upcoming OpenGL Projects which has been compiled to run the most basic Hello World OpenGL Progr

Jul 18, 2022
OpenGL 4.6 on Metal

MGL OpenGL 4.6 on Metal This is a start for porting OpenGL 4.6 on top of Metal, most of it is functional and has been tested. The tests are functional

Aug 10, 2022
This is a openGL cube demo program. It was made as a tech demo using PVR_PSP2 Driver layer GPU libraries.

OpenGL Cube Demo using PVR_PSP2 Driver layer GPU libraries This is a openGL cube demo program. It was made as a tech demo using PVR_PSP2 Driver layer

Oct 31, 2021
A low-level, cross-platform GPU library

vgpu is cross-platform low-level GPU library. Features Support for Windows, Linux, macOS. Modern rendering using Vulkan and Direct3D12. Dependencies U

Jul 28, 2022
OBS Linux Vulkan/OpenGL game capture

OBS Linux Vulkan/OpenGL game capture OBS plugin for Vulkan/OpenGL game capture on Linux. Requires OBS with EGL support (currently unreleased, you need

Aug 12, 2022
Aug 8, 2022
C++/openGL/Vulkan 3D engine
C++/openGL/Vulkan 3D engine

DeusEx Machina engine C++/GL/Vulkan 3D graphic engine First commit, hello world! :D Reddit post about why I started with skeletal animation system and

May 19, 2022
Easy to integrate memory allocation library for Direct3D 12

D3D12 Memory Allocator Easy to integrate memory allocation library for Direct3D 12. Documentation: Browse online: D3D12 Memory Allocator (generated fr

Aug 17, 2022
A minimal Direct3D 12 example that draws an animated triangle, written entirely in C-style C++, and all taking place inside a single function.
A minimal Direct3D 12 example that draws an animated triangle, written entirely in C-style C++, and all taking place inside a single function.

A minimal Direct3D 12 example that draws an animated triangle, written entirely in C-style C++, and all taking place inside a single function.

May 3, 2022
Simple console tool to get all the information from DXGI and Direct3D 12 on current system
Simple console tool to get all the information from DXGI and Direct3D 12 on current system

D3d12info Simple console tool to get all the information from DXGI and Direct3D 12 (D3D12) on current system. Built and tested on Windows 10 64-bit us

Aug 10, 2022
Direct3D 12.0 quick reference guide

Direct3D 12.0 quick reference guide

Mar 24, 2022
A legacy OpenGL simulator for OpenGL 4.4, written in C++.

the-ancient-tri A legacy OpenGL simulator for OpenGL 4.4, written in C++. Why? My Uni forces us to use legacy OpenGL (eww!), and I didn't want to lear

Feb 10, 2022
Source Code for "Ray Tracing Gems: High-Quality and Real-Time Rendering with DXR and Other APIs" by Eric Haines and Tomas Akenine-Möller

Apress Source Code This repository accompanies Ray Tracing Gems: High-Quality and Real-Time Rendering with DXR and Other APIs by Eric Haines and Tomas

Aug 11, 2022