0
\$\begingroup\$

I am trying to implement the d3d12 window resizing function. First, I delete all the buffers referenced by SwapChain, and then run SwapChain :: ResizeBuffers. At this point I get the error:

D3D12 ERROR: ID3D12Resource1::<final-release>: CORRUPTION: An ID3D12Resource object (0x000002323B7029A0:'Unnamed Object') is referenced by GPU operations in-flight on Command Queue (0x000002323B6BFD00:'Command queue'). 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]
Exception thrown at 0x00007FF89004A839 (KernelBase.dll) in dx12_buffers_learn.exe: 0x0000087D (parameters: 0x0000000000000000, 0x000000712E99AE80, 0x0000023238E800D0).
Unhandled exception at 0x00007FF89004A839 (KernelBase.dll) in dx12_buffers_learn.exe: 0xC000041D: 

This is the code of the procedure for changing sizes of window:

bool resize(int w, int h)
{
    if (device && swapChain && commandAllocator[frameIndex])
    {
        WaitForPreviousFrame();
        if (FAILED(commandAllocator[frameIndex]->Reset())) return false;
        if (FAILED(commandList->Reset(commandAllocator[frameIndex].Get(), nullptr))) return false;
        for (int i(0); i < frameBufferCount; i++)
            renderTargets[i].Reset();
        if (FAILED(swapChain->ResizeBuffers(frameBufferCount, w, h, backBufferFormat, NULL))) return false;
        frameIndex = 0;
        if (!createBackBuffer()) return false;
        createViewport();
        createScissor();
        if (FAILED(commandList->Close())) return false;
        vector<ID3D12CommandList*> cmdsLists = { commandList.Get() };
        commandQueue->ExecuteCommandLists(cmdsLists.size(), cmdsLists.data());
    }
    return true;
}

I put together a minimal self sufficient example for modeling the problem that described above:

#include <windows.h>
#include <d3d12.h>
#include <dxgi1_4.h>
#include "d3dx12.h"
#include <wrl.h>
#include <vector>
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3d12.lib")
using namespace std;
using Microsoft::WRL::ComPtr;

void updateSize();
bool InitializeWindow(HINSTANCE hInstance);
bool resize(int w, int h);
void mainloop();
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool InitD3D();
void UpdatePipeline();
void Render();
void WaitForPreviousFrame();
bool createBackBuffer();
void createViewport();
void createScissor();

HWND hwnd = nullptr;
int widthClient = 900;
int heightClient = 650;
int startWidth;
int startHeight;
int widthWindow;
int heightWindow;
int frameBufferCount = 3;
ComPtr<IDXGIFactory4> dxgiFactory;
DXGI_FORMAT backBufferFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
ComPtr < ID3D12Device> device;
ComPtr<IDXGISwapChain3> swapChain;
ComPtr < ID3D12CommandQueue> commandQueue;
ComPtr < ID3D12DescriptorHeap> rtvDescriptorHeap;
vector< ComPtr<ID3D12Resource>> renderTargets;
vector< ComPtr<ID3D12CommandAllocator>> commandAllocator;
ComPtr < ID3D12GraphicsCommandList> commandList;
vector< ComPtr<ID3D12Fence>> fence;
HANDLE fenceEvent = nullptr;
vector<unsigned long long> fenceValue;
int frameIndex = 0;
int rtvDescriptorSize = -1;
D3D12_VIEWPORT viewport;
D3D12_RECT scissorRect;
bool vsync = false;
float color[] = { 0.53f, 0.53f, 0.53f, 1.f };

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    if (!InitializeWindow(hInstance)) return -1;
    if (!InitD3D()) return -1;
    mainloop();
    WaitForPreviousFrame();
    return 0;
}

void updateSize()
{
    RECT windowRect;
    GetClientRect(hwnd, &windowRect);
    widthClient = windowRect.right;
    heightClient = windowRect.bottom;
    startWidth = windowRect.left;
    startHeight = windowRect.top;
    GetWindowRect(hwnd, &windowRect);
    widthWindow = windowRect.right - windowRect.left;
    heightWindow = windowRect.bottom - windowRect.top;
}

