Войти
ФлеймФорумПроЭкты

FrameGraph (8 стр)

Страницы: 17 8 9 10 11 Следующая »
#105
16:33, 11 апр 2019

Suslik
> при расстановке барьеров я автоматически меняю лейаут и передаю владение, если необходимо.
То есть сабмитишь командный буфер, где ресурс освобождается из очереди?

> однако, ремарка: у меня сейчас compute и graphics queue используют один и тот же queue family index,
Вообще не факт, что они будут параллельно выполняться. Я думаю 2 очереди с одним queue family используют один и тот же командный процессор, просто он будет чередовать эти команды, но не может их распараллеливать. А если разные queue family, то и командные процессоры разные, тем более для async compute там намного больше блоков которые обрабатывают команды.

> поэтому я пока не тестировал, если они действительно разные. может быть какой-то баг, о котором я пока не догадываюсь.
queue ownership transfer нужен только для разных queue family, а если ты не производишь корректную передачу владения, то это UB и содержимое ресурса может быть утеряно.

#106
16:34, 11 апр 2019

/A\
> Проблема в том, что не удобно руками указывать все эти атласы.
всё равно не понимаю, в чём проблема. сами юникодные страницы с глифами (или откуда ты там копируешь глифы?) вообще нигде указывать не надо, так как они всегда в одном лейауте для чтения. атласы же, в которые дописываешь глифы, указываешь как рендертаргет в пассе, который в них глифы добавляет, и как ресурс на чтение в пассе, который рендерит текст. что здесь именно неудобно?

> То есть сабмитишь командный буфер, где ресурс освобождается из очереди?
в принципе, как я ищу последний пасс, использовавший ресурс, можно точно так же найти и следующий пасс, который будет использовать этот ресурс. сейчас я ставлю барьер непосредственно перед использованием, который забирает ownership себе в том командном буфере, где он будет использоваться. но точно так же можно поставить другой барьер, который передаст ownership другому queue сразу после использования.

> queue ownership transfer нужен только для разных queue family, а если ты не производишь корректную передачу владения, то это UB и содержимое ресурса может быть утеряно.
насколько я помню, это не UB, а разрешено спекой и содержимое ресурса автоматически обнуляется, если не передать владение явно. я в курсе, что передача нужна только для разных family index — она у меня реализована, но я её по факту не тестил, так как индекс получается всегда один.

#107
16:41, 11 апр 2019

Suslik
> указываешь как рендертаргет в пассе, который в них глифы добавляет, и как
> ресурс на чтение в пассе, который рендерит текст. что здесь именно неудобно?
Неудобно то, что пасс, который грузит новые глифы не знает ни про какие другие пассы.

> но точно так же можно поставить другой барьер, который передаст ownership другому queue сразу после использования.
А как ты передаешь ownership если у тебя один и тот же queue family ?

#108
16:45, 11 апр 2019

/A\
> Неудобно то, что пасс, который грузит новые глифы не знает ни про какие другие
> пассы.
а, ну так это проблема установки зависимостей между пассами. у меня-то такой проблемы вообще нет, потому что пассы сабмитятся последовательно, гарантированно один за другим. зависимостей между пассами вообще нет, зависимости есть только через доступ к одним и тем же ресурсам. поэтому несмотря на то, что сабмитятся пассы последовательно, исполняться они могут всё равно параллельно, если между ними нет зависимостей.

> А как ты передаешь ownership если у тебя один и тот же queue family ?

        if (srcImageAccessPattern.queueFamilyIndex == dstImageAccessPattern.queueFamilyIndex)
        {
          imageBarrier
            .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
            .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED);
        }
        else
        {
          imageBarrier
            .setSrcQueueFamilyIndex(srcImageAccessPattern.queueFamilyIndex)
            .setDstQueueFamilyIndex(dstImageAccessPattern.queueFamilyIndex);
        }
#109
16:48, 11 апр 2019

