nvenc-opengl.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #include "nvenc-internal.h"
  2. #include "nvenc-helpers.h"
  3. /*
  4. * NVENC implementation using CUDA context and OpenGL textures
  5. */
  6. void cuda_opengl_free(struct nvenc_data *enc)
  7. {
  8. if (!enc->cu_ctx)
  9. return;
  10. cu->cuCtxPushCurrent(enc->cu_ctx);
  11. for (size_t i = 0; i < enc->input_textures.num; i++) {
  12. CUgraphicsResource res_y = enc->input_textures.array[i].res_y;
  13. CUgraphicsResource res_uv = enc->input_textures.array[i].res_uv;
  14. cu->cuGraphicsUnregisterResource(res_y);
  15. cu->cuGraphicsUnregisterResource(res_uv);
  16. }
  17. cu->cuCtxPopCurrent(NULL);
  18. }
  19. /* ------------------------------------------------------------------------- */
  20. /* Actual encoding stuff */
  21. static inline bool get_res_for_tex_ids(struct nvenc_data *enc, GLuint tex_id_y,
  22. GLuint tex_id_uv,
  23. CUgraphicsResource *tex_y,
  24. CUgraphicsResource *tex_uv)
  25. {
  26. bool success = true;
  27. for (size_t idx = 0; idx < enc->input_textures.num; idx++) {
  28. struct handle_tex *ht = &enc->input_textures.array[idx];
  29. if (ht->tex_id != tex_id_y)
  30. continue;
  31. *tex_y = ht->res_y;
  32. *tex_uv = ht->res_uv;
  33. return success;
  34. }
  35. CU_CHECK(cu->cuGraphicsGLRegisterImage(
  36. tex_y, tex_id_y, GL_TEXTURE_2D,
  37. CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY))
  38. CU_CHECK(cu->cuGraphicsGLRegisterImage(
  39. tex_uv, tex_id_uv, GL_TEXTURE_2D,
  40. CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY))
  41. struct handle_tex ht = {tex_id_y, *tex_y, *tex_uv};
  42. da_push_back(enc->input_textures, &ht);
  43. unmap:
  44. if (!success) {
  45. cu->cuGraphicsUnregisterResource(*tex_y);
  46. cu->cuGraphicsUnregisterResource(*tex_uv);
  47. }
  48. return success;
  49. }
  50. static inline bool copy_tex_data(struct nvenc_data *enc, const bool p010,
  51. GLuint tex[2], struct nv_cuda_surface *surf)
  52. {
  53. bool success = true;
  54. CUgraphicsResource mapped_tex[2] = {0};
  55. CUarray mapped_cuda;
  56. if (!get_res_for_tex_ids(enc, tex[0], tex[1], &mapped_tex[0],
  57. &mapped_tex[1]))
  58. return false;
  59. CU_CHECK(cu->cuGraphicsMapResources(2, mapped_tex, 0))
  60. CUDA_MEMCPY2D m = {0};
  61. m.dstMemoryType = CU_MEMORYTYPE_ARRAY;
  62. m.srcMemoryType = CU_MEMORYTYPE_ARRAY;
  63. m.dstArray = surf->tex;
  64. m.WidthInBytes = p010 ? enc->cx * 2 : enc->cx;
  65. m.Height = enc->cy;
  66. // Map and copy Y texture
  67. CU_CHECK(cu->cuGraphicsSubResourceGetMappedArray(&mapped_cuda,
  68. mapped_tex[0], 0, 0));
  69. m.srcArray = mapped_cuda;
  70. CU_CHECK(cu->cuMemcpy2D(&m))
  71. // Map and copy UV texture
  72. CU_CHECK(cu->cuGraphicsSubResourceGetMappedArray(&mapped_cuda,
  73. mapped_tex[1], 0, 0))
  74. m.srcArray = mapped_cuda;
  75. m.dstY += enc->cy;
  76. m.Height = enc->cy / 2;
  77. CU_CHECK(cu->cuMemcpy2D(&m))
  78. unmap:
  79. cu->cuGraphicsUnmapResources(2, mapped_tex, 0);
  80. return success;
  81. }
  82. bool cuda_opengl_encode(void *data, struct encoder_texture *tex, int64_t pts,
  83. uint64_t lock_key, uint64_t *next_key,
  84. struct encoder_packet *packet, bool *received_packet)
  85. {
  86. struct nvenc_data *enc = data;
  87. struct nv_cuda_surface *surf;
  88. struct nv_bitstream *bs;
  89. const bool p010 = obs_p010_tex_active();
  90. GLuint input_tex[2];
  91. if (tex == NULL || tex->tex[0] == NULL) {
  92. error("Encode failed: bad texture handle");
  93. *next_key = lock_key;
  94. return false;
  95. }
  96. bs = &enc->bitstreams.array[enc->next_bitstream];
  97. surf = &enc->surfaces.array[enc->next_bitstream];
  98. deque_push_back(&enc->dts_list, &pts, sizeof(pts));
  99. /* ------------------------------------ */
  100. /* copy to CUDA data */
  101. CU_FAILED(cu->cuCtxPushCurrent(enc->cu_ctx))
  102. obs_enter_graphics();
  103. input_tex[0] = *(GLuint *)gs_texture_get_obj(tex->tex[0]);
  104. input_tex[1] = *(GLuint *)gs_texture_get_obj(tex->tex[1]);
  105. bool success = copy_tex_data(enc, p010, input_tex, surf);
  106. obs_leave_graphics();
  107. CU_FAILED(cu->cuCtxPopCurrent(NULL))
  108. if (!success)
  109. return false;
  110. /* ------------------------------------ */
  111. /* map output tex so nvenc can use it */
  112. NV_ENC_MAP_INPUT_RESOURCE map = {NV_ENC_MAP_INPUT_RESOURCE_VER};
  113. map.registeredResource = surf->res;
  114. map.mappedBufferFmt = p010 ? NV_ENC_BUFFER_FORMAT_YUV420_10BIT
  115. : NV_ENC_BUFFER_FORMAT_NV12;
  116. if (NV_FAILED(nv.nvEncMapInputResource(enc->session, &map)))
  117. return false;
  118. surf->mapped_res = map.mappedResource;
  119. /* ------------------------------------ */
  120. /* do actual encode call */
  121. return nvenc_encode_base(enc, bs, surf->mapped_res, pts, packet,
  122. received_packet);
  123. }