bool InitializeWindow(HINSTANCE hInstance)
{
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
    wc.lpszClassName = L"dx12_className";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    if (!RegisterClassEx(&wc)) return false;
    if(!(hwnd = CreateWindowEx(NULL, L"dx12_className", L"DX12 Render Triangles", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, widthClient, heightClient, NULL, NULL, hInstance, NULL))) return false;
    updateSize();
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);
    return true;
}

void mainloop()
{
    MSG msg = {};
    while (true)
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
            Render();
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY: // x button on top right corner of window was pressed
        PostQuitMessage(0);
        return 0;
    case WM_SIZE:
        updateSize();
        if (!resize(widthWindow, heightWindow))
        {
            DestroyWindow(hwnd);
            return 0;
        }
        break;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

bool InitD3D()
{
    // init
    renderTargets.resize(frameBufferCount);
    commandAllocator.resize(frameBufferCount);
    fence.resize(frameBufferCount);
    fenceValue = { 0,0,0 };
    // debug
    ComPtr<ID3D12Debug> debugController;
    if (FAILED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) return false;
    debugController->EnableDebugLayer();
    // dxgi factory
    if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(dxgiFactory.GetAddressOf())))) return false;
    // device
    if (FAILED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.GetAddressOf())))) return false;
    // queue
    D3D12_COMMAND_QUEUE_DESC cqDesc = {};
    cqDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    cqDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 
    if (FAILED(device->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(commandQueue.GetAddressOf())))) return false;
    commandQueue->SetName(L"Command queue");
    // swap chain
    DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
    swapChainDesc.Format = backBufferFormat;
    swapChainDesc.Stereo = FALSE;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = frameBufferCount;
    swapChainDesc.Scaling = DXGI_SCALING_NONE;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
    ComPtr<IDXGISwapChain1> tempSwapChain;
    if (FAILED(dxgiFactory->CreateSwapChainForHwnd(commandQueue.Get(), hwnd, &swapChainDesc, nullptr, nullptr, tempSwapChain.GetAddressOf()))) return false;
    if(!(swapChain = static_cast<IDXGISwapChain3*>(tempSwapChain.Get()))) return false;
    frameIndex = swapChain->GetCurrentBackBufferIndex();
    DXGI_RGBA swapChainBkColor = { color[0], color[1], color[2], color[3] };
    if (FAILED(swapChain->SetBackgroundColor(&swapChainBkColor))) return false;
    // back buffers
    if (!createBackBuffer()) return false;
    // viewport
    createViewport();
    // scissor
    createScissor();
    // allocators
    for (int i = 0; i < frameBufferCount; i++)
        if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(commandAllocator[i].GetAddressOf())))) return false;
    // list
    if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator[frameIndex].Get(), NULL, IID_PPV_ARGS(commandList.GetAddressOf())))) return false;
    // fence
    for (int i = 0; i < frameBufferCount; i++)
        if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(fence[i].GetAddressOf())))) return false;
    if(!(fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr))) return false;
    // closed list
    commandList->Close();
    vector<ID3D12CommandList*> cmdsLists = { commandList.Get() };
    commandQueue->ExecuteCommandLists(cmdsLists.size(), cmdsLists.data());
    return true;
}

bool resize(int w, int h)
{
    if (device && swapChain && commandAllocator[frameIndex])
    {
        WaitForPreviousFrame();
        if (FAILED(commandAllocator[frameIndex]->Reset())) return false;
        if (FAILED(commandList->Reset(commandAllocator[frameIndex].Get(), nullptr))) return false;
        for (int i(0); i < frameBufferCount; i++)
            renderTargets[i].Reset();
        if (FAILED(swapChain->ResizeBuffers(frameBufferCount, w, h, backBufferFormat, NULL))) return false;
        frameIndex = 0;
        if (!createBackBuffer()) return false;
        createViewport();
        createScissor();
        if (FAILED(commandList->Close())) return false;
        vector<ID3D12CommandList*> cmdsLists = { commandList.Get() };
        commandQueue->ExecuteCommandLists(cmdsLists.size(), cmdsLists.data());
    }
    return true;
}

