Git Product home page Git Product logo

nvrhi's Introduction

NVRHI

Build Status

Introduction

NVRHI (NVIDIA Rendering Hardware Interface) is a library that implements a common abstraction layer over multiple graphics APIs (GAPIs): Direct3D 11, Direct3D 12, and Vulkan 1.2. It works on Windows (x64 only) and Linux (x64 and ARM64).

Key features:

  • Automatic tracking of resource states and barrier placement (optional).
  • Automatic tracking of resource usage and lifetime, deferred and safe resource destruction.
  • Convenient and efficient resource binding model with little runtime overhead.
  • Easy direct interaction with the underlying GAPI when necessary.
  • Easy portability of the rendering code between the supported GAPIs.
  • Hidden sub-allocation of upload buffers and versioning of constant buffers.
  • Parallel command list recording and multi-queue rendering.
  • Supports all types of pipelines: Graphics, Compute, Ray Tracing, and Meshlet.
  • Validation layer and resource reflection for easy debugging.

NVRHI is used in several NVIDIA GameWorks SDKs:

Notable third-party projects using NVRHI:

Various early versions of NVRHI have been used in various projects created at NVIDIA, including:

Requirements

  • Windows or Linux (x64 or ARM64)
  • CMake 3.10
  • A C++ 17 compiler (Visual Studio 2019, GCC 8 or Clang 6)
  • Windows SDK version 10.0.19041.0 or later for DX12 support

Building NVRHI

NVRHI can be configured to be used a set of static libraries in CMake-based projects, or as a single dynamic library.

To include NVRHI into a CMake project as static libraries:

  1. Add this repository as a submodule.
  2. Add a add_subdirectory(nvrhi) directive to the parent CMakeLists.txt.
  3. Add dependencies to the necessary targets:
    • nvrhi for the interface headers, common utilities, and validation;
    • nvrhi_d3d11 for DX11 (enabled when NVRHI_WITH_DX11 is ON);
    • nvrhi_d3d12 for DX12 (enabled when NVRHI_WITH_DX12 is ON); and
    • nvrhi_vk for Vulkan (enabled when NVRHI_WITH_VULKAN is ON).

To build NVRHI as a shared library (DLL or .so):

  1. Clone this repository recursively (including submodules).
  2. Generate the project with CMake:
    • Set the NVRHI_BUILD_SHARED variable to ON.
    • Make sure to set the target platform to a 64-bit one. 32-bit builds are not supported.
  3. Build and install as normal.

Using NVRHI in Applications

See the programming guide and the tutorial.

NVAPI Support

NVRHI includes optional support for certain DX11 and DX12 extensions available through the NVAPI library. The library is not distributed with NVRHI but is available separately here.

To enable NVAPI support, extract the NVAPI SDK into the nvapi subfolder of your main project and set the NVRHI_WITH_NVAPI CMake variable to ON.

The following extensions are supported:

  • Opacity Micro-Maps (DX12, Ada+)
  • Shader Execution Reordering on DX12 (DX12, Ada+)
  • Single Pass Stereo (Pascal+)
  • Fast Geometry Shader with optional coordinate swizzling (Maxwell+)
  • Conservative Raster and other rasterizer features (Maxwell+)
  • HLSL Extensions through a fake UAV slot (see this blog post)

RTXMU Integration

NVRHI includes an optional integration of the RTXMU library. The library is included as a git submodule, and can be enabled with the NVRHI_WITH_RTXMU CMake variable.

