15

D3D12 has 4 separate kinds of command lists: direct, bundle, compute, and copy. Vulkan has similar concepts, but they happen in a different way. Command buffers are allocated from command pools. And command pools are directly associated with a queue family. And command buffers allocated from a pool can only be submitted to the queue family for which the ...


13

The main gain would be that it would be easier to divide CPU tasks into multiple threads, without having to solve all the difficult issues with accessing the graphics API. Normally you either would have to make the context current (which might have bad performance implications) or provide a queue and call the graphics api in a single thread. I don't think ...


10

In DX12, a descriptor is a small record, basically a pointer, that tells the GPU where to find some data such as a constant buffer. Since each object is going to have its own constant buffer data with its own particular transforms, lighting/material properties, etc., each object also has to end up with a separate set of descriptors to point to its individual ...


9

There's a lot of work needed on the CPU to set up a frame for the GPU, and a good chunk of that work is inside the graphics driver. Prior to DX12 / Vulkan, that graphics driver work was essentially forced to be single-threaded by the design of the API. The hope is that DX12 / Vulkan lift that restriction, allowing driver work to be performed in parallel on ...


8

In DX12, there is no implicit driver-implemented SLI as there was in DX11. Instead, multiple GPUs are exposed to the application as separate "nodes" within a single DX12 device, and each VRAM resource lives on a single node, specified at creation time. There is no implicit mirroring of resources to both GPUs as in DX11 SLI. So, the game engine or ...


7

