Как повторно использовать выделенный ресурс в качестве буфера вывода потока в DX12 после чтения его обратно
Чтобы помочь отладить мой графический пиплейн, я хочу транслировать входные данные моего шейдера по запросу (через комбинацию клавиш). Я создал выделенный ресурс, который я использую в качестве цели вывода потока в DX12, следующим образом:
D3D12_HEAP_PROPERTIES heap_prop;
heap_prop.Type = D3D12_HEAP_TYPE_DEFAULT;
heap_prop.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heap_prop.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heap_prop.CreationNodeMask = 0;
heap_prop.VisibleNodeMask = 0;
D3D12_RESOURCE_DESC res_desc;
res_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
res_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
res_desc.Width = BufferSize;
res_desc.Height = 1;
res_desc.DepthOrArraySize = 1;
res_desc.MipLevels = 1;
res_desc.Format = DXGI_FORMAT_UNKNOWN;
res_desc.SampleDesc.Count = 1;
res_desc.SampleDesc.Quality = 0;
res_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
res_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
buffer.Reset();
device->CreateCommittedResource(&heap_prop, D3D12_HEAP_FLAG_NONE, &res_desc, D3D12_RESOURCE_STATE_STREAM_OUT, NULL, __uuidof(ID3D12Resource), void**)&buffer);
Я могу записать данные из моего шейдера в буфер, а затем прочитать их обратно в процессор следующим образом:
readbackCommandAllocator->Reset();
readbackCommandList->Reset(readbackCommandAllocator.Get(), nullptr);
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = buffer.Get();
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_STREAM_OUT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE;
readbackCommandList->ResourceBarrier(1, &barrier);
readbackCommandList->CopyBufferRegion(readbackBuffer.Get(), 0, buffer.Get(), 0, totalBytesWritten);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_STREAM_OUT;
readbackCommandList->ResourceBarrier(1, &barrier);
В течение кадра я выполняю несколько вызовов отрисовки, каждый из которых я передаю в другую часть буфера вывода потока, устанавливая различные смещения от начала буфера в структуре D3D12_STREAM_OUTPUT_BUFFER_VIEW. Это работает в первом кадре, и файл, в который я записываю данные, является правильным, однако я обнаружил, что во втором кадре, в котором я запрашиваю поток, используя тот же буфер потока, данные неверны. В частности, в первом кадре у меня есть сетка из 100 вершин, которую я направляю в смещение 8 в буфере (смещение 0-7 - это D3D12_STREAM_OUTPUT_BUFFER_VIEW.BufferFilledSizeLocation для рисования), а во втором кадре я хочу передать другую сетку с 200 Вертс в ту же самую область памяти GPU. Во втором кадре я транслирую 100-вертовую сетку в другое смещение графического процессора (я использую несколько потоков для создания списков команд, поэтому порядок выполнения списков команд меняется). После второго кадра я обнаружил, что смещение 8 буфера содержит 100 вершин от первого кадра, за которыми следуют 200 вершин от второго кадра, даже если у сетки с 100 вертами было другое целевое расположение памяти во втором кадре и сетке с 200 вертами должно отображаться со смещением 8. После кадра D3D12_STREAM_OUTPUT_BUFFER_VIEW.BufferFilledSizeLocation со смещением 0 содержит значение 200* шага, означающее, что было записано 200* байтов шага. Я ожидаю, что 200 вертов, написанных со смещения 8, появятся сразу после этого, но вместо этого после него появятся 100 вершин из сетки 100 вершин, а 200 вершин из сетки 200 вершин появятся после 100 вершин. Между 100 и 200 вертами также нет никакого BufferFilledSize, что также странно - 200 вершин следуют сразу за 100 вертами. Я обнаружил, что если я воссоздаю буфер потоковой передачи перед каждым кадром потоковой передачи, буфер заполняется правильно. Почему я получаю повреждение в буфере потоковой передачи, когда я использую его каждый кадр вместо создания нового буфера? Как правильно переинициализировать буфер потоков между использованиями?