короче, вот так я расставляю барьеры для image'ей перед исполнением таска dstTaskIndex:

        for (uint32_t mipLevel = imageView->GetBaseMipLevel(); mipLevel < imageView->GetBaseMipLevel() + imageView->GetMipLevelsCount(); mipLevel++)
        {
          auto lastUsageType = GetLastImageSubresourceUsageType(dstTaskIndex, imageView->GetImageData(), mipLevel, arrayLayer);
          if (prevSubresourceUsageType != lastUsageType)
          {
            FlushImageTransitionBarriers(imageView->GetImageData(), range, prevSubresourceUsageType, dstUsageType, srcStage, dstStage, imageBarriers);
            range
              .setBaseMipLevel(mipLevel)
              .setLevelCount(0);
            prevSubresourceUsageType = lastUsageType;
          }
          range.levelCount++;
        }

> В спеке сказано, что содержимое ресурса может быть утеряно, но у меня оно не терялось. Поэтому я и сказал что UB, так как оно может работать, а может и нет и ты не сразу увидишь ошибку, а слой валидации это не отслеживает.
окей, приму к сведенью. но точно помню, что это — не запрещённая операция. то есть если тебе всё равно на содержимое ресурса, ты можешь не указывать явно барьер для передачи его владения. это может быть очень полезно для случая, когда ресурс в кадре не использовался (неизвестно, кому он принадлежит), но его всё равно очищать надо. поэтому оно, наверное, и не репортится validation layer'ом.

#110
16:48, 11 апр 2019

Suslik
> насколько я помню, это не UB, а разрешено спекой и содержимое ресурса автоматически обнуляется, если не передать владение явно.
В спеке сказано, что содержимое ресурса может быть утеряно, но у меня оно не терялось. Поэтому я и сказал что UB, так как оно может работать, а может и нет и ты не сразу увидишь ошибку, а слой валидации это не отслеживает.

#111
16:57, 11 апр 2019

вот так у меня в последней ревизии выглядит запись таска:

    frameInfo.renderGraph->AddPass(legit::RenderGraph::ComputePassDesc()
      .SetStorageBuffers(
      {
        frameResources->indirectLightBuffer
      })
      .SetInputImages(
      {
        frameResources->blurredDirectLight.imageViewProxy,
        frameResources->blurredDepthMoments.imageViewProxy,
        frameResources->normal.imageViewProxy,
        frameResources->depthStencil.imageViewProxy,
      })
      .SetRecordFunc([this, passData](legit::RenderGraph::PassContext passContext)
      {
        auto pipeineInfo = pipelineCache->BindComputePipeline(passContext.GetCommandBuffer(), indirectLightingShader.compute.get());
        {
          const legit::DescriptorSetLayoutKey *shaderDataSetInfo = indirectLightingShader.compute->GetSetInfo(ShaderDataSetIndex);
          auto shaderData = passData.memoryPool->BeginSet(shaderDataSetInfo);
          {
            auto shaderDataBuffer = passData.memoryPool->GetUniformBufferData<IndirectLightingShader::DataBuffer>("IndirectLightingData");

            shaderDataBuffer->viewMatrix = passData.viewMatrix;
            shaderDataBuffer->projMatrix = passData.projMatrix;
            shaderDataBuffer->viewportSize = glm::vec4(passData.viewportSize.width, passData.viewportSize.height, 0.0f, 0.0f);
          }
          passData.memoryPool->EndSet();

          std::vector<legit::ImageSamplerBinding> imageSamplerBindings;
          auto blurredDirectLightImageView = passContext.GetImageView(passData.frameResources->blurredDirectLight.imageViewProxy);
          imageSamplerBindings.push_back(shaderDataSetInfo->MakeImageSamplerBinding("blurredDirectLightSampler", blurredDirectLightImageView, screenspaceSampler.get()));
          auto blurredDepthMomentsImageView = passContext.GetImageView(passData.frameResources->blurredDepthMoments.imageViewProxy);
          imageSamplerBindings.push_back(shaderDataSetInfo->MakeImageSamplerBinding("blurredDepthMomentsSampler", blurredDepthMomentsImageView, screenspaceSampler.get()));
          auto normalImageView = passContext.GetImageView(passData.frameResources->normal.imageViewProxy);
          imageSamplerBindings.push_back(shaderDataSetInfo->MakeImageSamplerBinding("normalSampler", normalImageView, screenspaceSampler.get()));
          auto depthStencilImageView = passContext.GetImageView(passData.frameResources->depthStencil.imageViewProxy);
          imageSamplerBindings.push_back(shaderDataSetInfo->MakeImageSamplerBinding("depthStencilSampler", depthStencilImageView, screenspaceSampler.get()));

          std::vector<legit::StorageBufferBinding> storageBufferBindings;
          auto pixelBuffer = passContext.GetBuffer(passData.frameResources->indirectLightBuffer);
          storageBufferBindings.push_back(shaderDataSetInfo->MakeStorageBufferBinding("PixelData", pixelBuffer));

          auto shaderDataSet = descriptorSetCache->GetDescriptorSet(*shaderDataSetInfo, shaderData.uniformBufferBindings, storageBufferBindings, imageSamplerBindings);

          passContext.GetCommandBuffer().bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipeineInfo.pipelineLayout, ShaderDataSetIndex, { shaderDataSet }, { shaderData.dynamicOffset });
          size_t workGroupSize = 32;

          passContext.GetCommandBuffer().dispatch(passData.viewportSize.width / workGroupSize + 1, passData.viewportSize.height / workGroupSize + 1, 1);
        }
      }));