void UpdatePipeline()
{
    WaitForPreviousFrame();
    commandAllocator[frameIndex]->Reset();
    commandList->Reset(commandAllocator[frameIndex].Get(), nullptr);
    commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(renderTargets[frameIndex].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), frameIndex, rtvDescriptorSize);
    commandList->ClearRenderTargetView(rtvHandle, color, 0, nullptr);
    commandList->RSSetViewports(1, &viewport); 
    commandList->RSSetScissorRects(1, &scissorRect); 
    commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(renderTargets[frameIndex].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
    commandList->Close();
}

void Render()
{
    UpdatePipeline();
    vector<ID3D12CommandList*> ppCommandLists = { commandList.Get() };
    commandQueue->ExecuteCommandLists(ppCommandLists.size(), ppCommandLists.data());
    commandQueue->Signal(fence[frameIndex].Get(), fenceValue[frameIndex]);
    swapChain->Present(vsync ? 1 : 0, 0);
}

void WaitForPreviousFrame()
{
    frameIndex = swapChain->GetCurrentBackBufferIndex();
    if (fence[frameIndex]->GetCompletedValue() < fenceValue[frameIndex])
    {
        fence[frameIndex]->SetEventOnCompletion(fenceValue[frameIndex], fenceEvent);
        WaitForSingleObject(fenceEvent, INFINITE);
    }
    fenceValue[frameIndex]++;
}

bool createBackBuffer()
{
    D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
    rtvHeapDesc.NumDescriptors = frameBufferCount;
    rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
    rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
    if (FAILED(device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(rtvDescriptorHeap.GetAddressOf()))))
        return false;
    rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
    for (int i = 0; i < frameBufferCount; i++)
    {
        if (FAILED(swapChain->GetBuffer(i, IID_PPV_ARGS(renderTargets[i].GetAddressOf()))))
            return false;
        device->CreateRenderTargetView(renderTargets[i].Get(), nullptr, rtvHandle);
        rtvHandle.Offset(1, rtvDescriptorSize);
    }
    return true;
}

void createViewport()
{
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = widthClient;
    viewport.Height = heightClient;
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;
}

void createScissor()
{
    scissorRect.left = 0;
    scissorRect.top = 0;
    scissorRect.right = widthClient;
    scissorRect.bottom = heightClient;
}

Tell me how to fix this problem.

UPD1

I set my RTV names and text error replace:

D3D12 ERROR: ID3D12Resource1::<final-release>: CORRUPTION: An ID3D12Resource object (0x000001E405CEB230:'back buffer #1')...

D3D12 ERROR: ID3D12Resource1::<final-release>: CORRUPTION: An ID3D12Resource object (0x0000022F37904B10:'back buffer #3')

RTV number is always random.

\$\endgroup\$
0
\$\begingroup\$

I have to wait for my GPU to idle before I can resize.

This code make wait GPU:

void flushGpu()
{
    for (int i = 0; i < frameBufferCount; i++)
    {
        uint64_t fenceValueForSignal = ++fenceValue[i];
        commandQueue->Signal(fence[i].Get(), fenceValueForSignal);
        if (fence[i]->GetCompletedValue() < fenceValue[i])
        {
            fence[i]->SetEventOnCompletion(fenceValueForSignal, fenceEvent);
            WaitForSingleObject(fenceEvent, INFINITE);
        }
    }
    frameIndex = 0;
    // Thank you gamedev
}
\$\endgroup\$
  • 1
    \$\begingroup\$ You should take a look at the DirectX 12 implementation of DeviceResources on GitHub h cpp \$\endgroup\$ – Chuck Walbourn Sep 12 at 19:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.