Skip to content

Commit

Permalink
Merge pull request #142 from crud89/integrate-pr140
Browse files Browse the repository at this point in the history
Port over platform independent changes from PR #140.
  • Loading branch information
crud89 authored Nov 7, 2024
2 parents af56e9c + 5ed7f87 commit f2a3efa
Show file tree
Hide file tree
Showing 53 changed files with 229 additions and 262 deletions.
129 changes: 3 additions & 126 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,130 +56,11 @@ LiteFX is written in modern C++23, following established design patterns to make
- **CMake Integration**: you can use CMake to integrate the engine into your project. Furthermore, it exports scripts that allow you to integrate assets and shaders into your build process. It can be installed using *vcpkg*, making project setup quick and painless.
- **Much More**: If you want to learn what else you can do, check out the [guides](https://litefx.crudolph.io/docs/md_docs_tutorials_project_setup.html) and [wiki](https://github.com/crud89/LiteFX/wiki).
## Installation
If you just want to start using LiteFX, you can acquire binaries of the latest version from the [releases page](https://github.com/crud89/LiteFX/releases) and follow the [project setup](https://litefx.crudolph.io/docs/md_docs_tutorials_project_setup.html) and [quick start](https://litefx.crudolph.io/docs/md_docs_tutorials_quick_start.html) guides.
### Using vcpkg
If you are using vcpkg, you can use the [registry](https://github.com/crud89/LiteFX-Registry) to install the engine directly.
### Manual Builds
You can also build the sources on your own. Currently only MSVC and Clang builds under Windows are officially supported. However, the engine does use CMake and (besides the DirectX 12 backend) no Windows-specific features, so porting the Vulkan backend and engine architecture should be absolutely possible (pull requests are much appreciated!).
#### Prerequisites
In order for the project to be built, there are a few prerequisites that need to be present on your environment:
- [C++23 compatible compiler](https://en.cppreference.com/w/cpp/compiler_support/23): At the moment only MSVC and Clang 18+ fully supports the required features. †
- [CMake](https://cmake.org/download/) (version 3.20 or higher). ‡
- Optional: [LunarG Vulkan SDK](https://vulkan.lunarg.com/) 1.3.204.1 or later (required to build the Vulkan backend).
- Optional: Windows 10 SDK 10.0.19041.0 or later (required to build DirectX backend).
† Note that at least Visual Studio 17.10 or later is required.
‡ CMake 3.20 is part of Visual Studio 2022. When using other compilers, CMake needs to be installed manually.
#### Cloning the Repository
Create a new directory from where you want to build the sources. Then open your shell and clone the repository:
```sh
git clone --recursive https://github.com/crud89/LiteFX.git .
```

#### Performing a Build

There are multiple ways of creating a build from scratch. In general, all *CMake*-based build systems are supported.

##### From Command Line

Building from command line is the most straightforward way and is typically sufficient, if you only want to consume a fresh build.

```sh
cmake src/ --preset windows-msvc-x64-release
cmake --build out/build/windows-msvc-x64-release/ --target install
```

##### Using Visual Studio

From Visual Studio open the folder where you just checked out the contents of the repository. In the *Project Explorer* change the view to *CMake Targets*. Right click *LiteFX* and select *Install*.

#### Build Customization

You can customize the engine build, according to your specific needs. The most straightforward way is to use [*CMake presets*](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html). Create a file called *CMakeUserPresets.json* inside the *src/* directory and add the following content to it:

```json
{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "win-x64-custom-preset",
"inherits": "windows-msvc-x64-release",
"cacheVariables": {
}
}
]
}
```

Within the cache variables, you can override the build options, LiteFX exports. All customizable options have the `LITEFX_BUILD_` prefix and are described in detail below:

- `LITEFX_BUILD_VULKAN_BACKEND` (default: `ON`): builds the Vulkan 🌋 backend (requires [LunarG Vulkan SDK](https://vulkan.lunarg.com/) 1.3.204.1 or later to be installed on your system).
- `LITEFX_BUILD_DX12_BACKEND` (default: `ON`): builds the DirectX 12 ❎ backend.
- `LITEFX_BUILD_DEFINE_BUILDERS` (default: `ON`): enables the [builder architecture](https://github.com/crud89/LiteFX/wiki/Builders) for backends.
- `LITEFX_BUILD_SUPPORT_DEBUG_MARKERS` (default: `OFF`): implements support for setting debug regions on device queues.
- `LITEFX_BUILD_WITH_GLM` (default: `ON`): adds [glm](https://glm.g-truc.net/0.9.9/index.html) converters to math types. †
- `LITEFX_BUILD_WITH_DIRECTX_MATH` (default: `ON`): adds [DirectX Math](https://github.com/microsoft/DirectXMath) converters to math types. †
- `LITEFX_BUILD_HLSL_SHADER_MODEL` (default: `6_5`): specifies the default HLSL shader model.
- `LITEFX_BUILD_EXAMPLES` (default: `ON`): builds the examples. Depending on which backends are built, some may be omitted.
- `LITEFX_BUILD_EXAMPLES_DX12_PIX_LOADER` (default: `ON`): enables code that attempts to load the latest version of the [PIX GPU capturer](https://devblogs.microsoft.com/pix/) in the DirectX 12 samples, if available (and if the command line argument `--load-pix=true` is specified).
- `LITEFX_BUILD_EXAMPLES_RENDERDOC_LOADER` (default: `OFF`): enables code in the samples, that loads the [RenderDoc](https://renderdoc.org/) runtime API, if the application is launched from within RenderDoc (and if the command line argument `--load-render-doc=true` is specified).
- `LITEFX_BUILD_TESTS` (default: `OFF`): builds tests for the project.

For example, if you only want to build the Vulkan backend and samples and don't want to use DirectX Math, a preset would look like this:

```json
{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "win-x64-vulkan-only",
"inherits": "windows-msvc-x64-release",
"cacheVariables": {
"LITEFX_BUILD_DX12_BACKEND": "OFF",
"LITEFX_BUILD_WITH_DIRECTX_MATH": "OFF"
}
}
]
}
```

You can build using this preset from command line like so:

```sh
cmake src/ --preset win-x64-vulkan-only
cmake --build out/build/win-x64-vulkan-only/ --target install --config Release
```

† Note that *glm* and *DirectX Math* are installed using *vcpkg* automatically. If one of those options gets disabled, no converters will be generated and the dependency will not be exported. Note that both can be used for DirectX 12 and Vulkan.

#### Troubleshooting
## Getting Started
If you are having problems building the project, you may find answers [in the wiki](https://github.com/crud89/LiteFX/wiki/Troubleshooting). Otherwise, feel free to start a [discussion](https://github.com/crud89/LiteFX/discussions/categories/q-a) or open an [issue](https://github.com/crud89/LiteFX/issues).
If you just want to start using LiteFX, you can acquire binaries of the latest version from the [releases page](https://github.com/crud89/LiteFX/releases) and follow the [project setup](https://litefx.crudolph.io/docs/md_docs_tutorials_project_setup.html) and [quick start](https://litefx.crudolph.io/docs/md_docs_tutorials_quick_start.html) guides. If you want to perform a custom build, check out the [building guide](https://github.com/crud89/LiteFX/wiki/Building-Guide). For a collection of tutorials and more in-depth information on how to use the engine and work with the code base, take a look at the [documentation](https://litefx.crudolph.io/docs/) and the [project wiki](https://github.com/crud89/LiteFX/wiki).
### Dependencies
## Dependencies
All dependencies are automatically installed using *vcpkg*, when performing a manual build. The engine core by itself only has one hard dependency:
Expand Down Expand Up @@ -207,10 +88,6 @@ Furthermore, the samples also use some libraries for convenience. Those dependen
- [glfw3](https://www.glfw.org/): Cross-platform window manager.
- [stb](https://github.com/nothings/stb): Lightweight image loading and processing library.
## Getting Started

For a [quick-start guide](https://litefx.crudolph.io/docs/md_docs_tutorials_project_setup.html), a collection of tutorials and more in-depth information on how to use the engine and work with the code base, take a look at the [documentation](https://litefx.crudolph.io/docs/) and the [project wiki](https://github.com/crud89/LiteFX/wiki).

## Contribute
If you are having trouble using the engine, found a bug or have suggestions, just drop an [issue](https://github.com/crud89/LiteFX/issues). Keep in mind that this project is developed in my free time and I might not be able to provide any advanced support. If you want to, feel free to provide improvements by creating a pull request.
Expand Down
10 changes: 5 additions & 5 deletions src/Backends/DirectX12/src/blas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ void DirectX12BottomLevelAccelerationStructure::build(const DirectX12CommandBuff
if (buffer == nullptr)
buffer = m_impl->m_buffer && m_impl->m_buffer->size() >= requiredMemory ? m_impl->m_buffer : device.factory().createBuffer(BufferType::AccelerationStructure, ResourceHeap::Resource, requiredMemory, 1, ResourceUsage::AllowWrite);
else if (maxSize < requiredMemory) [[unlikely]]
throw ArgumentOutOfRangeException("maxSize", std::make_pair(0ull, maxSize), requiredMemory, "The maximum available size is not sufficient to contain the acceleration structure.");
throw ArgumentOutOfRangeException("maxSize", std::make_pair(0_ui64, maxSize), requiredMemory, "The maximum available size is not sufficient to contain the acceleration structure.");
else if (buffer->size() < offset + requiredMemory) [[unlikely]]
throw ArgumentOutOfRangeException("buffer", std::make_pair(0ull, (UInt64)buffer->size()), offset + requiredMemory, "The buffer does not contain enough memory after offset {0} to fully contain the acceleration structure.", offset);
throw ArgumentOutOfRangeException("buffer", std::make_pair(0uz, buffer->size()), offset + requiredMemory, "The buffer does not contain enough memory after offset {0} to fully contain the acceleration structure.", offset);

// Perform the build.
commandBuffer.buildAccelerationStructure(*this, scratchBuffer, *buffer, offset);
Expand Down Expand Up @@ -220,9 +220,9 @@ void DirectX12BottomLevelAccelerationStructure::update(const DirectX12CommandBuf
if (buffer == nullptr)
buffer = m_impl->m_buffer->size() >= requiredMemory ? m_impl->m_buffer : device.factory().createBuffer(BufferType::AccelerationStructure, ResourceHeap::Resource, requiredMemory, 1, ResourceUsage::AllowWrite);
else if (maxSize < requiredMemory) [[unlikely]]
throw ArgumentOutOfRangeException("maxSize", std::make_pair(0ull, maxSize), requiredMemory, "The maximum available size is not sufficient to contain the acceleration structure.");
throw ArgumentOutOfRangeException("maxSize", std::make_pair(0_ui64, maxSize), requiredMemory, "The maximum available size is not sufficient to contain the acceleration structure.");
else if (buffer->size() < offset + requiredMemory) [[unlikely]]
throw ArgumentOutOfRangeException("buffer", std::make_pair(0ull, (UInt64)buffer->size()), offset + requiredMemory, "The buffer does not contain enough memory after offset {0} to fully contain the acceleration structure.", offset);
throw ArgumentOutOfRangeException("buffer", std::make_pair(0uz, buffer->size()), offset + requiredMemory, "The buffer does not contain enough memory after offset {0} to fully contain the acceleration structure.", offset);

// Perform the update.
commandBuffer.updateAccelerationStructure(*this, scratchBuffer, *buffer, offset);
Expand Down Expand Up @@ -257,7 +257,7 @@ void DirectX12BottomLevelAccelerationStructure::copy(const DirectX12CommandBuffe
if (buffer == nullptr)
buffer = destination.m_impl->m_buffer->size() >= requiredMemory ? destination.m_impl->m_buffer : device.factory().createBuffer(BufferType::AccelerationStructure, ResourceHeap::Resource, requiredMemory, 1, ResourceUsage::AllowWrite);
else if (buffer->size() < offset + requiredMemory) [[unlikely]]
throw ArgumentOutOfRangeException("buffer", std::make_pair(0ull, (UInt64)buffer->size()), offset + requiredMemory, "The buffer does not contain enough memory after offset {0} to fully contain the acceleration structure.", offset);
throw ArgumentOutOfRangeException("buffer", std::make_pair(0uz, buffer->size()), offset + requiredMemory, "The buffer does not contain enough memory after offset {0} to fully contain the acceleration structure.", offset);

// Store the buffer and the offset.
destination.m_impl->m_offset = offset;
Expand Down
28 changes: 18 additions & 10 deletions src/Backends/DirectX12/src/buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,20 @@ UInt64 DirectX12Buffer::virtualAddress() const noexcept

void DirectX12Buffer::map(const void* const data, size_t size, UInt32 element)
{
if (data == nullptr) [[unlikely]]
throw ArgumentNotInitializedException("data", "The data pointer must be initialized.");

if (element >= m_impl->m_elements) [[unlikely]]
throw ArgumentOutOfRangeException("element", std::make_pair(0u, m_impl->m_elements), element, "The element {0} is out of range. The buffer only contains {1} elements.", element, m_impl->m_elements);

if (this->size() - (element * this->alignedElementSize()) < size) [[unlikely]]
throw InvalidArgumentException("size", "The provided data size would overflow the buffer (buffer offset: 0x{1:X}; {2} bytes remaining but size was set to {0}).", size, element * this->alignedElementSize(), this->size() - (element * this->alignedElementSize()));

D3D12_RANGE mappedRange = { };
char* buffer;
raiseIfFailed(this->handle()->Map(0, &mappedRange, reinterpret_cast<void**>(&buffer)), "Unable to map buffer memory.");
auto result = ::memcpy_s(reinterpret_cast<void*>(buffer + (element * this->alignedElementSize())), this->size(), data, size);
std::memcpy(reinterpret_cast<void*>(buffer + (element * this->alignedElementSize())), data, size);
this->handle()->Unmap(0, nullptr);

if (result != 0) [[unlikely]]
throw RuntimeException("Error mapping buffer to device memory: {#X}.", result);
}

void DirectX12Buffer::map(Span<const void* const> data, size_t elementSize, UInt32 firstElement)
Expand All @@ -108,20 +111,25 @@ void DirectX12Buffer::map(Span<const void* const> data, size_t elementSize, UInt

void DirectX12Buffer::map(void* data, size_t size, UInt32 element, bool write)
{
if (data == nullptr) [[unlikely]]
throw ArgumentNotInitializedException("data", "The data pointer must be initialized.");

if (element >= m_impl->m_elements) [[unlikely]]
throw ArgumentOutOfRangeException("element", std::make_pair(0u, m_impl->m_elements), element, "The element {0} is out of range. The buffer only contains {1} elements.", element, m_impl->m_elements);

if (this->size() - (element * this->alignedElementSize()) < size) [[unlikely]]
throw InvalidArgumentException("size", "The provided data size would overflow the buffer (buffer offset: 0x{1:X}; {2} bytes remaining but size was set to {0}).", size, element * this->alignedElementSize(), this->size() - (element * this->alignedElementSize()));

D3D12_RANGE mappedRange = { };
char* buffer;
raiseIfFailed(this->handle()->Map(0, &mappedRange, reinterpret_cast<void**>(&buffer)), "Unable to map buffer memory.");
auto result = write ?
::memcpy_s(reinterpret_cast<void*>(buffer + (element * this->alignedElementSize())), this->size(), data, size) :
::memcpy_s(data, size, reinterpret_cast<void*>(buffer + (element * this->alignedElementSize())), size);

this->handle()->Unmap(0, nullptr);
if (write)
std::memcpy(reinterpret_cast<void*>(buffer + (element * this->alignedElementSize())), data, size);
else
std::memcpy(data, reinterpret_cast<void*>(buffer + (element * this->alignedElementSize())), size);

if (result != 0) [[unlikely]]
throw RuntimeException("Error mapping buffer to device memory: {#X}.", result);
this->handle()->Unmap(0, nullptr);
}

void DirectX12Buffer::map(Span<void*> data, size_t elementSize, UInt32 firstElement, bool write)
Expand Down
6 changes: 3 additions & 3 deletions src/Backends/DirectX12/src/frame_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ DirectX12FrameBuffer::~DirectX12FrameBuffer() noexcept = default;
D3D12_CPU_DESCRIPTOR_HANDLE DirectX12FrameBuffer::descriptorHandle(UInt32 imageIndex) const
{
if (imageIndex >= m_impl->m_images.size()) [[unlikely]]
throw ArgumentOutOfRangeException("imageIndex", std::make_pair(0ull, (UInt64)m_impl->m_images.size()), imageIndex, "The frame buffer does not contain an image at index {0}.", imageIndex);
throw ArgumentOutOfRangeException("imageIndex", std::make_pair(0uz, m_impl->m_images.size()), imageIndex, "The frame buffer does not contain an image at index {0}.", imageIndex);

return m_impl->m_renderTargetHandles.at(m_impl->m_images[imageIndex].get());
}
Expand Down Expand Up @@ -170,7 +170,7 @@ size_t DirectX12FrameBuffer::getHeight() const noexcept
void DirectX12FrameBuffer::mapRenderTarget(const RenderTarget& renderTarget, UInt32 index)
{
if (index >= m_impl->m_images.size()) [[unlikely]]
throw ArgumentOutOfRangeException("index", std::make_pair(0ull, (UInt64)m_impl->m_images.size()), index, "The frame buffer does not contain an image at index {0}.", index);
throw ArgumentOutOfRangeException("index", std::make_pair(0uz, m_impl->m_images.size()), index, "The frame buffer does not contain an image at index {0}.", index);

if (m_impl->m_images[index]->format() != renderTarget.format()) [[unlikely]]
LITEFX_WARNING(DIRECTX12_LOG, "The render target format {0} does not match the image format {1} for image {2}.", renderTarget.format(), m_impl->m_images[index]->format(), index);
Expand Down Expand Up @@ -201,7 +201,7 @@ Enumerable<const IDirectX12Image*> DirectX12FrameBuffer::images() const noexcept
const IDirectX12Image& DirectX12FrameBuffer::image(UInt32 index) const
{
if (index >= m_impl->m_images.size()) [[unlikely]]
throw ArgumentOutOfRangeException("index", std::make_pair(0ull, (UInt64)m_impl->m_images.size()), index, "The frame buffer does not contain an image at index {0}.", index);
throw ArgumentOutOfRangeException("index", std::make_pair(0uz, m_impl->m_images.size()), index, "The frame buffer does not contain an image at index {0}.", index);

return *m_impl->m_images[index];
}
Expand Down
6 changes: 3 additions & 3 deletions src/Backends/DirectX12/src/render_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ class DirectX12RenderPass::DirectX12RenderPassImpl : public Implement<DirectX12R
std::ranges::sort(m_renderTargets, [this](const auto& a, const auto& b) { return a.location() < b.location(); });

if (auto match = std::ranges::find_if(m_renderTargets, [](const RenderTarget& renderTarget) { return renderTarget.type() == RenderTargetType::Present; }); match != m_renderTargets.end())
m_presentTarget = match._Ptr;
m_presentTarget = std::addressof(*match);
else
m_presentTarget = nullptr;

if (auto match = std::ranges::find_if(m_renderTargets, [](const RenderTarget& renderTarget) { return renderTarget.type() == RenderTargetType::DepthStencil; }); match != m_renderTargets.end())
m_depthStencilTarget = match._Ptr;
m_depthStencilTarget = std::addressof(*match);
else
m_depthStencilTarget = nullptr;

Expand Down Expand Up @@ -310,7 +310,7 @@ const Array<RenderPassDependency>& DirectX12RenderPass::inputAttachments() const
const RenderPassDependency& DirectX12RenderPass::inputAttachment(UInt32 location) const
{
if (location >= m_impl->m_inputAttachments.size()) [[unlikely]]
throw ArgumentOutOfRangeException("location", std::make_pair(0ull, (UInt64)m_impl->m_inputAttachments.size()), location, "The render pass does not contain an input attachment at location {0}.", location);
throw ArgumentOutOfRangeException("location", std::make_pair(0uz, m_impl->m_inputAttachments.size()), location, "The render pass does not contain an input attachment at location {0}.", location);

return m_impl->m_inputAttachments[location];
}
Expand Down
Loading

0 comments on commit f2a3efa

Please sign in to comment.