#112
17:04, 11 апр 2019

Suslik
> std::vector
Не боишься выделять память каждый раз? ))

#113
17:06, 11 апр 2019

/A\
да это всё можно легко заменить либо на кешированный вектор, либо на small vector (который меньше определённого размера выделяется на стеке). там под капотом гораздо более криминальные вещи с точки зрения микрооптимизаций происходят, например, у меня все кеши построены на std::map'ах вместо хотя бы std::unordered_map. это всё можно исправить позже, когда я уверен, что меня устраивает вся архитектура.

#114
17:11, 11 апр 2019

Suslik
> там под капотом гораздо более криминальные вещи с точки зрения микрооптимизаций
> происходят, например, у меня все кеши построены на std::map'ах вместо хотя бы std::unordered_map.
По сравнению с глобальным мютексом на алокаторе, это не так страшно.
А у меня бывали случаи, когда unordered из-за хэшей работала в 10 раз медленее обычной мапы.

У меня вообще линейный поиск был для проверки пересечений диапазонов, профайлер говорил, что это далеко не самое медленное место)

#115
17:15, 11 апр 2019

/A\
> По сравнению с глобальным мютексом на алокаторе, это не так страшно.
> А у меня бывали случаи, когда unordered из-за хэшей работала в 10 раз медленее
> обычной мапы.
это всё микрооптимизации, которые всегда можно разрулить позже. для текущей реализации я просто определяю operator < () и могу использовать структуру как ключ для кеша. у меня даже хешей нигде нету, потому что не до них. во всех примерах выше std::vector<> можно заменить как минимум на std::array<>, но суть вообще не в этом, потому что сейчас я занимаюсь обкаткой гораздо более глобальных алгоритмов и более высокоуровневой архитектуры.

#116
17:29, 30 апр 2019

Раз эта тема перешла в обсуждение фреймграфов, то вот вариант от юбисофт еще от 2017 года.
https://developer.download.nvidia.com/assets/gameworks/downloads/… 017_FINAL.pdf

Интересно насколько быстро эта их система работает.

#117
11:29, 17 мая 2019

на пути к лайтмаперу

+ ожидание
+ реальность
#118
11:48, 17 мая 2019

/A\
лул, уже близко

#119
15:18, 28 июля 2019

Какой-то странный баг появился: добавил поддержку VR для рейтрейса как в шейдертое, но вот некоторые шейдеры рисуются с шумом.
noise | FrameGraph

* Воспроизводится на реальном VR, эмуляторе и на самописном эмуляторе.
* Воспроизводится на нвидиа и интел.
* В обычном режиме все работает.
* Слои валидации молчат.
* Пробовал играться с синхронизациями - не помогло.
* Смотрел в рендер доке, тот же шум воспроизводится,
* Запускал свой дебагер шейдеров и черных пикселей не обнаружил, то есть проблема где-то позже.
* А вот что помогло - убрал макрос VR_MODE, все равно у меня правильно рассчитываются лучи для VR. Но вот почему небольшая разница в коде дает такой результат я не понимаю. С макросом VR_MODE но с рисованием в одну текстуру баг воспроизводится.

+ Показать
Страницы: 17 8 9 10 11 Следующая »
ФлеймФорумПроЭкты

Тема в архиве.