Кодирование + отображение без отслеживания (NVEnc, OpenGL, CUDA)

Я пишу приложение для Windows, которое обрабатывает, кодирует в H.264 и отображает живые изображения, полученные с камеры с частотой 60 Гц. Я использую Quadro P400. Мне нужно, чтобы задержка от приобретения до отображения была минимальной.

Изображения, загружаемые в графический процессор, имеют формат 1920x1080, байерский формат. Я использую примитивы Npp для де-Байера и масштабирования изображений до 4K (часть моего требования). Я использую OpenGL для отображения.

Функционально приложение корректно (изображения отображаются и кодируются правильно), но период кадра составляет около 22 мс, что означает, что оно сбрасывает кадры.

Я ищу несколько советов о том, как реструктурировать приложение для повышения производительности.

Я профилировал приложение, используя профилировщик NSight в Visual Studio, и я вижу, что ядра загружены на 100%. Текстура memcpy to OpenGL (cudaMemcpyToArray()) существенно медленнее, чем простые вызовы cudaMemcpy(). Можно ли это улучшить? Есть несколько простоев для GPU, которые я не понимаю. Я не могу прикрепить трассировку профилировщика, но могу предоставить ее по запросу.

Я заметил, что комментирование на дисплее приводит к тому, что время простоя графического процессора исчезает. Вызывает ли зависание взаимодействия с OpenGL графический процессор по какой-то причине? Весь код выполняется в одном потоке, и есть только один поток CUDA. Поможет ли использование большего количества потоков и / или потоков?

Псевдокод для основного цикла приложения показан ниже.

    NvQueryPerformanceCounter(&lStart);

      for (int i = 0; i < N; ++i) {
         // Copy Lena to GPU
         __cuda(cudaMemcpy(d_lena, h_lena, lena_size, cudaMemcpyHostToDevice));

         // Debayer using NPP
         __npp(nppiCFAToRGBA_8u_C1AC4R(d_lena, nSrcStep, oSrcSize, oSrcROI, d_rgba, nDstStep, eGrid, eInterpolation, nAlpha));

            // Upscale to 4K using NPP
            __npp(nppiResize_8u_C4R(d_rgba, nSrcStep, oSrcSize, oSrcROI, d_upscaled_rgba, nDstStep, oDstSize, oDstROI, eInterpolation));

            // Encode
            nv_enc.Encode(d_upscaled_rgba);

            // Display
            gl_window.SetImageFromCUDA(d_upscaled_rgba);
            gl_window.Render()

            ++numFramesEncoded;
      }

    NvQueryPerformanceCounter(&lEnd);
    NvQueryPerformanceFrequency(&lFreq);
    double elapsedTime = (double)(lEnd - lStart);
    print("Average Processing Time : %6.2fms\n", ((elapsedTime*1000.0) / numFramesEncoded) / lFreq);
  • Хост-буфер закреплен в памяти.
  • nv_enc.Encode () берет копию входного изображения RGBA и затем вызывает NVENC::nvEncEncodePicture(). NVENC API внутренне преобразует изображение из RGBA в YUV перед отправкой в ​​кодировщик.
  • gl_window.SetImageFromCUDA копирует изображение в текстурную память с помощью cudaMemcpyToArray(), отображает его в квад и вызывает SwapBuffers(). Указатель cudaArray был получен с помощью функции cuGraphicsMapResources(), как показано в этом примере https://github.com/nvpro-samples/gl_cuda_interop_pingpong_st.
  • Дисплей синхронизируется с VSync.

РЕДАКТИРОВАТЬ: добавил код отображения ниже

int CGLWindow::SetImageFromCUDA(void *frame)
{
   // m_pImageData is a cudaArray * that is mapped once at initialisation
   int size_tex_data = m_nWidth * m_nHeight * sizeof(uint32_t);
   cudaMemcpyToArray(m_pImageData, 0, 0, frame, size_tex_data, cudaMemcpyDeviceToDevice);
}

int CGLWindow::Render()
{
   glActiveTexture(GL_TEXTURE0);

   glEnable(GL_TEXTURE_2D);
   glDisable(GL_DEPTH_TEST);
   glDisable(GL_LIGHTING);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

   glBindTexture(GL_TEXTURE_2D, m_textureID);

   glUseProgram(m_programID);
   glUniform1i(m_loc_tex, 0);

   glBegin(GL_QUADS);
   glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 0.0f);
   glTexCoord2f(0.0f, 0.0f); glVertex3f(+1.0f, -1.0f, 0.0f);
   glTexCoord2f(1.0f, 0.0f); glVertex3f(+1.0f, +1.0f, 0.0f);
   glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, +1.0f, 0.0f);
   glEnd();

   glDisable(GL_TEXTURE_2D);
   glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

   SwapBuffers(m_hDC);
}

0 ответов

Другие вопросы по тегам