When RTXMU integration is enabled, all bottom-level ray tracing acceleration structures (BLAS'es) are managed by that library. All built BLAS'es that have the AllowCompaction flag set are automatically compacted when ICommandList::compactBottomLevelAccelStructs method is called. No other configuration is necessary.

License

NVRHI is licensed under the MIT License.

nvrhi's People

Contributors

apanteleev avatar blueskythlikesclouds avatar blurrylight avatar cpp-tools avatar huntlier avatar jarvism-nv avatar loopunit avatar manuelknvda avatar nbickford-nv avatar nv-jdeligiannis avatar sirtsu55 avatar srsaunders avatar stephenap07 avatar tksgmsy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nvrhi's Issues

Feature: occlusion queries

NVRHI has timer queries and event queries. However, I think it would be useful to have occlusion queries too, like in NRI.

Without them, I'd have to use a workaround such as rendering into a low-res framebuffer and using a compute shader to count pixels, which I guess would be significantly slower than the real thing, but I've never tried. Directly using the rendering API is not preferable.

What are your thoughts on this?

Add documentation on the GPU read-back process to the docs (texture/buffer/etc)

Although readback at runtime is generally bad, critical readback tasks include saving results of cubemap convolution for IBL and other compute related tasks that may be done offline.

Doesn't need to by hyper detailed documentation, just a basic block of "you can grab a layer/mip like this and buffers are done like this." Utility functions are certainly welcome, but this is about docs.

Depth texture read/write transitions

I'm adding transparent textures to my engine. To go about this, I'm drawing transparent meshes with depth write disabled. Initially I was just disabled the depth writing on the GraphicsState - however this throw a warning about being unoptimal.

I have a color and depth texture. The depth texture is created in the DepthWrite state, with keepInitialState enabled. At initialization, two framebuffers are created, identical except framebufferDesc.depthAttachment.isReadOnly is true/false. For each framebuffer, a corresponding pipeline is created, with setDepthWriteEnable set accordingly.

At draw, the correct pipeline & framebuffer is added to the graphics state depending on if the material is transparent, and is dispatched.

All opaque objects are drawn first (obviously using the pipeline expecting DepthWrite of the depth texture). Then, all transparent objects. The first time a transparent object is drawn per frame, I get this warning:

[Vulkan: location=1303270965 code=0, layerPrefix='Validation'] Validation Error: [ UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout ] Object 0: handle = 0x3b19d147850, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x4dae5635 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[0] command buffer VkCommandBuffer 0x3b19d147850[] expects VkImage 0xe694900000000278[] (subresource: aspectMask 0x2 array layer 0, mip level 0) to be in layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL--instead, current layout is VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL.

I have automatic barriers enabled. I must have made a mistake somewhere, because NVRHI is intended to take care of these transitions. As there's no further errors, it must, just not immediately. I can attach a renderdoc capture if it helps. Thanks!

clearBufferUInt does not work on raw UAV buffers under DX11

It fails on d3d11-buffer.cpp line 360 "assert(format != Format::UNKNOWN);", since in clearBufferUInt function, the viewType is incorrectly assigned as TypedBuffer_UAV. This function does not expect a raw UAV buffer.

I added the following lines to clearBufferUInt (d3d11-buffer.cpp) line 170 as a WAR to make it work.

        if (bufferDesc.canHaveRawViews && bufferDesc.format == Format::UNKNOWN)
        {
            viewType = ResourceType::RawBuffer_UAV;
        }

Support indirect draw count buffers

ExecuteIndirect & vkCmdDrawIndirectCount both support taking in a buffer as an argument for draw counts. However, this is not implemented, and as a result, the user will be forced to always provide conservative values for the 'drawCount' argument for indirect draw commands.

In addition, it seems like both RenderDoc & PIX doesn't really like to replay empty indirect draw calls, as they will release the graphic driver & unload the reply when attempted to reply indirect commands, at least on my machine. Without a buffer for draw counts, empty indirect draw calls are common when any sort of GPU culling is implemented.

I have modified nvrhi files in my own private repo to support draw count buffer for d3d12 and it has resolved the issue with RenderDoc. I'm not exactly sure what's the underlying low level API issue regarding RenderDoc & empty indirect draw calls, but the issue went away. Admittedly, compacting my indirect buffers to discard empty draw arguments would also likely solve this issue.

Nonetheless, officially supporting draw count buffers for indirect commands in this library would be beneficial.

Support PushConstants[RootConstants] in raytracing SBT and VolatileSRV[Versioned RootShaderResourceView] for command list.

Resource binding can be a area of very verbose. Can the following resource binding features be supported:

  1. PushConstants for Vulkan or RootConstants for D3D12 directly written into ray tracing shader binding table, maybe IBindingSet need to specify the constant buffer to create shader table entry.
  2. Volatile SRV[Versioned RootShaderResourceView] is just a resource type of StructuredBuffer<> compared to ConstantBuffer<> in HLSL, which can be bound to root shader resource view.
  3. for BindingSetItem of type "ConstantBuffer", buffer range can not be specified and not work properly, this may be a bug instead of a feature.

Add BGRX8 format support

This format is useful for interop between NVRHI and some other APIs (in my case SDL). It would be useful to avoid custom code to translate pixel formats or having to "fake" the format via BGRA8.

BGRX8 is supported in Vulkan and D3D (DXGI), and doesn't exist in Metal. It seems straight-forward to add to D3D and Vulkan, using the existing format tables, and in Metal NVRHI can return no support via the mechanism to indicate there's no support for a particular format (Device::queryFormatSupport).

Would this be an acceptable new feature? If so I'm happy to put together a PR.

Unresolved external symbols

I'm unable to build my project upon including this create device line in my code:

#include <nvrhi/vulkan.h>
...
nvrhi::vulkan::createDevice(deviceDesc);
...
1>main.cpp
1>nvrhi_vk.lib(vulkan-resource-bindings.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-commandlist.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-state-tracking.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-graphics.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-compute.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-meshlets.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-raytracing.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-staging-texture.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-buffer.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-shader.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-queries.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-device.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-queue.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-allocator.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)
1>nvrhi_vk.lib(vulkan-texture.obj) : error LNK2001: unresolved external symbol "class vk::DispatchLoaderDynamic vk::defaultDispatchLoaderDynamic" (?defaultDispatchLoaderDynamic@vk@@3VDispatchLoaderDynamic@1@A)

My top level CMakeLists:

...
# Dependencies
find_package(Vulkan REQUIRED)
add_subdirectory(Dependencies)

if (VULKAN_FOUND)
    include_directories(${Vulkan_INCLUDE_DIRS})
    target_link_libraries (${PROJECT_NAME} ${Vulkan_LIBRARIES} Dependencies)
endif (VULKAN_FOUND)
...

Dependencies/CMakeLists:

...
set(NVRHI_BUILD_SHARED OFF CACHE BOOL "" FORCE)

set(NVRHI_WITH_DX11 OFF CACHE BOOL "" FORCE)
set(NVRHI_WITH_DX12 OFF CACHE BOOL "" FORCE)
set(NVRHI_WITH_VULKAN ON CACHE BOOL "" FORCE)

add_subdirectory(nvrhi)
target_link_libraries(Dependencies INTERFACE nvrhi)
target_link_libraries(Dependencies INTERFACE nvrhi_vk)
...

PSO recreation on frame buffer resize

I'm confused why the validation layer enforces PSO framebuffer sizes to match a framebuffer binding. The rest of the member checks are correct, but I don't believe size needs to be the same. Recreating PSOs due to a window resize can be a very expensive operation. The documentation mentions:

"Following the Vulkan API for creating graphics pipelines, NVRHI has a concept of a framebuffer. A framebuffer is a collection of render targets, up to 8, and a depth target, each with its subresource set. Framebuffers hold strong references to their textures and are immutable.

A valid framebuffer is necessary to create a graphics or meshlet pipeline. A pipeline created with a certain framebuffer can then be used with the same framebuffer, or with any other framebuffer which is compatible. Two framebuffers are considered compatible when they have the same number and formats of the render targets, and the width and height of the render targets."

I believe this is meant to follow Vulkan render pass compatibility (note render pass, not framebuffer). The Vulkan docs don't mention the size (width and height) in the compatibility requirements: https://registry.khronos.org/vulkan/specs/1.2-extensions/html/chap8.html#renderpass-compatibility

Removing this validation and reusing PSOs with a resized framebuffer doesn't trigger any validation issues on d3d12 or VK. If I'm incorrect can you point me to the relevant documentation for d3d12 or VK?

Thanks!

Recursive locking of a non-recursive mutex can occur in StaticDescriptorHeap

On entry, StaticDescriptorHeap::allocateDescriptors() locks m_Mutex for the scope of the function, and on descriptor exhaustion (or heavy fragmentation) it calls Grow() which also tries to lock m_Mutex. However, m_Mutex is a std::mutex, for which locking multiple times on the same thread is undefined behavior. On Windows Debug builds this generally results in a std::system_error being thrown on the second locking attempt, possibly crashing the whole process.

To be fair, I discovered this while writing a buggy app that didn't correctly clean up after itself and would eventually overflow the default RTV heap size of 1024. But still probably worth switching to std::recursive_mutex for correctness at least.

Vulkan header mismatch failures with statically linked (non-standalone) nvrhi library

Unless I disable precompiled headers in certain files (e.g. DeviceManager_VK.cpp), I experience Vulkan header mismatch failures when building RBDoom3BFG on linux. On Arch linux (manjaro) at least, Vulkan-Headers is installed by the package manager as a dependency for the Vulkan SDK. RBDoom3BFG pulls in the SDK which is ahead of the Vulkan-Headers version included with nvrhi. Up to this point I have been just living with this and disabling pch for files that require vulkan.hpp (i.e. DeviceManager_VK.cpp). However, today I decided to dive into the cmake processing to determine where things are going wrong. I found the following in nvrhi's main CMakeLists file:

if (NVRHI_WITH_VULKAN)
    add_subdirectory(thirdparty/Vulkan-Headers)
endif()

...

if (NVRHI_WITH_VULKAN)
    ...
    target_link_libraries(${nvrhi_vulkan_target} Vulkan-Headers)
endif()

This seems to be pulling in nvrhi's version which may conflict with the application's own use of Vulkan, especially if a newer Vulkan-Headers is installed elsewhere for the SDK. I am wondering whether you should only pull in Vulkan-Headers as a linked library if nvrhi is being built for standalone use vs. static linking, i.e. should the target_link_libraries line be guarded by NVRHI_BUILD_SHARED?

Shader resource arrays

It seems that currently arrays of resources are not possible. E.g mipmapgen_cs from donut causes an validation error (Vulkan):
Shader expects at least 13 descriptors for binding 0.384 but only 1 provided The Vulkan spec states: layout must be consistent with the layout of the compute shader specified in stage.
While it works on both Vulkan and DX it might be then driver related (RTX 3080).
I am not too familiar with the DX implementation but it could be correct as it groups same resources? For Vulkan this might be hard to support without providing the concept of arrays in layout/bindingset items.

C API?

Hello,
Is there a C API available for this, I don't spot one. It would really help with adoption if bindings could be created for other languages.
Also how is this different from https://github.com/NVIDIAGameWorks/NRI ?

Linking nvrhi and nvrhi_vk to a library produces errors when linking to an executable afterwards

Hi,
I followed the instruction to install nvrhi as a submodule and I'm trying to use it with cmake.
I use

set(NVRHI_WITH_VULKAN ON)
add_subdirectory(thirdparty/nvrhi)

To include the project, then later on I link it to one of my libraries.

target_link_libraries(Renderer Vulkan-Headers) # This line changed a lot
target_link_libraries(Renderer nvrhi_vk)
target_link_libraries(Renderer nvrhi)

This is what it currently looks like. At some point I had nvrhi first, then I used Vulkan::Vulkan instead of Vulkan-Headers, etc. But in the end the target Renderer always built itself correctly.

Now if I link Renderer to another target and use one of the functions I get a link error LNK2001 (The compiler can't find vulkan-hpp's dynamic loader).

I tried linking nvrhi to said target, I tried linking vulkan, didn't work. Note that I use vk-boostrap to speed up vulkan instance creation but even if I remove it it still doesn't work.

Does anyone have an idea as why it doesn't work ? Maybe I'm just dumb and forgot how c++ libraries and linking work.

Seems Redundant loop in CommandList::writeBuffer in Vulkan Backend

while (remaining > 0)
{
// vulkan allows <= 64kb transfers via VkCmdUpdateBuffer
int64_t thisGulpSize = std::min(remaining, int64_t(commandBufferWriteLimit));
// we bloat the read size here past the incoming buffer since the transfer must be a multiple of 4; the extra garbage should never be used anywhere
thisGulpSize = (thisGulpSize + 3) & ~3ll;

thisGulpSize is rounded up to multiple of 4, so it should be greater equal than remaining.
There should be no second loop here.

Line 437 is also redundant, because it won't enter this branch if data size greater than 65536

if (dataSize <= commandBufferWriteLimit)

Thread safety documentation

I was looking at implementing multi-threading in my engine for uploading textures. I used the CommandList::writeTexture method. Unfortunately this causes a crash, as although it's a member of the command list (which should be able to be recorded in parallel?), behind the scenes it interfaces with the (Vulkan) device to allocate memory.

Some documentation on which methods are thread safe, and an overview of how to safely use them in the Programming Guide would be very helpful I think? Thanks

potential dangling resources in CommandListResourceStateTracker

A minimal repoducable example is as following:

  void TestRelease() {
    nvrhi::BufferDesc desc{};
    desc.keepInitialState = true;
    desc.initialState = nvrhi::ResourceStates::Common;
    desc.byteSize = 4;

    auto CmdList = GetDevice()->createCommandList();
    CmdList->open();
    {
      auto buf = GetDevice()->createBuffer(desc);
      CmdList->setBufferState(buf,nvrhi::ResourceStates::ConstantBuffer);
    }
    CmdList->close();
  }

It's because CommandListResourceStateTracker store all resources references in raw pointers without ref counter.
When cmdlists are about to close, they try to iterate over these resources ( keepBufferInitialStates / keepTextureInitialStates) and may trigger a crash because these resources may have been freed.

potential fix

CommandListResourceStateTracker might extend resources lifetime until closed.

Web Support (WebGL/WebGPU)

It would be cool if NVRHI had web support. A similar API, wgpu, supports both WebGPU and WebGL2 backends. It would be nice if this library supported those as well, as it would make it easier to port projects made with NVRHI to the web

Vulkan's CommandList::copyTexture copies the entire region instead of slice.

copyTexture(ITexture* _dst, const TextureSlice& dstSlice, IStagingTexture* _src, const TextureSlice& srcSlice) and copyTexture(IStagingTexture* _dst, const TextureSlice& dstSlice, ITexture* _src, const TextureSlice& srcSlice) uses vk::Extent3D srcMipSize/dstMipSize of the whole image instead of the slice that was resolved.

vk::Extent3D srcMipSize = src->imageInfo.extent;
srcMipSize.width = std::max(srcMipSize.width >> resolvedDstSlice.mipLevel, 1u);
srcMipSize.height = std::max(srcMipSize.height >> resolvedDstSlice.mipLevel, 1u);

vk::Extent3D dstMipSize = dst->imageInfo.extent;
dstMipSize.width = std::max(dstMipSize.width >> resolvedDstSlice.mipLevel, 1u);
dstMipSize.height = std::max(dstMipSize.height >> resolvedDstSlice.mipLevel, 1u);

was this the intended behaviour?

Vulkan validation layer bufferDeviceAddress warning

VK validation layer reports:

WARNING: [Vulkan: location=0xfffffffff972dfbf code=0, layerPrefix='Validation'] Validation Error: [ VUID-VkMemoryAllocateInfo-flags-03331 ] Object 0: handle = 0x12f05f5af50, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xf972dfbf | If VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT is set, bufferDeviceAddress must be enabled. The Vulkan spec states: If VkMemoryAllocateFlagsInfo::flags includes VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT, the bufferDeviceAddress feature must be enabled (https://vulkan.lunarg.com/doc/view/1.3.224.1/windows/1.3-extensions/vkspec.html#VUID-VkMemoryAllocateInfo-flags-03331)

Adding .setBufferDeviceAddress(bufferAddressSupported) to vulkan12features in DeviceManager_VK.cpp fixed the problem.

[Question] Should Vulkan WriteTexture need vkFlushMappedMemoryRanges?

m_UploadManager->suballocateBuffer(
deviceMemSize,
&uploadBuffer,
&uploadOffset,
&uploadCpuVA,
MakeVersion(m_CurrentCmdBuf->recordingID, m_CommandListParameters.queueType, false));
size_t minRowPitch = std::min(size_t(deviceRowPitch), rowPitch);
uint8_t* mappedPtr = (uint8_t*)uploadCpuVA;
for (uint32_t slice = 0; slice < mipDepth; slice++)
{
const uint8_t* sourcePtr = (const uint8_t*)data + depthPitch * slice;
for (uint32_t row = 0; row < deviceNumRows; row++)
{
memcpy(mappedPtr, sourcePtr, minRowPitch);
mappedPtr += deviceRowPitch;
sourcePtr += rowPitch;
}
}
auto imageCopy = vk::BufferImageCopy()

the code snippnet is trying to first transfer data to upload heap and then using vkCopyBufferToImage to transfer data into device-local memory.
However, the staging buffer is created with eHostVisible instead of eHostCoherent.

case CpuAccessMode::Write:
flags = vk::MemoryPropertyFlagBits::eHostVisible;
break;

Taking Vulkan-Docs:Transfer-dependencies as reference, it seems there should be a vkFlushMappedMemoryRanges between the memcpy and the vkCopyBufferToImage, to ensure the host write is visible.

Unexpected nvrhi::utils::ClearDepthStencilAttachment() validation error

Calling nvrhi::utils::ClearDepthStencilAttachment() with a framebuffer that has a depth stencil texture triggers a validation error that says:

ERROR: Texture DepthStencil cannot be cleared with clearTextureFloat because it's a depth-stencil texture. Use clearDepthStencilTexture instead.

Is there a usage reason why nvrhi::utils::ClearDepthStencilAttachment() calls clearTextureFloat() instead of clearDepthStencilTexture()?

commandList->clearTextureFloat(att.texture, att.subresources, Color(depth, float(stencil), 0.f, 0.f));

If so, what's the intended way to clear a depth/stencil texture with nvhri?

Help with push constants

Hello! Apologies for making this an issue, I couldn't see a discord or similar place to ask for help.

I've made a simple triangle demo on top of Donut's DeviceManager, and am trying to add basic push constants to it. Creating the pipeline fails. My code is as follows:

struct Vertex {
    float pos[3];
    float color[3];
};

struct PushConstants {
    float x;
    float y;
};

constexpr const Vertex RENDER_DATA_VERTICES[] = {
        {{-0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f}},
        {{0.f,   0.5f,  0.0f}, {0.0f, 1.0f, 0.0f}},
        {{0.5f,  -0.5f, 0.0f}, {0.0f, 0.0f, 1.0f}}
};
constexpr const uint32_t RENDER_DATA_INDICES[] = {0, 1, 2};

TestAnimatedTriangleRenderPass::TestAnimatedTriangleRenderPass(donut::app::DeviceManager *deviceManager) : IRenderPass(
        deviceManager) {
    // Create the command queue!
    m_pCommandList = GetDevice()->createCommandList();
    m_pCommandList->open();

    // Load shaders.
    createShader(GetDevice(), nvrhi::ShaderType::Vertex, "push_const_triangle_main_vs.bin", "main_vs",
                 m_pVertexShader);
    createShader(GetDevice(), nvrhi::ShaderType::Pixel, "push_const_triangle_main_ps.bin", "main_ps",
                 m_pPixelShader);

    // Create vertex attributes.
    nvrhi::VertexAttributeDesc uVertexAttributes[] = {
            nvrhi::VertexAttributeDesc()
                    .setName("POSITION")
                    .setFormat(nvrhi::Format::RGB32_FLOAT)
                    .setOffset(0)
                    .setElementStride(sizeof(Vertex)),
            nvrhi::VertexAttributeDesc()
                    .setName("COLOR")
                    .setFormat(nvrhi::Format::RGB32_FLOAT)
                    .setOffset(3 * sizeof(float))
                    .setElementStride(sizeof(Vertex)),
    };
    m_pInputLayout = GetDevice()->createInputLayout(uVertexAttributes, std::size(uVertexAttributes), m_pVertexShader);

    // Create vertex buffer.
    {
        nvrhi::BufferDesc szBufferDesc;
        szBufferDesc.initialState = nvrhi::ResourceStates::CopyDest;
        szBufferDesc.isVertexBuffer = true;
        szBufferDesc.byteSize = sizeof(RENDER_DATA_VERTICES);
        szBufferDesc.debugName = "Test vertex buffer";
        m_pVertexBuffer = GetDevice()->createBuffer(szBufferDesc);

        m_pCommandList->beginTrackingBufferState(m_pVertexBuffer, nvrhi::ResourceStates::CopyDest);
        m_pCommandList->writeBuffer(m_pVertexBuffer, RENDER_DATA_VERTICES, sizeof(RENDER_DATA_VERTICES));
        m_pCommandList->setPermanentBufferState(m_pVertexBuffer, nvrhi::ResourceStates::VertexBuffer);
    }

    // Create index buffer.
    {
        nvrhi::BufferDesc szBufferDesc;
        szBufferDesc.initialState = nvrhi::ResourceStates::CopyDest;
        szBufferDesc.isIndexBuffer = true;
        szBufferDesc.byteSize = sizeof(RENDER_DATA_INDICES);
        szBufferDesc.debugName = "Test index buffer";
        m_pIndexBuffer = GetDevice()->createBuffer(szBufferDesc);

        m_pCommandList->beginTrackingBufferState(m_pIndexBuffer, nvrhi::ResourceStates::CopyDest);
        m_pCommandList->writeBuffer(m_pIndexBuffer, RENDER_DATA_INDICES, sizeof(RENDER_DATA_INDICES));
        m_pCommandList->setPermanentBufferState(m_pIndexBuffer, nvrhi::ResourceStates::IndexBuffer);
    }

    // Binding desc.
    {
        nvrhi::BindingSetDesc szBindingSetDesc;
        szBindingSetDesc.bindings = {
                nvrhi::BindingSetItem::PushConstants(0, sizeof(PushConstants)),
        };
        nvrhi::utils::CreateBindingSetAndLayout(GetDevice(), nvrhi::ShaderType::Vertex, 0, szBindingSetDesc,
                                                m_pBindingLayout, m_pBindingSet);
    }

    // Create pipeline.
    {
        nvrhi::RenderState szRenderState{
                .depthStencilState = {
                        .depthTestEnable = false,
                        .depthWriteEnable = false,
                        .stencilEnable = false,
                },
                .rasterState = {
                        .cullMode = nvrhi::RasterCullMode::Back,
                },
        };

        nvrhi::GraphicsPipelineDesc szPipelineDesc = nvrhi::GraphicsPipelineDesc()
                .addBindingLayout(m_pBindingLayout)
                .setInputLayout(m_pInputLayout)
                .setVertexShader(m_pVertexShader)
                .setPixelShader(m_pPixelShader)
                .setRenderState(szRenderState)
                .setPrimType(nvrhi::PrimitiveType::TriangleList);

        m_pPipeline = GetDevice()->createGraphicsPipeline(szPipelineDesc, GetDeviceManager()->GetCurrentFramebuffer());
    }

    m_pCommandList->close();
    GetDevice()->executeCommandList(m_pCommandList);
}

static PushConstants aPushConstants;

void TestAnimatedTriangleRenderPass::Render(nvrhi::IFramebuffer *framebuffer) {
    IRenderPass::Render(framebuffer);

    m_pCommandList->open();

    nvrhi::utils::ClearColorAttachment(
            m_pCommandList,
            GetDeviceManager()->GetCurrentFramebuffer(),
            0,
            nvrhi::Color{.05f, .05f, .1f, 1.f}
    );

    nvrhi::GraphicsState szGraphicsState = nvrhi::GraphicsState()
            .setPipeline(m_pPipeline)
            .setFramebuffer(GetDeviceManager()->GetCurrentFramebuffer())
            .setViewport(
                    nvrhi::ViewportState().addViewportAndScissorRect(framebuffer->getFramebufferInfo().getViewport()))
            .addVertexBuffer({m_pVertexBuffer, 0, 0})
            .setIndexBuffer({m_pIndexBuffer, nvrhi::Format::R32_UINT, 0})
            .addBindingSet(m_pBindingSet);
    m_pCommandList->setGraphicsState(szGraphicsState);

    // Arbitrary push constant value. This would be dynamic in a real app.
    aPushConstants.x = 1.0f;
    m_pCommandList->setPushConstants(&aPushConstants, sizeof(aPushConstants));

    auto szDrawArguments = nvrhi::DrawArguments()
            .setVertexCount(3);
    m_pCommandList->drawIndexed(szDrawArguments);

    m_pCommandList->close();
    GetDevice()->executeCommandList(m_pCommandList);
}
#ifdef SPIRV
#define VK_PUSH_CONSTANT [[vk::push_constant]]
#else
#define VK_PUSH_CONSTANT
#endif

struct AppPushConstants {
    float x;
    float y;
};

VK_PUSH_CONSTANT ConstantBuffer<AppPushConstants> g_AppConstants : register(b0);

void main_vs(
    float3 inPosition : POSITION,
    float3 inColor : COLOR,

    out float4 outPosition : SV_POSITION,
    out float4 outColor : COLOR
)
{
    outPosition = float4( inPosition, 1.0 );
    outPosition += float4( g_AppConstants.x, g_AppConstants.y, 0, 0);
    outColor = float4(inColor, 0.5);
}

void main_ps(
    in float4 inPosition : SV_POSITION,
    in float4 inColor : COLOR,

    out float4 outColour : SV_TARGET0
)
{
    outColour.rgba = inColor;
}

With the following error:

[Vulkan: location=0x45717876 code=0, layerPrefix='Validation'] Validation Error: [ VUID-VkGraphicsPipelineCreateInfo-layout-00756 ] Object 0: handle = 0xd10d270000000018, type = VK_OBJECT_TYPE_SHADER_MODULE; Object 1: handle = 0xc4f3070000000021, type = VK_OBJECT_TYPE_PIPELINE_LAYOUT; | MessageID = 0x45717876 | Shader expects at least 1 descriptors for binding 0.256 but only 0 provided The Vulkan spec states: layout must be consistent with all shaders specified in pStages (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-layout-00756)

This is running on Linux with Vulkan.

I've referenced code from the RBDOOM3 and the donut examaples repo and can't see what I'm missing. Any ideas? Thanks.

clang error: No matching function for call to 'hash_combine'

Compiling with Apple clang gives the following error:

nvrhi/src/vulkan/vulkan-resource-bindings.cpp:456:17: error: no matching function for call to 'hash_combine'
                nvrhi::hash_combine(viewInfoHash, range.byteOffset);
                ^~~~~~~~~~~~~~~~~~~
In file included from .../nvrhi/src/vulkan/vulkan-resource-bindings.cpp:23:
In file included from .../nvrhi/src/vulkan/vulkan-backend.h:25:
In file included from .../nvrhi/include/nvrhi/vulkan.h:26:
.../nvrhi/include/nvrhi/nvrhi.h:2768:10: note: candidate function template not viable: no known conversion from 'uint64_t' (aka 'unsigned long long') to 'size_t &' (aka 'unsigned long &') for 1st argument
    void hash_combine(size_t& seed, const T& v)

And the following warning:

.../nvrhi/src/validation/validation-device.cpp:1182:87: warning: '&&' within '||' [-Wlogical-op-parentheses]
        if (!(graphicsApi == GraphicsAPI::D3D12 || graphicsApi == GraphicsAPI::VULKAN && desc.registerSpaceIsDescriptorSet))
                                                ~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../nvrhi/src/validation/validation-device.cpp:1182:87: note: place parentheses around the '&&' expression to silence this warning
        if (!(graphicsApi == GraphicsAPI::D3D12 || graphicsApi == GraphicsAPI::VULKAN && desc.registerSpaceIsDescriptorSet))
                                                                                      ^
                                                   (                                                                      )

I will submit a PR with fixes.

wrong calculation for vulkan buffer 4-byte alignment in vkCmdUpdateBuffer

size += size % 4;

thisGulpSize += thisGulpSize % 4;

take 5 byte as example , 5 + (5 % 4) = 6, which is not multiple of 4.

An easily reproducible code is as follows:

        nvrhi::BufferDesc desc{};
        desc.byteSize = 5;
        desc.keepInitialState = true;
        desc.initialState = nvrhi::ResourceStates::Common; // some boilerplate...
        auto buf = GetDevice()->createBuffer(desc);
        std::array<uint8_t, 5> data{0, 1, 2, 3, 4};
        m_CommandList->writeBuffer(buf, data.data(),sizeof(data)); // write 5 bytes

vulkan validation layer catchs the error:

WARNING: [Vulkan: location=0xe9aa8ae3 code=0, layerPrefix='Validation'] Validation Error: [ VUID-vkCmdUpdateBuffer-dataSize-00038 ] Object 0: handle = 0x275ca6f9400, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xe9aa8ae3 | vkCmdUpdateBuffer() parameter, VkDeviceSize dataSize (0x6), is not a multiple of 4. The Vulkan spec states: dataSize must be a multiple of 4 (https://vulkan.lunarg.com/doc/view/1.3.243.0/windows/1.3-extensions/vkspec.html#VUID-vkCmdUpdateBuffer-dataSize-00038)

Why does vulkan have a separate device handle type?

In the DeviceMangers for DX11 and DX12, the member m_NvrhiDevice is of type nvrhi::DeviceHandle whereas in Vulkan's DeviceManager it is nvrhi::vulkan::DeviceHandle.

However the tutorial when invoking createDevice in the Vulkan section uses nvrhi::DeviceHandle: https://github.com/NVIDIAGameWorks/nvrhi/blob/main/doc/Tutorial.md

I notice if I don't use nvrhi::vulkan::DeviceHandle I cannot invoke functions like queueWaitForSemaphore. And on the other hand since createValidationLayer returns nvrhi::DeviceHandle, I cannot use it for those function calls that rely on the Vulkan handle. What is the intended usage of these handles and why does Vulkan seemingly have different treatment?

Fail to compile nvrhi_d3d12

Upon compiling nvrhi_d3d12 using MSVC clang when linked with a C++20 project, I'm hit with this error several times:

nvrhi\src\d3d12/d3d12-backend.h(79,62): error : integer value 4294967295 is outside the valid range of values [0, 33554431] for the enumeration type 'D3D12_RESOURCE_STATES' [-Wenum-constexpr-conversion]

Replacing constexpr D3D12_RESOURCE_STATES c_ResourceStateUnknown = D3D12_RESOURCE_STATES(~0u); on line 79 with constexpr D3D12_RESOURCE_STATES c_ResourceStateUnknown = D3D12_RESOURCE_STATES(0xFFFFu); seems to resolve the error.

Incomplete Vulkan HPP Initialization in DLL Builds

I found a problem in the Vulkan backend while attempting to follow the tutorial. I built NVRHI for win64 from a fresh clone of the main branch like so:

cmake -D NVRHI_BUILD_SHARED=ON -D NVRHI_WITH_VULKAN=ON -D NVRHI_WITH_DX11=OFF -D NVRHI_WITH_DX12=OFF -D NVRHI_WITH_SHADER_COMPILER=OFF ..

The problem is, when I call nvrhi::vulkan::createDevice only calls the first of the three required VULKAN_HPP_DEFAULT_DISPATCHER.init variants, which means only vkCreateInstance, vkEnumerateInstanceExtensionProperties, vkEnumerateInstanceLayerProperties, and vkEnumerateInstanceVersion are initialized. NVRHI then proceeds to behave as if the full initialization had been performed, and then immediately crashes when it tries to call VULKAN_HPP_DEFAULT_DISPATCHER::createSemaphore via vk::Device::createSemaphore, which is still null.

When NVRHI_SHARED_LIBRARY_BUILD is set, as is the case in my build, NVRHI defines VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE but not VULKAN_HPP_STORAGE_SHARED or VULKAN_HPP_STORAGE_SHARED_EXPORT. According to the vulkan-hpp docs, this means I can't just finish up the initialization in my own application.

So I think to fix this correctly, VULKAN_HPP_STORAGE_SHARED and VULKAN_HPP_STORAGE_SHARED_EXPORT need to be define for the build config or so, and nvrhi::vulkan::createDevice needs to be updated to initialize like so:

    DeviceHandle createDevice(const DeviceDesc& desc)
    {
#if defined(NVRHI_SHARED_LIBRARY_BUILD)
        const vk::DynamicLoader dl;
        const PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =   // NOLINT(misc-misplaced-const)
            dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
        VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
        VULKAN_HPP_DEFAULT_DISPATCHER.init(desc.instance);
        VULKAN_HPP_DEFAULT_DISPATCHER.init(desc.device);
#endif

When building with RTXMU Acceleration Structure doesn't destroy vulkan objects after use

When building with RTXMU and compacting an AccelStruct everyting is fine, but when the application closes and the device is destroyed, a bunch of Vulkan and DX12 messages warn, that the resources haven't been destroyed. After digging in the code I suspect the destructor for AccelStruct doesn't implement this functionality.

The error message:
Validation Error: [ VUID-vkDestroyDevice-device-00378 ] Object 0: handle = 0x55a8fb9483c0, type = VK_OBJECT_TYPE_DEVICE; Object 1: handle = 0x603cd90000000044, type = VK_OBJECT_TYPE_BUFFER;

This comes up for also VK_OBJECT_TYPE_DEVICE_MEMORY, VK_OBJECT_TYPE_QUERY_POOL and VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR

Thanks :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.