lukasbanana / llgl Goto Github PK
View Code? Open in Web Editor NEWLow Level Graphics Library (LLGL) is a thin abstraction layer for the modern graphics APIs OpenGL, Direct3D, Vulkan, and Metal
License: BSD 3-Clause "New" or "Revised" License
Low Level Graphics Library (LLGL) is a thin abstraction layer for the modern graphics APIs OpenGL, Direct3D, Vulkan, and Metal
License: BSD 3-Clause "New" or "Revised" License
The GenerateMips
functions should be part of the CommandBuffer
interface instead of the RenderSystem
interface.
Reason:
ID3D12GraphicsCommandList
interface.MTLBlitCommandEncoder
to generate MIP-maps, which is acquired by the MTLCommandBuffer
interface.Appendix:
Texture::QueryMipLevelSize
function should possibly be renamed to Texture::QueryMipExtent
, because the name "extent" corresponds better to the nomenclature. DoneHi,
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.
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?
It seems like current C# wrapper using C++/CLI. (Correct me if I'm wrong)
Isn't C++/CLI only supported on Windows platform for now? Microsoft introduced C++/CLI support to .NET Core 3 but unfortunately it is only working on Windows.
PInvoke is the only option right now for cross-platform C# binding.
hello, could you shared the Guass math LIB?
I'm mulling over the cmakelists file to see how I can port it over to premake5 for my own personal project, but I was wondering if you guys could give me a rundown on the build flags and such that need to be set in order to build it properly. Since the library can only get the full range of features when built as a shared library, I am definitely going to be doing that at least, but is there anything else I shod be aware of? Any gotchas or quirks I should know about?
This is a concept for a new and simplied TextureDescriptor
that applies to the new rendering APIs. Instead of having multiple nested structures for 1D, 2D, 3D, 2DMS and Cube textures, there is only one descriptor for all types of texutres:
struct TextureDescriptor {
TextureType type = TextureType::Undefined;
Format format = Format::Undefined;
long flags = TextureFlags::Default;
std::uint32_t width = 1;
std::uint32_t height = 1;
std::uint32_t depth = 1;
std::uint32_t layers = 1;
std::uint32_t samples = 1;
};
The member bool TextureDescriptor::Texture2DMS::fixedSamples
can be replaced by a new flags entry to the TextureFlags
enum.
Usage example:
// 1D array texture
LLGL::TextureDescriptor myTex1DDesc;
myTex1DDesc.type = LLGL::TextureType::Texture1DArray;
myTex1DDesc.width = 128;
myTex1DDesc.layers = 64;
auto myTex1D = myRenderer->CreateTexture(myTex1DDesc);
// Cube texture
LLGL::TextureDescriptor myTexCubeDesc;
myTexCubeDesc.type = LLGL::TextureType::TextureCube;
myTexCubeDesc.width = 32;
myTexCubeDesc.height = 32; // must be equal to width!
myTexCubeDesc.layers = 1; // automatically multiplied by 6 (one for each cube face)
auto myTexCube = myRenderer->CreateTexture(myTexCubeDesc);
This is an overview of some major bullet points for improvements or unimplemented features in LLGL:
VK_EXT_conditional_rendering
extension for conditional rendering, but it hasn't been implemented in LLGL yet.SetStreamOutputBuffer
etc.). Requires VK_EXT_transform_feedback
Vulkan extension.SetUniform
/ SetUniforms
functions in CommandBuffer
interface is the way to go for Vulkan's "push constants".CommandBuffer::UpdateBuffer
simply does not work correct for the D3D12 backend. A Ring-Buffer implementation may be useful for this purpose.D3D12MipGenerator
class to generate MIP-maps with a compute shader, like the DX12 example illustrates. Before that, GenerateMips
function must be moved from RenderSystem
to CommandBuffer
interface, or RenderSystem
may keep it as a secondary function to be used outside of command encoding.SetStreamOutputBuffer
etc.).TessControl
shader must be merged into the 'vertex function', and the TessEvaluation
shader must be implemented as a 'kernel function'.Window
event handling and resize: The envent handling in the MacOS implementation of the Window
interface could be improved. Especially resiying the window does not work properly.LinuxDisplay::SetDisplayMode
LinuxDisplay::ResetDisplayMode
LinuxDisplay::ShowCursor
LinuxDisplay::IsCursorShown
LinuxWindow::SetDesc
LinuxWindow::GetDesc
D3D12CommandBuffer::ClearAttachments
D3D12CommandBuffer::CopyBuffer
(resource transition/barrieres)D3D12CommandBuffer::CopyTexture
(resource transition/barrieres)CommandBuffer::ResetResourceSlots
: This function is only used to circumvent an issue with resource binding with older APIs that do not support descriptor heaps/sets natively. Binding a resource for writing (e.g. a render target) requires the same resource to not be bound at any other binding point for reading. It's not trivial to keep track of each resource where it is bound (potentially at multiple points) in an efficient manner. The ResetResourceSlots
function is used so the client programmer can manually unbind resources before binding it for writing (or as UAV in D3D terms). With LLGL having the concept of ResourceHeap
, this manual unbinding should not be a requirement. Finding an efficient way to detect resources that need to be unbound is crucial ... and not easy :)RenderSystem
: The Release
functions should not delete the objects immediately. Instead, RenderSystem
should keep track which objects are still used. For instance, a released Texture
object that is still in use in another ResourceHeap
should only be deleted when the last ResourceHeap
or Texture
-view that refers to it is deleted (via reference counter).The idea is to get rid of all ...Array
interfaces as well as Set...Array
functions in the CommandBuffer
interface. Instead, the new ResourceHeap
interface should be used, which complies with the new rendering APIs. The SetVertexBufferArray
function should be refactored to the following:
void SetVertexBuffers(std::uint32_t numVertexBuffers, Buffer* const * vertexBuffers);
For all renderers (except OpenGL) this can be trivially implemented by using an uninitialized local C-style array that is passed to the native renderer API like this:
void D3D11CommandBuffer::SetVertexBuffers(
std::uint32_t numVertexBuffers,
Buffer* const* vertexBuffers)
{
/* Uninitialized local arrays are trivially constructed on the stack */
ID3D11Buffer* buffers[g_maxVertexBuffers];
UINT strides[g_maxVertexBuffers];
UINT offsets[g_maxVertexBuffers];
/* Convert vertex buffer array to native parameters */
numVertexBuffers = std::min(numVertexBuffers, g_maxVertexBuffers);
for (std::uint32_t i = 0; i < numVertexBuffers; ++i)
{
auto vertexBufferD3D = LLGL_CAST(D3D11VertexBuffer*, vertexBuffers[i]);
buffers[i] = vertexBufferD3D->GetNative();
strides[i] = vertexBufferD3D->GetStride();
offsets[i] = 0;
}
/* Pass local arrays to native API */
context_->IASetVertexBuffers(0, numVertexBuffers, buffers, strides, offsets);
}
This works analogous to the SetViewports
and SetScissors
functions.
For OpenGL, however, this requires a little more effort. The idea is to convert the GLVertexArrayObject
member variable in GLVertexBuffer
into shared pointer. Then all vertex buffers used in a call to SetVertexBuffers
refer to the same VAO. When these buffers are used in the SetVertexBuffers
function for the first time, this VAO is created 'on the fly'. When they are used together once more, this VAO can be reused. This allows to dynamically change the vertex buffers without letting the client programmer manage a BufferArray
object.
Caveat:
To make a buffer usable for multiple sets of vertex buffers, each GLVertexBuffer
must hold a container of shared pointers. Otherwise, some VAOs could be created and deleted every frame :-(
So either each GLVertexBuffer
needs this list, which must be iterated for each buffer used in the SetVertexBuffers
function, or some sort of hash map must be involved to quickly find the correct VAO for a set of buffers.
Alternative 1:
Get rid of all ...Array
interfaces except of BufferArray
(but only for vertex buffer arrays).
Alternative 2:
Both SetVertexBufferArray
and SetVertexBuffers
are supported. The former one is supported for optimization purposes and the latter one is supported for flexibility purposes.
Update (12/07/2018):
Maybe the GL_ARB_vertex_attrib_binding extension can help here.
Would you like to replace any double quotes by angle brackets around file names for include statements?
D3DResourceViewHeapSegment2
& -1
are falsely reversed.
Type is already LinuxGLContext
at c'tor parameter.
Does LLGL have support for host memory allocations callbacks ? Such as VkAllocationCallbacks for vulkan? How about other apis (dx, ogl, etc) and other library allocations ?
If not, is this planned ?
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?
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 ?
It seems that if you want to set the uniforms are not stored in the deferred command buffer for opengl.
@LukasBanana help wanted ?
Hardware accelerated functions for copy, clear and map Buffer
and Texture
objects should be added to the RenderSystem
and CommandBuffer
interface.
Concept for Buffer
:
// Todo (use 'glClearBufferSubData' for GL renderer)
void CommandBuffer::FillBuffer(
Buffer& dstBuffer,
std::uint64_t dstOffset,
std::uint32_t value,
std::uint64_t fillSize
);
// Done
void CommandBuffer::CopyBuffer(
Buffer& dstBuffer,
std::uint64_t dstOffset,
Buffer& srcBuffer,
std::uint64_t srcOffset,
std::uint64_t size
);
// Done
void* RenderSystem::MapBuffer(Buffer& buffer, const BufferCPUAccess access);
void RenderSystem::UnmapBuffer(Buffer& buffer);
Progress overview:
FillBuffer
CopyBuffer
CopyBufferFromTexture
MapBuffer
/ UnmapBuffer
CopyTexture
CopyTextureFromBuffer
Start/stop of command recording must be part of the CommandBuffer
interface instead of the CommandQueue
interface. The submission of the command buffers to the command queue should also become explicit.
Before:
cmdQueue->Begin(*cmdBuffer);
/* ... */
cmdQueue->End(*cmdBuffer);
context->Present();
After:
cmdBuffer->Begin();
/* ... */
cmdBuffer->End();
cmdQueue->Submit(*cmdBuffer);
context->Present();
Command recording is independent of the command queue and must be part of the CommandBuffer
interface, to allow multi-threaded command recording (aka. encoding) in a later version of LLGL.
The CommandQueue
interface should also get a secondary Submit
function to submit multiple command buffers at once:
void Submit(
std::size_t numCommandBuffers,
CommandBuffer* const* commandBuffers
);
All of this is a preparation for better support of encoding multiple command buffers to benefit from the latest rendering APIs.
Metal has no function to clear the framebuffer attachments on demand. They can only be cleared when a new render-pass begins.
The same functionality is provided in Vulkan, even though it provides the functionality to clear the color attachments on demand, too.
The new RenderPass
interface will be used for the GraphicsPipelineDescriptor
structure instead of the RenderTarget
interface to specfiy the color attachment formats.
Proposal:
enum class AttachmentLoadOp {
Undefined, // Vulkan: VK_ATTACHMENT_LOAD_OP_DONT_CARE
Load, // Vulkan: VK_ATTACHMENT_LOAD_OP_CLEAR
Clear, // Vulkan: VK_ATTACHMENT_LOAD_OP_CLEAR
};
enum class AttachmentStoreOp {
Undefined, // Vulkan: VK_ATTACHMENT_STORE_OP_DONT_CARE
Store, // Vulkan: VK_ATTACHMENT_STORE_OP_STORE
};
struct AttachmentFormatDescriptor {
Format format = Format::Undefined;
AttachmentLoadOp loadOp = AttachmentLoadOp::Undefined;
AttachmentStoreOp storeOp = AttachmentStoreOp::Undefined;
};
struct RenderPassDescriptor {
std::vector<AttachmentFormatDescriptor> colorAttachments; // e.g. Format::RGBA8UNorm
AttachmentFormatDescriptor depthAttachment; // e.g. Format::D24UNormS8UInt
AttachmentFormatDescriptor stencilAttachment; // e.g. Format::D24UNormS8UInt
};
struct GraphicsPipelineDescriptor {
ShaderProgram* shaderProgram = nullptr;
PipelineLayout* pipelineLayout = nullptr;
RenderPass* renderPass = nullptr;
/* ... */
};
class CommandBuffer {
/* ... */
void BeginRenderPass(
RenderPass& renderPass,
RenderTarget& renderTarget,
std::uint32_t numClearValues = 0,
const ClearValue* clearValues = nullptr
);
void EndRenderPass();
};
The render pass will replace the SetRenderTarget
functions and RenderContext
will finally inherit from RenderTarget
:
Before:
myCmdBuffer->SetClearColor({ 1.0f, 0.0f, 0.0f, 1.0f });
myCmdBuffer->SetRenderTarget(*myRenderTarget);
myCmdBuffer->Clear(LLGL::Color);
/* ... */
myCmdBuffer->SetRenderTarget(*myRenderContext);
myCmdBuffer->Clear(LLGL::Color);
/* ... */
myRenderContext->Present();
After:
LLGL::ClearValue clearValue;
clearValue.color = { 1.0f, 0.0f, 0.0f, 1.0f };
myCmdBuffer->BeginRenderPass(*myRenderPass, *myRenderTarget, 1, &clearValue);
/* ... */
myCmdBuffer->EndRenderPass();
myCmdBuffer->BeginRenderPass(*myRenderPass, *myRenderContext, 1, &clearValue);
/* ... */
myCmdBuffer->EndRenderPass();
myRenderContext->Present();
Hello. Will support for SDL, X11 (Linux/Unix), and GLFW backends window support? Also, will support of Vulkan API? I very wait for Vulkan API support, as DirectX 12 too.
hello lukas, i found LLGL hard to run example on Mac xcode.
So I've been using the basic triangle program as my baseline for ensuring all of the systems I'm implementing for Firestorm are working properly, and I'm hitting a bit of a snag. Where it used to render the triangle properly it is now simply showing me a black screen. I've looked at the source code for the existing Triangle program and everything seems to match up, however my version is not rendering the triangle for whatever reason.
I do have a few layers of abstraction in my implementation, however outside of the asynchronous loading of the shader resources (using std::async at the moment and having it simply load up the source code for it to be compiled on the main thread as seen in the line resource->Compile({vertexFormat});
), everything is fairly straightforward.
The source code for the base application class, the program's implementation of that class, and the ResourceMgr class as well as the associated ShaderLoader class that runs the asynchronous loading are all attached. The ShaderResource class is also included so that you can see how I'm loading up the shader resources.
To be honest, this issue has me stumped as I'm still a newbie when it comes to graphics programming and I would really appreciate anyone's assistance in this matter. The shader itself is simple and the differences between the existing triangle shader and the version that's implied by the code here came about as part of my debugging. It wasn't working with the existing version of the shader either. Vector2 and Vector4 are both simple structs with float x, y
and float x,y,z,w
as you'd expect. Nothing weird going on in there except for a few explicit constructors for Vector2 to take in either a Vector3 or Vector4 for initialization data.
class Vector2
{
public:
Vector2(float x = 0.0f, float y = 0.0f);
explicit Vector2(const Vector3& v);
explicit Vector2(const Vector4& v);
float x, y;
};
class Vector3
{
public:
Vector3(float x = 0.0f, float y = 0.0f, float z = 0.0f);
Vector3(const Vector2& v2d, float z = 0.0f);
explicit Vector3(const Vector4& v2d);
float x, y, z;
};
class Vector4
{
public:
Vector4(float x = 0.0f, float y = 0.0f, float z = 0.0f, float w=0.0f);
Vector4(const Vector2& v, float z = 0.0f, float w = 0.0f);
Vector4(const Vector3& v, float w = 0.0f);
float x, y, z, w;
};
I found two problems with the vulkan rendering backend on Windows.
VKCommandBuffer.cpp.obj : error LNK2019: unresolved external symbol _vkCmdBeginTransformFeedbackEXT@20 referenced in function "public: virtual void __thiscall LLGL::VKCommandBuffer::BeginStreamOutput(unsigned int,class LLGL::Buffer * const *)" (?BeginStreamOutput@VKCommandBuffer@LLGL@@UAEXIPBQAVBuffer@2@@Z) VKCommandBuffer.cpp.obj : error LNK2019: unresolved external symbol _vkCmdEndTransformFeedbackEXT@20 referenced in function "public: virtual void __thiscall LLGL::VKCommandBuffer::EndStreamOutput(void)" (?EndStreamOutput@VKCommandBuffer@LLGL@@UAEXXZ) VKCommandBuffer.cpp.obj : error LNK2019: unresolved external symbol _vkCmdBeginConditionalRenderingEXT@8 referenced in function "public: virtual void __thiscall LLGL::VKCommandBuffer::BeginRenderCondition(class LLGL::QueryHeap &,unsigned int,enum LLGL::RenderConditionMode)" (?BeginRenderCondition@VKCommandBuffer@LLGL@@UAEXAAVQueryHeap@2@IW4RenderConditionMode@2@@Z) VKCommandBuffer.cpp.obj : error LNK2019: unresolved external symbol _vkCmdEndConditionalRenderingEXT@4 referenced in function "public: virtual void __thiscall LLGL::VKCommandBuffer::EndRenderCondition(void)" (?EndRenderCondition@VKCommandBuffer@LLGL@@UAEXXZ)
Add the following functions to support texture resource views:
class RenderSystem {
// Creates a resource view for the source texture
// using the same <Texture> interface for seamless interoperability.
Texture* CreateTextureView(Texture& sourceTexture, const TextureViewDescriptor& desc);
/* ... */
};
class Texture {
// Returns true if this texture is a resource view and not the original texture
bool IsResourceView() const;
/* ... */
};
This will also replace the secondary version of the GenerateMips
function (which currently generates resource views on demand).
For OpenGL, this is only supported if the GL_ARB_texture_view
extension is available on the host platform.
For D3D11, D3D12, and Vulkan there is a respective resource view interface (e.g. VkImageView
or ID3D11ShaderResourceView
).
For Metal, the same interface MTLTexture
is used for both textures and texture-views.
Only the debug layer will keep track of all resource views that refer to a source texture. When a source texture is released, and any of its resource views is still used, the debug layer will throw an error message.
EDIT:
Instead of making texture views part of the Texture
interface, they are probably better suited for the ResourceHeap
interface. Also simplifies the way of creating multiple different views of the same texture object.
Maybe the enumeration LLGL::BufferType
should be replaced by LLGL::BufferFlags
with additional entries to specifiy one or more purposes for binding a buffer.
This will require a lot of refactoring especially in the D3D11 backend because there are multiple sub-classes of D3D11Buffer
, e.g. D3D11ConstantBuffer
.
This is especially helpful with the upcoming interface for indirect draw/dispatch commands. The enum BufferType
and member BufferDescriptor::type
will be replaced by three new enums:
LLGL::BufferDescriptor myDesc;
myDesc.size = /* ... */;
myDesc.bindFlags = LLGL::BindFlags::RWStorageBuffer | LLGL::BindFlags::IndirectBuffer;
myDesc.cpuAccessFlags = LLGL::CPUAccessFlags::ReadWrite;
myDesc.miscFlags = LLGL::MiscFlags::DynamicUsage;
auto myBuffer = myRenderer->CreateBuffer(myDesc);
All these flags will also be available in the TextureDescriptor
struct, but here the TextureType
enum and type
member will remain.
Because the dedicated sub-classes for vertex buffers typically have more payload than the other buffers, the new sub-class hierarchy could look like this:
Buffer
|- GLBuffer
| `- GLBufferWithVAO (for vertex buffers)
|- D3D11Buffer
| `- D3D11BufferWithRV (for storage buffers)
|- ...
...
Indirect draw and dispatch commands as well as their respective buffer types should be added.
Concept:
enum class BufferType {
Vertex,
Index,
Constant,
Storage,
StreamOutput,
DrawIndirect, // New buffer type for indirect draw commands
DispatchIndirect, // New buffer type for indirect dispatch commands
};
For the case the rendering APIs have slightly different buffer formats for these commands, individual structures for each backend must be provided. Otherwise, a uniform structure can be used:
struct DrawIndirectFormat {
std::uint32_t numVertices;
std::uint32_t numInstances;
std::uint32_t firstVertex;
std::uint32_t firstInstance;
};
struct DrawIndexedIndirectFormat {
std::uint32_t numIndices;
std::uint32_t numInstances;
std::uint32_t firstIndex;
std::int32_t vertexOffset;
std::uint32_t firstInstance;
};
struct DispatchIndirectFormat {
std::uint32_t groupSizeX;
std::uint32_t groupSizeY;
std::uint32_t groupSizeZ;
};
The functions in the CommandBuffer
interface may look like this:
void DrawIndirect(Buffer& buffer, std::uint64_t offset);
void DrawIndexedIndirect(Buffer& buffer, std::uint64_t offset);
void DispatchIndirect(Buffer& buffer, std::uint64_t offset);
The parameter buffer
specifies a buffer that contains the draw/dispatch command arguments and the parameter offset
specifies an aligned byte offset within the buffer for command arguments.
Progress overview:
DrawIndirect
DrawIndexedIndirect
DispatchIndirect
Must be GLFramebuffer::AttachTextureLayer
instead.
glFramebufferTexture3D
only allows GL_TEXTURE_3D
as texture-target.
Instead of automatic generation of multi-sampled attachments that get resolved into the actual render target attachments, the user should be able to specify their custom multi-sampled textures. For OpenGL, a Texture
that has not the BindFlags::Sampled
flag bit, a renderbuffer should be used internally, which is currently only done in GLRenderTarget
for the auto.-generated multi-sampled attachments. This feature should be optional, though, and not required for convenience.
Before:
struct RenderTargetDescriptor
{
const RenderPass* renderPass = nullptr;
Extent2D resolution;
std::uint32_t samples = 1;
bool customMultiSampling = false;
std::vector<AttachmentDescriptor> attachments;
};
After:
struct RenderTargetDescriptor
{
const RenderPass* renderPass = nullptr;
Extent2D resolution;
AttachmentDescriptor colorAttachments[8];
AttachmentDescriptor resolveAttachments[8];
AttachmentDescriptor depthStencilAttachment;
};
The samples
parameter is taken from the specified (or default) render pass, i.e. RenderPassDescriptor::samples
.
Shader
and ShaderProgram
interfaces should be refactored to follow the 'descriptor at creation time' principle.
Attaching, detaching, and re-compiling shaders does not work properly for Direct3D and Vulkan.
Moreover, it has only been adopted from the deprecated interface of OpenGL (like with glAttachShader
).
In the new interface, the shaders must be compiled at creation time:
enum class ShaderSourceType {
CodeString, // Refers to <const char[sourceSize + 1]> describing shader code (with '\0')
CodeFile, // Refers to <const char[sourceSize + 1]> describing shader code file (with '\0')
BinaryBuffer, // Refers to <const char[sourceSize]> describing shader binary
BinaryFile // Refers to <const char[sourceSize + 1]> describing shader binary file (with '\0')
};
struct ShaderDescriptor {
ShaderDescriptor();
ShaderDescriptor(
ShaderType type,
const char* source,
std::size_t sourceSize = 0
);
ShaderDescriptor(
ShaderType type,
const char* source,
std::size_t sourceSize,
const char* entryPoint,
const char* profile
);
struct StreamOutput {
StreamOutputFormat format;
};
ShaderType type = ShaderType::Undefined;
const char* source = nullptr; // points to the source code or filename
std::size_t sourceSize = 0; // length of the source (excluding a null terminator!)
ShaderSourceType sourceType = ShaderSourceType::CodeFile;
const char* entryPoint = nullptr;
const char* profile = nullptr; // previously called target, but profile fits better
long flags = 0;
StreamOutput streamOutput;
};
struct GraphicsShaderProgramDescriptor {
std::vector<VertexFormat> vertexFormats;
Shader* vertexShader = nullptr;
Shader* tessControlShader = nullptr;
Shader* tessEvaluationShader = nullptr;
Shader* geometryShader = nullptr;
Shader* fragmentShader = nullptr;
};
struct ComputeShaderProgramDescriptor {
Shader* computeShader = nullptr;
};
class RenderSystem {
Shader* CreateShader(const ShaderDescriptor& desc);
ShaderProgram* CreateShaderProgram(const GraphicsShaderProgramDescriptor& desc);
ShaderProgram* CreateShaderProgram(const ComputeShaderProgramDescriptor& desc);
/* ... */
};
Functions that will be removed from the interfaces:
class Shader {
bool Compile(const std::string&, const ShaderDescriptor&);
bool LoadBinary(std::vector<char>&&, const ShaderDescriptor&);
/* ... */
};
class ShaderProgram {
void AttachShader(Shader&);
void DetachAll();
bool LinkShaders();
void BuildInputLayout(std::uint32_t, const VertexFormat*);
/* ... */
};
Functions that will be added to the interfaces:
class Shader {
bool HasErrors() const;
/* ... */
};
class ShaderProgram {
bool HasErrors() const;
/* ... */
};
Example usage:
LLGL::GraphicsShaderProgramDescriptor myGfxProgramDesc;
{
myGfxProgramDesc.vertexFormats = { myVertexFormat };
myGfxProgramDesc.vertexShader = myRenderer->CreateShader({ LLGL::ShaderType::Vertex, "myVertexShader.vert" });
myGfxProgramDesc.fragmentShader = myRenderer->CreateShader({ LLGL::ShaderType::Fragment, "myFragmentShader.frag" });
}
auto myShaderProgram = myRenderer->CreateShaderProgram(myGfxProgramDesc);
The D3D11 renderer currently does not support depth textures (i.e. format TextureFormat::D32
and TextureFormat::D24S8
from the latest "vulkan"-branch).
Notes:
Depth textures in D3D11 can have more than one MIP-map, but the GenerateMips
function cannot be used with them when they have the bind flag D3D11_BIND_DEPTH_STENCIL
.
This, however, is only required when the depth-texture is used as depth-stencil attachment (i.e. LLGL::TextureFlags::DepthStencilAttachmentUsage
).
ResourceHeap
currently only supports one set of resource views that are always bound at once.
It should be extended to provide a functionality similar to the descriptor heap in D3D12, which stores an arbitrary number of descriptors in one heap.
The number of resources that are bound with SetResourceHeap
will depend on the pipeline layout of the actively bound pipeline state.
SetResourceHeap
should then have an optional parameter to specify the first resource within the heap.
Moreover, the parameter firstSet
should be moved into BindingDescriptor
structure:
void SetResourceHeap(
ResourceHeap& resourceHeap,
std::uint32_t firstResource = 0,
const PipelineBindPoint bindPoint = PipelineBindPoint::Undefined
);
How to implement a extendible material system on dx11, use ConstBuffer?
Miscellaneous scheduled features:
GenerateMips
function with parameters for a range of MIP-levels and array slices.D3D11StateManager
to avoid redundant calls to VSSetShader
etc.BufferType
entries.ShaderDescriptor::fragment::outputAttribs
.The RenderSystem
should keep its functions to read and write buffers. However, the same functions should be added to the CommandBuffer
interface (or similar name) to be used in a different situation.
Since the modern APIs require to explicitly submit command buffers, buffer updates do not become visible in the same order as the drawing commands are encoded. Consider the following example:
// Render model M with transformation matrix X
renderer->WriteBuffer(*constantBuffer, ...);
cmdBuffer->Draw(...);
// Render model M with transformation matrix Y
renderer->WriteBuffer(*constantBuffer, ...);
cmdBuffer->Draw(...);
This won't work with Vulkan for instance, since the content of constantBuffer
is modified multiple times during the command encoding but the commands have not yet been submitted to the GPU.
This, however, can be achieved by writing the content, the buffer is to be updated with, directly into the command buffer (e.g. with vkCmdUpdateBuffer
for Vulkan). Therefore, the WriteBuffer
function should also be part of the CommandBuffer
interface to update constant buffers during rendering.
The old WriteBuffer
function in the RenderSystem
interface can then only be used outside of command encoding and submitting command buffers must be scheduled properly by the client programmer.
Proposal:
// Update large buffers
renderer->WriteBuffer(*largeStorageBuffer, ...);
// Render
cmdBuffer->Begin();
{
// Render model M with transformation X
cmdBuffer->WriteBuffer(*smallConstantBuffer, ...);
cmdBuffer->BeginRenderPass(...);
{
cmdBuffer->Draw(...);
}
cmdBuffer->EndRenderPass();
// Render model M with transformation Y
cmdBuffer->WriteBuffer(*smallConstantBuffer, ...);
cmdBuffer->BeginRenderPass(...);
{
cmdBuffer->Draw(...);
}
cmdBuffer->EndRenderPass();
}
cmdBuffer->End();
cmdQueue->Submit(*cmdBuffer);
context->Present();
Caveat:
vkCmdUpdateBuffer
can only appear outside of a render pass.vkCmdUpdateBuffer
can only update buffers with a maximum size of 65536 bytes (i.e. primarily useful for constant buffers only).I couldn't find any statement on the minimum version of OpenGL that LLGL is written for. While working with the sample Cpp programs I noticed that LLGL always enables GL_TEXTURE_CUBE_MAP_SEAMLESS which is a 3.2 feature and GL_PRIMITIVE_RESTART_FIXED_INDEX which is a 4.3 feature. On earlier versions either of these calls could cause an INVALID_ENUM error to be logged.
Since the OpenGL on the Mac is frozen at version 4.1 GL_PRIMITIVE_RESTART_FIXED_INDEX doesn't work. I'm trying to re-implement this using GL_PRIMITIVE_RESTART but that requires a minimum version of 3.1. Can 3.1 features be invoked unconditionally?
When running the Multi-Threading example (in debug mode) using the DirectX12 renderer I got the following error:
D3D12 ERROR: ID3D12CommandQueue::ExecuteCommandLists: A command list, which writes to a swapchain back buffer, may only be executed when that back buffer is the back buffer that will be presented during the next call to Present*. Such a back buffer is also referred to as the "current back buffer". Swap Chain: 0x0000022962A35080:'Unnamed Object' - Current Back Buffer Buffer: 0x0000022961DA41B0:'Unnamed ID3D12Resource Object' - Attempted Write Buffer: 0x0000022961DA6880:'Unnamed ID3D12Resource Object' [ STATE_SETTING ERROR #907: EXECUTECOMMANDLISTS_WRONGSWAPCHAINBUFFERREFERENCE]
D3D12: Removing Device.
D3D12 ERROR: ID3D12Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_ACCESS_DENIED: The application attempted to use a resource it does not access to. This could be, for example, rendering to a texture while only having read access.). [ EXECUTION ERROR #232: DEVICE_REMOVAL_PROCESS_AT_FAULT]
Console output:
selected renderer: Direct3D12
render system:
renderer: Direct3D 11.1
device: NVIDIA GeForce RTX 2060 SUPER
vendor: NVIDIA Corporation
shading language: HLSL 6.0
render context:
resolution: 800 x 600
samples: 8
colorFormat: RGBA8UNorm
depthStencilFormat: D24UNormS8UInt
Enter thread: mainThread
Leave thread: mainThread
failed to present DXGI swap chain (error code = DXGI_ERROR_DEVICE_REMOVED)
D3D12 always requires an explicit buffer resource for the results of a query heap.
OpenGL added a buffer type GL_QUERY_BUFFER
so the query results can be used in a shader.
This functionality should be added to LLGL.
Proposal:
enum class BufferType {
/* ... */
QueryResult,
};
struct BufferFlags {
enum {
/* ... */
// Force creation of query buffer also for GL backend.
// Otherwise, the buffer is only created for D3D12.
QueryShaderReadAccess = (1 << 3),
};
};
class CommandBuffer {
/* ... */
void ResolveQuery(
Buffer& dstBuffer,
std::uint64_t dstOffset,
QueryHeap& srcQueryHeap,
std::uint32_t firstQuery,
std::uint32_t numQueries
);
};
Example:
myCmdBuffer->Begin();
myCmdBuffer->BeginRenderPass();
myCmdBuffer->BeginQuery(*myQuery, 0);
/* ... */
myCmdBuffer->EndQuery(*myQuery, 0);
myCmdBuffer->EndRenderPass();
myCmdBuffer->ResolveQuery(*myResultBuffer, 0, *myQuery, 0, 1);
myCmdBuffer->End();
myCmdQueue->Submit(*myCmdBuffer);
std::uint64_t result = 0;
if (myCmdQueue->QueryResult(*myQuery, 0, 1, &result, sizeof(result))) {
/* ... */
}
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?
Replace the ShaderProgram
interface and use Shader
instances individually in various combinations for a GraphicsPipeline
:
Before:
LLGL::ShaderProgramDescriptor myProgramDesc;
myProgramDesc.vertexShader = myVertShader;
myProgramDesc.fragmentShader = myFragShader;
LLGL::ShaderProgram* myShaderProgram = myRenderer->CreateShaderProgram(myProgramDesc);
LLGL::GraphicsPipelineDescriptor myPipelineDesc;
myPipelineDesc.shaderProgram = myShaderProgram;
/* ... */
After:
LLGL::GraphicsPipelineDescriptor myPipelineDesc;
myPipelineDesc.vertexShader = myVertShader;
myPipelineDesc.fragmentShader = myFragShader;
/* ... */
For OpenGL there need to be two paths implemented:
GL_ARB_separate_shader_objects
extension.GLShaderProgram
implementation will remain as internal class as fallback when the extension (see 1.) is not available.All the shader reflection will move into Shader
interface, which might be a bit chellenging for the 2nd case for OpenGL, because all shader related glGet*
function need a shader program, i.e. a dummy shader program needs to be created, e.g. with a dummy vertex or fragment shader.
RenderSystem
interface should be renamed to Device
and RenderContext
should be renamed to SwapChain
.
Along this renaming, the RenderContextDescriptor
, VsyncDescriptor
and VideoModeDescriptor
should be merged into SwapChainDescriptor
like this:
Before:
struct VsyncDescriptor {
bool enabled = false;
std::uint32_t refreshRate = 60;
std::uint32_t interval = 1;
};
struct VideoModeDescriptor {
Extent2D resolution;
int colorBits = 32;
int depthBits = 24;
int stencilBits = 8;
bool fullscreen = false;
std::uint32_t swapChainSize = 2;
};
struct RenderContextDescriptor {
VsyncDescriptor vsync;
std::uint32_t samples = 1;
VideoModeDescriptor videoMode;
};
After:
struct SwapChainDescriptor {
Extent2D resolution;
int colorBits = 32;
int depthBits = 24;
int stencilBits = 8;
bool fullscreen = false;
std::uint32_t swapBuffers = 2;
// std::uint32_t refreshRate = 60; // Refresh rate is display dependent and should not be an option here
std::uint32_t samples = 1;
std::uint32_t vsyncInterval = 0;
};
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?
Hi.
Thanks for for sharing this beautiful library with us. I would be glad to help this project with contributions. But I don't know which parts aren't implemented or need maintenance.
In readme file, project progress described with percentage. For example ~30% of Vulkan renderer is complete. Unfortunately percentage is not enough for new contributors. Isn't it better to create todo list of which parts are not done?
Good news is that github already has that feature in Projects tab.
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
The event handler is trying to catch 'DestroyNotify'. Without having the code tested on an actual linux machine, there's probably a mistake.
I am not sure whether this last point should belong to the former one:
See here
One thing I've found extremely useful while working with various Open Source projects is the ability to have a community to talk to, including the very same authors.
LLGL at the current state does not offer any kind of Discussion channel around this project. My proposal would be to either consider one of these following options:
Although it's very used and popular, most of the people today are no more keen to download, install or use IRC in general. I would personally NOT suggest this option.
Although this platform is very popular among Developers, it's not really the best platform to chat into. Lack of rooms, is definitely a CONs. One of the biggest PROs is definitely the fact that to start chatting most probably the users already do have one of the required accounts to login.
Pretty much used by gamers, but not only to. For eg. Microsoft is one of those having a Discord channel supporting also Developers. The fact you can create rooms and have also vocal rooms makes this definitely a very good platform to get in touch, also with non-written communication.
I would like to use this issue to solve and ideally choose the right platform in order to get in touch. I already have some questions regarding LLGL and Shader loading, but I fear I would fill the issue list a lot, and maybe not all the users may find it useful. As well as you being distracted by "managing issues" than actually focusing on the real problems.
Thank you in advance if you ever consider this!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.