When trying to re-create my vertex buffers, my app crashes and I get this error:
D3D12 ERROR: ID3D12Resource2::: CORRUPTION: An ID3D12Resource object (0x000001DDEBA98FC0:'Vertex Buffer Default Resource Heap') is referenced by GPU operations in-flight on Command Queue (0x000001DDEB80E3A0:'Unnamed ID3D12CommandQueue Object'). It is not safe to final-release objects that may have GPU operations pending. This can result in application instability. [ EXECUTION ERROR #921: OBJECT_DELETED_WHILE_STILL_IN_USE]
Here is my function called create_vertex_buffers()
:
// a triangle
Vertex verts[] = {
Vertex(0.0f, 0.5f, 0.5f),
Vertex(0.5f, -0.5f, 0.5f),
Vertex(-0.5f, -0.5f, 0.5f),
};
const UINT verts_size = sizeof(verts);
// create default heap
auto buffer = CD3DX12_RESOURCE_DESC::Buffer(verts_size);
auto heap_properties1 = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
device->CreateCommittedResource(
&heap_properties1, // a default heap
D3D12_HEAP_FLAG_NONE, // no flags
&buffer, // resource description for a buffer
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&vertex_buffer));
// create upload heap
// upload heaps are used to upload data to the GPU. CPU can write to it, GPU can read from it
// We will upload the vertex buffer using this heap to the default heap
auto heap_properties2 = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
auto buffer2 = CD3DX12_RESOURCE_DESC::Buffer(verts_size);
device->CreateCommittedResource(
&heap_properties2, // upload heap
D3D12_HEAP_FLAG_NONE, // no flags
&buffer2, // resource description for a buffer
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&vertex_buffer_upload));
D3D12_SUBRESOURCE_DATA vertex_data = {};
vertex_data.pData = reinterpret_cast<BYTE*>(verts); // pointer to our vertex array
vertex_data.RowPitch = verts_size; // size of all our triangle vertex data
vertex_data.SlicePitch = verts_size; // also the size of our triangle vertex data
UpdateSubresources(command_list.Get(), vertex_buffer.Get(), vertex_buffer_upload.Get(), 0, 0, 1, &vertex_data);
auto transition = CD3DX12_RESOURCE_BARRIER::Transition(vertex_buffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
command_list->ResourceBarrier(1, &transition);
vertex_buffer_view.BufferLocation = vertex_buffer->GetGPUVirtualAddress();
vertex_buffer_view.StrideInBytes = sizeof(Vertex);
vertex_buffer_view.SizeInBytes = verts_size;
It is my function for creating the vertex upload and default buffers. I implement it into my command queue like this:
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(render_targets[frame_index].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
command_list->ResourceBarrier(1, &barrier);
// -------------------------+
create_vertex_buffers(); // | <== This is where I'm calling it!!
// -------------------------+
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle(rtv_descriptor_heap->GetCPUDescriptorHandleForHeapStart(), frame_index, rtv_descriptor_size);
CD3DX12_CPU_DESCRIPTOR_HANDLE dsv_handle(depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart());
command_list->OMSetRenderTargets(1, &rtv_handle, FALSE, &dsv_handle);
command_list->ClearRenderTargetView(rtv_handle, color, 0, nullptr);
command_list->ClearDepthStencilView(depth_stencil_descriptor_heap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
command_list->SetPipelineState(pipeline_state_object.Get());
command_list->SetGraphicsRootSignature(root_signature.Get()); // set the root signature
command_list->RSSetViewports(1, &viewport); // set the viewports
command_list->RSSetScissorRects(1, &scissor_rect); // set the scissor rects
command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // set the primitive topology
command_list->IASetVertexBuffers(0, 1, &vertex_buffer_view); // set the vertex buffer (using the vertex buffer view)
command_list->DrawInstanced(3, 1, 0, 0); // finally draw 3 vertices (draw the triangle)
barrier = CD3DX12_RESOURCE_BARRIER::Transition(render_targets[frame_index].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
command_list->ResourceBarrier(1, &barrier);
I have tried adding a fence after creating the resources and waiting for that fence before calling DrawInstanced()
, in case it's still making them once it's started drawing. I tried moving where I call create_vertex_buffers()
.
I'm unsure of when I should be creating these buffers. I'm planning on later only creating them when necessary, which will be every so often, not every frame.
As you can see my command list does the following in order:
- Empties (or at least tries to) and re-creates my default and upload heaps for vertex buffering
- Sets the render targets + depth stencil
- Clears the render target view
- Clears the depth stencil view
- Sets the pipeline state
- Sets the root signature
- Sets the viewport(s)
- Sets the scissor rect(s)
- Sets the primitive topology
- Sets the vertex buffer(s)
- Draws