I'm trying to create a shadow map in my DirectX application, but currently having trouble when creating the Depth Stencil view. CreateDepthStencilView() is leaving my ID3D11DepthStencilView* variable as NULL.
The only error I've managed to get from the HRESULT is "The parameter is incorrect". It seems the problem is with both the D3D11_TEXTURE2D_DESC and the ID3D11_DEPTH_STENCIL_VIEW_DESC as when I've replaced them with the depth texture and nullptr respectively, it works. I then replaced the working function parameters with the shadow map values one at a time and it did not work with either.
I have also tried setting shadowDsv.Flags = 0 , as suggested in this post, but had the same result.
I'm following this tutorial, the code is the same as his (except mine is DX11 not DX10), I'm unsure what the problem could be. This is my code:
Application.h
ID3D11Texture2D* _shadowMapTexture;
ID3D11DepthStencilView* _shadowMapStencil;
ID3D11ShaderResourceView* _shadowMapRV;
Application.cpp
//Set up shadow map
D3D11_TEXTURE2D_DESC shadowTexDesc;
shadowTexDesc.Width = _WindowWidth;
shadowTexDesc.Height = _WindowHeight;
shadowTexDesc.MipLevels = 1;
shadowTexDesc.ArraySize = 1;
shadowTexDesc.Format = DXGI_FORMAT_R32_TYPELESS;
shadowTexDesc.SampleDesc.Count = 1;
shadowTexDesc.SampleDesc.Quality = 0;
shadowTexDesc.Usage = D3D11_USAGE_DEFAULT;
shadowTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
shadowTexDesc.CPUAccessFlags = 0;
shadowTexDesc.MiscFlags = 0;
D3D11_DEPTH_STENCIL_VIEW_DESC shadowDsv;
shadowDsv.Format = shadowTexDesc.Format;
shadowDsv.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
shadowDsv.Texture2D.MipSlice = 0;
D3D11_SHADER_RESOURCE_VIEW_DESC shadowSrv;
shadowSrv.Format = DXGI_FORMAT_R32_FLOAT;
shadowSrv.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shadowSrv.Texture2D.MipLevels = shadowTexDesc.MipLevels;
shadowSrv.Texture2D.MostDetailedMip = 0;
hr = _pd3dDevice->CreateTexture2D(&shadowTexDesc, nullptr, &_shadowMapTexture);
hr = _pd3dDevice->CreateDepthStencilView(_shadowMapTexture, &shadowDsv, &_shadowMapStencil);
hr = _pd3dDevice->CreateShaderResourceView(_shadowMapTexture, &shadowSrv, &_shadowMapRV);
EDIT:
This is the console output when CreateDepthStencilView() is called. Thank you for the help so far.
D3D11 ERROR: ID3D11Device::CreateDepthStencilView: The Format (0x27, R32_TYPELESS) is invalid, when creating a View; it is not a fully qualified Format castable from the Format of the Resource (0x27, R32_TYPELESS). [ STATE_CREATION ERROR #144: CREATEDEPTHSTENCILVIEW_INVALIDFORMAT]
D3D11 ERROR: ID3D11Device::CreateDepthStencilView: The format (0x27, R32_TYPELESS) cannot be used with a DepthStencil view. [ STATE_CREATION ERROR #144: CREATEDEPTHSTENCILVIEW_INVALIDFORMAT]
D3D11 ERROR: ID3D11Device::CreateDepthStencilView: There were unrecognized flags specified in the DepthStencilView Flags field. The flags value was 0xcccccccc, while the valid flags are limited to 0x3. [ STATE_CREATION ERROR #2097153: CREATEDEPTHSTENCILVIEW_INVALIDFLAGS]
Exception thrown at 0x76D235D2 in DX11 Framework.exe: Microsoft C++ exception: _com_error at memory location 0x00B3EE98.
D3D11 ERROR: ID3D11Device::CreateDepthStencilView: Returning E_INVALIDARG, meaning invalid parameters were passed. [ STATE_CREATION ERROR #148: CREATEDEPTHSTENCILVIEW_INVALIDARG_RETURN]
It seems the R32_TYPELESS format is what's causing the error. After looking at the documentation I see there are only a few allowable formats. Does anyone recommend a specific format for a shadow map? I've not done this before so unsure if any of the following would be a good subsitute:
DXGI_FORMAT_D16_UNORM
DXGI_FORMAT_D24_UNORM_S8_UINT
DXGI_FORMAT_D32_FLOAT
DXGI_FORMAT_D32_FLOAT_S8X24_UINT
DXGI_FORMAT_UNKNOWN
Thanks again :)
To anyone else having this problem: my fix was to set the D3D11_DEPTH_STENCIL_VIEW_DESC format to DXGI_FORMAT_D32_FLOAT, and the D3D11_DEPTH_STENCIL_VIEW_DESC Flags equal to 0.
Related
I am trying to use the dynamic rendering extension, to that effect I am initializing my instance this way:
auto enabled = vk::ValidationFeatureEnableEXT::eBestPractices;
vk::ValidationFeaturesEXT features;
features.enabledValidationFeatureCount = 1;
features.pEnabledValidationFeatures = &enabled;
vk::PhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering = {};
dynamic_rendering.dynamicRendering = true;
features.pNext = &dynamic_rendering;
// Setup general information about the current application.
vk::ApplicationInfo program_info(
"NeverEngine",
VK_MAKE_VERSION(1, 0, 0),
"No Engine",
VK_MAKE_VERSION(1, 0, 0),
VK_API_VERSION_1_2);
// Create Vulkan instance to communicate with the loader.
vk::InstanceCreateInfo create_info = {};
create_info.pNext = &features;
create_info.pApplicationInfo = &program_info,
create_info.enabledLayerCount = static_cast<uint32_t>(VALIDATION_LAYERS.size()),
create_info.ppEnabledLayerNames = VALIDATION_LAYERS.data(),
create_info.enabledExtensionCount = static_cast<uint32_t>(required_extensions.size()),
create_info.ppEnabledExtensionNames = required_extensions.data();
auto [result, instance] = vk::createInstanceUnique(create_info);
Assert(result == vk::Result::eSuccess, "Error: Failed to create instance");
However I am getting these errors:
VUID-VkInstanceCreateInfo-pNext-pNext(ERROR / SPEC): msgNum: -1337267667 - Validation Error: [ VUID-VkInstanceCreateInfo-pNext-pNext ] Object 0: VK_NULL_HANDLE, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xb04aea2d | vkCreateInstance: pCreateInfo->pNext chain includes a structure with unexpected VkStructureType VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; Allowed structures are [VkDebugReportCallbackCreateInfoEXT, VkDebugUtilsMessengerCreateInfoEXT, VkValidationFeaturesEXT, VkValidationFlagsEXT]. This error is based on the Valid Usage documentation for version 204 of the Vulkan header. It is possible that you are using a struct from a private extension or an extension that was added to a later version of the Vulkan header, in which case the use of pCreateInfo->pNext is undefined and may not work correctly with validation enabled The Vulkan spec states: Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDebugReportCallbackCreateInfoEXT, VkDebugUtilsMessengerCreateInfoEXT, VkValidationFeaturesEXT, or VkValidationFlagsEXT (https://vulkan.lunarg.com/doc/view/1.3.204.1/linux/1.3-extensions/vkspec.html#VUID-VkInstanceCreateInfo-pNext-pNext)
Objects: 1
[0] 0, type: 3, name: NULL
VUID-VkInstanceCreateInfo-pNext-pNext(ERROR / SPEC): msgNum: -1337267667 - Validation Error: [ VUID-VkInstanceCreateInfo-pNext-pNext ] Object 0: VK_NULL_HANDLE, type = VK_OBJECT_TYPE_INSTANCE; | MessageID = 0xb04aea2d | vkCreateInstance: Includes a pNext pointer (pCreateInfo->pNext) to a VkStructureType (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES), but its parent extension VK_KHR_dynamic_rendering has not been enabled. The Vulkan spec states: Each pNext member of any structure (including this one) in the pNext chain must be either NULL or a pointer to a valid instance of VkDebugReportCallbackCreateInfoEXT, VkDebugUtilsMessengerCreateInfoEXT, VkValidationFeaturesEXT, or VkValidationFlagsEXT (https://vulkan.lunarg.com/doc/view/1.3.204.1/linux/1.3-extensions/vkspec.html#VUID-VkInstanceCreateInfo-pNext-pNext)
Objects: 1
[0] 0, type: 1, name: NULL
My driver, headers and validation layers are the latest version 1.3.204.
If I don;t enable layers and just run my code, things seem to work fine, I can resize my window and rendering is updated as expected. Is this a bug in the validation layers?
Some research suggests I should do this instead:
const std::vector<const char*> device_extensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME,
};
vk::PhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering = {};
dynamic_rendering.dynamicRendering = true;
// Get the features of the selected device.
vk::PhysicalDeviceFeatures device_features = phys_device.getFeatures();
// The enabledLayerCount and ppEnabledLayerNames parameters are deprecated,
// they should always be 0 and nullptr.
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkDeviceCreateInfo.html
vk::DeviceCreateInfo create_info = {};
create_info.pNext = &dynamic_rendering;
create_info.queueCreateInfoCount = queue_create_infos.size();
create_info.pQueueCreateInfos = queue_create_infos.data();
create_info.enabledLayerCount = 0;
create_info.ppEnabledLayerNames = nullptr;
create_info.enabledExtensionCount = device_extensions.size();
create_info.ppEnabledExtensionNames = device_extensions.data();
create_info.pEnabledFeatures = &device_features;
But this is returning the following error:
Message ID name: VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06052
Message: Validation Error: [ VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06052 ] Object 0: handle = 0x2357fc0, name = Logical device: NVIDIA GeForce GTX 1070, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xdf901c9e | vkCreateGraphicsPipeline: pCreateInfos[0].renderPass is VK_NULL_HANDLE but dynamicRendering is not enabled. The Vulkan spec states: If the dynamicRendering feature is not enabled, renderPass must not be VK_NULL_HANDLE (https://vulkan.lunarg.com/doc/view/1.3.204.1/linux/1.3-extensions/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06052)
I don;t understand, I AM enabling the extension.
Following the advice in teh comments, I am seeing this:
vkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice) returns VkResult VK_SUCCESS (0):
physicalDevice: VkPhysicalDevice = 0x32f85c0
pCreateInfo: const VkDeviceCreateInfo* = 0x7fff0d9dbb20:
sType: VkStructureType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO (3)
pNext: const void* = NULL
Which seems to suggest the pNext is not being set properly.
You'll probably need to add VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME to your list of device_extensions. You didn't show the code that sets up that list. The rest of it looks OK.
It isn't that unusual for a driver to go ahead and use a requested feature, even though it isn't enabled. But since that can change from driver to driver, it is always best to enable the extensions and features you need.
During initialization of my program I want to use some single time command buffers for image layout transitions and acceleration structure building etc.
However, I can't seem to free the command buffer once it's finished.
VkCommandBuffer AppContext::singleTimeCommandBuffer() const {
VkCommandBuffer ret;
auto allocInfo = vks::initializers::commandBufferAllocateInfo(vkCommandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1);
vkCheck(vkAllocateCommandBuffers(vkDevice, &allocInfo, &ret));
auto beginInfo = vks::initializers::commandBufferBeginInfo();
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkCheck(vkBeginCommandBuffer(ret, &beginInfo));
return ret;
}
void AppContext::endSingleTimeCommands(VkCommandBuffer cmdBuffer) const {
vkCheck(vkEndCommandBuffer(cmdBuffer));
auto submitInfo = vks::initializers::submitInfo(&cmdBuffer);
vkQueueSubmit(queues.graphics, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(queues.graphics);
// Overkill, I know
vkDeviceWaitIdle(vkDevice);
vkFreeCommandBuffers(vkDevice, vkCommandPool, 1, &cmdBuffer);
}
Which produces the following validation error:
VUID-vkFreeCommandBuffers-pCommandBuffers-00047(ERROR / SPEC): msgNum: 448332540 - Validation Error: [ VUID-vkFreeCommandBuffers-pCommandBuffers-00047 ] Object 0: handle = 0x5586acaeff78, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x1ab902fc | Attempt to free VkCommandBuffer 0x5586acaeff78[] which is in use. The Vulkan spec states: All elements of pCommandBuffers must not be in the pending state (https://vulkan.lunarg.com/doc/view/1.2.182.0/linux/1.2-extensions/vkspec.html#VUID-vkFreeCommandBuffers-pCommandBuffers-00047)
Objects: 1
[0] 0x5586acaeff78, type: 6, name: NULL
I don't see how this makes sense since the VkQueueWaitIdle as well as the vkDeviceWaitIdle should ensure the command buffer to not be in the pending state. Am I misunderstanding the Vulkan specs or might I have stumbled upon a bug in the video driver, or perhaps the validation layer?
You aren't checking the return values of vkQueueSubmit(), vkQueueWaitIdle() or vkDeviceWaitIdle(). Are any of them failing? That could cause this error.
Some of the mesh that I'll be using doesn't always have a DiffuseMap or a SpecularMap. When I try to load something without a diffuse and specular map the program crashes because there's nothing in the DiffuseMap.ImageView/SpecularMap.ImageView because it isn't pointing to anything. If I try to set the imageview/sample to VK_NULL_HANDLE the program gives me this and crashes at the vkUpdateDescriptorSets:
Validation Layer: Invalid VkImageView Object 0x0. The Vulkan spec states: If descriptorType is VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, or VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, the imageView and imageLayout members of each element of pImageInfo must be a valid VkImageView and VkImageLayout, respectively (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkWriteDescriptorSet-descriptorType-00326)
Then if I just try set the binding to null, I get this:
Validation Layer: vkUpdateDescriptorSets: required parameter pDescriptorWrites[2].dstSet specified as VK_NULL_HANDLE
Validation Layer: Cannot call vkUpdateDescriptorSets() on VkDescriptorSet 0x0[] that has not been allocated.
This is what the base code looks like right now. This is the area that defines the descriptor sets to make it bit easier to see what's going on:
void Mesh::CreateDescriptorSets(VulkanRenderer& Renderer)
{
BaseMesh::CreateDescriptorSets(Renderer, *GetDescriptorSetLayout(Renderer));
VkDescriptorImageInfo DiffuseMap = {};
DiffuseMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
DiffuseMap.imageView = TextureList[0].textureImageView;
DiffuseMap.sampler = TextureList[0].textureSampler;
VkDescriptorImageInfo SpecularMap = {};
SpecularMap.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
SpecularMap.imageView = TextureList[1].textureImageView;
SpecularMap.sampler = TextureList[1].textureSampler;
for (size_t i = 0; i < GetSwapChainImageCount(Renderer); i++)
{
VkDescriptorBufferInfo PositionInfo = {};
PositionInfo.buffer = uniformBuffers[i];
PositionInfo.offset = 0;
PositionInfo.range = sizeof(UniformBufferObject);
VkDescriptorBufferInfo AmbiantLightInfo = {};
AmbiantLightInfo.buffer = AmbientLightUniformBuffers[i];
AmbiantLightInfo.offset = 0;
AmbiantLightInfo.range = sizeof(AmbientLightUniformBuffer);
VkDescriptorBufferInfo LightInfo = {};
LightInfo.buffer = LighterUniformBuffers[i];
LightInfo.offset = 0;
LightInfo.range = sizeof(Lighter);
std::array<WriteDescriptorSetInfo, 5> WriteDescriptorInfo = {};
WriteDescriptorInfo[0].DstBinding = 0;
WriteDescriptorInfo[0].DstSet = descriptorSets[i];
WriteDescriptorInfo[0].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[0].DescriptorBufferInfo = PositionInfo;
WriteDescriptorInfo[1].DstBinding = 1;
WriteDescriptorInfo[1].DstSet = descriptorSets[i];
WriteDescriptorInfo[1].DescriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
WriteDescriptorInfo[1].DescriptorImageInfo = DiffuseMap;
WriteDescriptorInfo[2].DstBinding = 2;
WriteDescriptorInfo[2].DstSet = descriptorSets[i];
WriteDescriptorInfo[2].DescriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
WriteDescriptorInfo[2].DescriptorImageInfo = SpecularMap;
WriteDescriptorInfo[3].DstBinding = 3;
WriteDescriptorInfo[3].DstSet = descriptorSets[i];
WriteDescriptorInfo[3].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[3].DescriptorBufferInfo = AmbiantLightInfo;
WriteDescriptorInfo[4].DstBinding = 4;
WriteDescriptorInfo[4].DstSet = descriptorSets[i];
WriteDescriptorInfo[4].DescriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
WriteDescriptorInfo[4].DescriptorBufferInfo = LightInfo;
Mesh::CreateDescriptorSetsData(Renderer, std::vector<WriteDescriptorSetInfo>(WriteDescriptorInfo.begin(), WriteDescriptorInfo.end()));
}
}
Until Vulkan 1.2, Vulkan did not recognize the possibility of a descriptor being "empty". When a descriptor set is created, the descriptors are (mostly) uninitialized. It's OK to have a set with an uninitialized descriptor, so long as the pipeline which consumes it does not statically use the descriptor. Since you are presumably trying to use the same pipeline for objects with diffuse maps and objects without them, your shader reads from the image based on a variable you provide. That represents static use of the descriptor, so you need an image there.
The typical way to deal with this is to create a tiny image of a reasonable format and stuff that into the descriptor. You can use the same image for essentially any "null" texture you want to use.
Vulkan 1.2, as part of the VK_EXT_descriptor_indexing extension promoted to core, allows for the possibility of partially bound descriptors. Basically, if the descriptorBindingPartiallyBound feature is available and requested, then you can allocate a descriptor set using the VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT bit. This means that it's OK to leave a descriptor undefined so long as it is not dynamically used.
So you simply wouldn't write a value for that descriptor.
Of course, this requires 1.2 (or the aforementioned extension), as well as requesting the feature.
You are not quite correct, a combined image sampler still requires a valid sampler for some reason, and not only that, a nullDescriptor functionality have to be enabled. I run into exactly the same problem. What noone ever tells is that partly bound descriptors is not the same as sparsly bound descriptors, so it basicaly means y can bind X descriptors out of N if X<N but all those X must be valid, the specs is realy thin on this and there is no good examples.
I've started to learn DirectX12 and i try to make some kind of simple engine.
I follow the Frank D. Luna "Introduction to 3D programming with DirectX12" and i have got some problems.
First during creating swapChain, filling description like this:
DXGI_SWAP_CHAIN_DESC swapChainDesc;
swapChainDesc.BufferDesc.Width = Core::displayWidth;
swapChainDesc.BufferDesc.Height = Core::displayHeight;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferDesc.Format = Core::pixelDefinitionFormat;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.SampleDesc.Count = Core::multiSamplingLevel ? 4 : 1;
swapChainDesc.SampleDesc.Quality = Core::multiSamplingEnabled ? (Core::multiSamplingLevel - 1) : 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = (INT) Core::buffering;
swapChainDesc.OutputWindow = Core::mainWindow;
swapChainDesc.Windowed = true;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
// Note: Swap chain uses queue to perform flush.
ThrowIfFailed(Core::factory->CreateSwapChain(
Core::commandQueue.Get(),
&swapChainDesc,
Core::swapChain.GetAddressOf()
));
I recive "bad parameter" error. I've already found solution on MSDN but i want to know what i'am doing wrong.
Second question is why have i:
D3D12 ERROR: ID3D12GraphicsCommandList::*: A single command list cannot write to multiple buffers within a particular swapchain. [ STATE_SETTING ERROR #904: COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES]
Durning execution of this clearing screen code fragment:
void Renderer::drawSomething() {
// Reuse the memory associated with command recording.
// We can only reset when the associated command lists have finished
// execution on the GPU.
ThrowIfFailed(Core::commandAllocator->Reset());
// A command list can be reset after it has been added to the
// command queue via ExecuteCommandList. Reusing the command list reuses memory.
ThrowIfFailed(Core::commandList->Reset(Core::commandAllocator.Get(), NULL));
// Set the viewport and scissor rect. This needs to be reset
// whenever the command list is reset.
Core::commandList->RSSetViewports(1, &Core::viewport);
Core::commandList->RSSetScissorRects(1, &Core::scissorsRectangle);
// Indicate a state transition on the resource usage.
Core::commandList->ResourceBarrier(
1,
&CD3DX12_RESOURCE_BARRIER::Transition(
Core::getCurrentBackBuffer().Get(),
D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_PRESENT,
D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_RENDER_TARGET
)
);
// Specify the buffers we are going to render to.
Core::commandList->OMSetRenderTargets(
1,
&Core::getCurrentBackBufferView(),
true,
&Core::getDSVHeapStartDescriptorHandle()
);
// Clear the back buffer and depth buffer.
Core::commandList->ClearRenderTargetView(
Core::getCurrentBackBufferView(),
DirectX::Colors::LightSteelBlue,
0,
NULL
);
Core::commandList->ClearDepthStencilView(
Core::getDSVHeapStartDescriptorHandle(),
D3D12_CLEAR_FLAGS::D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAGS::D3D12_CLEAR_FLAG_STENCIL,
1.0f,
0,
0,
NULL
);
//// Indicate a state transition on the resource usage.
Core::commandList->ResourceBarrier(
1,
&CD3DX12_RESOURCE_BARRIER::Transition(
Core::getCurrentBackBuffer().Get(),
D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_PRESENT
)
);
// Done recording commands.
ThrowIfFailed(Core::commandList->Close());
// Add the command list to the queue for execution.
ID3D12CommandList* cmdsLists[] = {Core::commandList.Get()};
Core::commandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
// swap the back and front buffers
ThrowIfFailed(Core::swapChain->Present(0, 0));
UINT buffering = Core::buffering;
Core::currentBackBuffer = (Core::currentBackBuffer + 1) % buffering;
Core::flushCommandQueue();
}
To not making big mess in this post, i won't place all code here, but if you would like to look how does it look like, or it would be important in this case, my whole repository is here:
repository
It's very small and simlple, almost all code is placed in Core class.
Thank you in advance!
Edit:
I found solution to second question.
Problem was in this loop:
void Core::createSwapChainBuffersIntoRTVHeap() {
for (UINT i = 0; i < Core::buffering; i++) {
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHeapHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
ErrorUtils::messageAndExitIfFailed(
swapChain->GetBuffer(i, IID_PPV_ARGS(&swapChainBackBuffers[i])),
L"B³¹d pobierania backBuffera!",
GET_SWAPCHAIN_BACK_BUFFER_ERROR
);
device->CreateRenderTargetView(swapChainBackBuffers[i].Get(), NULL, rtvHeapHandle);
//Zapamiêtuje offset, to jest sterta po prostu zwyk³a
rtvHeapHandle.Offset(1, rtvDescriptorSize);
}
}
I did only one move to made this code look like this:
void Core::createSwapChainBuffersIntoRTVHeap() {
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHeapHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
for (UINT i = 0; i < Core::buffering; i++) {
ErrorUtils::messageAndExitIfFailed(
swapChain->GetBuffer(i, IID_PPV_ARGS(&swapChainBackBuffers[i])),
L"B³¹d pobierania backBuffera!",
GET_SWAPCHAIN_BACK_BUFFER_ERROR
);
device->CreateRenderTargetView(swapChainBackBuffers[i].Get(), NULL, rtvHeapHandle);
//Zapamiêtuje offset, to jest sterta po prostu zwyk³a
rtvHeapHandle.Offset(1, rtvDescriptorSize);
}
}
After that. When the commandList closing gone right, i've got AccessViolationException in D3D12.dll on:
ThrowIfFailed(Core::swapChain->Present(0, 0));
Which after few hours of internet research i fixed by forcing WARP on this application using "dxcpl.exe".
I assume that was because i work on laptop with HD4000 and Nvidia as second card, but i'm not sure.
This will not help you to fix the problem at once, but will give you much more information. DirectX12 wants you to push all commands into commandlists and it will only report an error when you call Close() on it. Note that you can not "resurrect" the commandlist that failed on Close() by resetting it, the best thing you can do is to delete it and then create a new commandlist. In this case you however may not update referenced resources. Don't really recommend you doing that.
What you indeed can do is to use the ID3D12InfoQueue interface to make your program break on D3D12 errors if the debugger is attached.
Get it from your device:
ID3D12InfoQueue* InfoQueue = nullptr;
Core::device->QueryInterface(IID_PPV_ARGS(&InfoQueue));
Enable "break on severity":
InfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
InfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
InfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, false);
And let it go:
InfoQueue->Release();
You can also set your InfoQueue to whitelist or blacklist sets of D3D12 error ids. Your error ID is D3D12_MESSAGE_ID_COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES (code 904).
Hope that this will help someone to deal with this graphics API.
I'm following the Rastertek Tutorials on Direct3D12, which can be found here.
I've double-checked to make sure all my code is the same as his, but I'm running into issues with the Command List. When I close the command list after just clearing the back buffer, the method ID3D12GraphicsCommandList::Close() returns E_INVALIDARG, which means that I've done something wrong during recording of the Command List. However, nothing I'm doing seems to be wrong.
D3D12_RESOURCE_BARRIER Barrier;
hr = CommandAllocator->Reset(); HANDLE_HR(__LINE__);
hr = CommandList->Reset (
CommandAllocator,
nullptr
); HANDLE_HR(__LINE__);
Barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
Barrier.Transition.pResource = RenderTargetResource[BufferIndex];
Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
Barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
Barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
CommandList->ResourceBarrier(1, &Barrier);
RenderTargetViewPtr.ptr = RenderTargetViewHandle.ptr + BufferIndex * RenderTargetBytes;
CommandList->OMSetRenderTargets(1, &RenderTargetViewPtr, FALSE, nullptr);
FLOAT color[] = { 1.0, 1.0, 1.0, 1.0 };
CommandList->ClearRenderTargetView(RenderTargetViewHandle, color, 0, nullptr);
Barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
Barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
CommandList->ResourceBarrier(1, &Barrier);
hr = CommandList->Close(); HANDLE_HR(__LINE__);
The entirety of my project can be found at this github branch.
What is the issue with this code?
It seems like the resource barriers are the problem, but they're rather innocuous. Commenting out OMSetRenderTargets() and ClearRenderTargetView() still results in E_INVALIDARG being returned from Close().
I've also tried using the ID3D12InfoQueue interface to find out what the problem was. There are no messages in the queue when Close() returns the error - I've checked to make sure the interface is working properly, since messages do show up when other errors occur.