It's very different between the Khronos standards (including Vulkan) and DirectX. In DirectX, Microsoft implements the API, but they publish to GPU vendors a HAL API. There's actually two HALs: one that runs in kernel-mode, to communicate with the card directly; and one that runs in user-space, to do other tasks (like manage memory, set up data structures, ...


5

TL;DR: There's some room for optimization in Vulkan drivers, but not nearly to the degree that there is in GL / DX11 drivers. how much do drivers affect performance? It depends a great deal on how the application is written and the hardware. Specifically it depends on whether you're using features where there are large opportunities for optimization on ...


5

Modern GPUs generally have a single frontend section that processes an entirely linear stream of commands from the CPU. Whether this is a natural hardware design or if it simply evolved out of the days when there was a single CPU core generating commands for the GPU is debatable, but it's the reality for now. So if you generate a single linear stream of ...


5

Vector has a few different semantics from static arrays. For one it's a struct containing a pointer a capacity and a length (at the very least). That means that sizeof will not reflect how much data is actually stored in there (that only works on static arrays). If you need to get the size in bytes of the data then you need const UINT vertexBufferSize = ...


4

The problem looks like it's in this line: d3dDevice->CreateConstantBufferView(cbvDesc, cbvHandle1); The first parameter should be &cbvDesc[1]. As it is now, you're setting up two copies of cbvDesc[0]. Also, it looks like you've reversed the second and third arguments to the cbvHandle1 constructor: the second argument should be the offset (1) and ...


4

In your first example, the call to WaitForSingleObject blocks the thread. This puts it into a waiting state, which takes it off the run queue and allows other threads to run on this CPU core. If no threads can run, the CPU will idle. When the fenceEvent completes, it wakes up this thread. Your proposed replacement is called a spinlock. The thread keeps ...


3

One point: the Lambert BRDF is not $N\cdot L$, it's just the albedo divided by pi. The $N \cdot L$ factor comes from the $\cos \theta$ in the rendering equation. So, when sampling with a cosine-weighted distribution the $N \cdot L$s and pis will cancel out and you should just be accumulating $\frac{1}{N} \sum L_i * \text{albedo}$. It looks like in your code ...


3

My understanding would be that resource barriers are not at all about synchronization. They are about memory ordering, which is a related but separate concern. Basically, synchronization is about making sure that A happens before B. Memory ordering is about making sure that if A did X, someone how saw A happen will always also see X and no one will ever see ...


3

There are two general ways the graphics driver can implement Map(). One way is to set up a virtual memory mapping that makes the resource's actual memory (could be system memory or GPU memory) visible as part of the application's address space. If it does happen to be GPU memory, any writes you do would typically be buffered up and sent across the PCIe bus ...


3

You have to use the appropriate register type for the resource: b registers for constant buffers, t for textures, and u for UAVs. AFAIK, it is not possible to bind a UAV to a texture slot, or otherwise mismatch registers and resources. However, a resource can have multiple views, so it is possible to have a resource bound as a UAV in one shader and as a ...


2

You're trying to map all three UAVs to the same descriptor slot (slot 0). ranges_madhu[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE); ranges_madhu[1].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE); ranges_madhu[2].Init(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, 0, ...


2

If I understand you correctly, you've added a new compute shader. In DX12, you'll need at least one separate PSO for each shader, since the shader code is part of the PSO.


2

You don't. These objects typically work with CPU memory, not device memory. And to the extent that they involve device memory, such allocations tend to be rare and/or fixed in size (a queue may have a small spot of device memory that the hardware queue reads commands from or something, but even that is implementation-dependent). Vulkan allows you to give ...


2

You should be able to use RWTexture3D. The hlsl documentation page about RWTexture2D also has sample code that you might find useful.


2

I think what you want for this is to create a descriptor table which lists your textures. The individual textures would be created and uploaded as ordinary Texture2Ds. You'd set up the root signature of your shader to bind your Texture2D[] in HLSL to a contiguous range of SRV descriptors from a descriptor heap. Then, when you create the SRVs for your ...


2

That's how I used to initialize viewport (CD3DX12_VIEWPORT). But I didn't realize that there are two additional fields minDepth and maxDepth. Therefore, I have min/max depth set to 0.0 and objects rendered to depth buffer are always black: m_viewport.TopLeftY = 0.0f; m_viewport.TopLeftX = 0.0f; m_viewport.Width = static_cast<float>(m_windowSize.x); ...


1

In accord with the GLSL extension, gl_Layer in a mesh shader is part of the predefined gl_MeshPerPrimitiveNV output interface block. It seems to have the expected definition. This is a per-primitive parameter, so you can set it to a different value for each primitive you output. Basically, yes: layered rendering is available in task/mesh shaders. And since ...


1

The code for mip1 and mip2 (and higher mips if you have them—SSR ray marching can benefit a lot from higher mips) is identical except for which mip is being read and written; you don't need separate PSOs for those. Instead of creating bindings for mip0, mip1, mip2, you could rather create bindings for "source mip" and "dest mip" and set ...


1

Everything is allowed to be left unbound / invalid / uninitialized as long as the shader doesn't try to look at it. However, if the shader does try to look at it, it could trigger a GPU crash / TDR. In practice, it may be a good idea to explicitly clear out descriptors that you know aren't going to be valid: either setting them to a null descriptor, or ...


1

Problem was that perspective matrix had very short Z_NEAR and Z_FAR values (0.01f and 200.0f). By changing it to much higher range (10.0f, 20000.0f), problem with jaggies and artifacts disappears.


1

This can be caused by the compiler creating unsigned bytecode. For the compiler to sign the bytecode, you have to have a copy of dxil.dll in the same folder as the dxcompiler.dll at runtime. See Using the GitHub dxcompiler.dll for some more info. The dxil.dll is available in the official DXC releases.


1

Yes it is possible by putting Samplers in descriptor tables to dynamically assign and index into them. Source: https://youtu.be/Wbnw87tYqVg?t=754 Here's an example that uses the HLSL root signature syntax to do this here: https://youtu.be/Wbnw87tYqVg?t=5277


1

So, I figured it out. While UAV will be necessary when I start manipulating data in Compute Shaders, for the time being, SRV works fine provided the resource is read-only from the fragment shader. The two big problems were Creating an ImageTexture that was receiving the data. Note that the data copy was occurring just fine, but the texture was never used ...


1

First you may want to take a look at the doc. Map basically allows you to retrieve a CPU pointer of a GPU resource. It performs a few operations on the background so the data is up to date. Depending on the type of resource you are mapping, you can perform different tasks like reading data or copying it. As far as I know, Map will only allocate an address ...


1

Ok, so I made little example of how to do this. Short version You need to allocate additional buffer with heap type D3D12_HEAP_TYPE_READBACK and resource state set to D3D12_RESOURCE_STATE_COPY_DEST. Then create command list with type D3D12_COMMAND_LIST_TYPE_COPY. After dispatch compute shader use fence to check if buffer is ready, then copy from this ...


Only top voted, non community-wiki answers of a minimum length are eligible