| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- #include "nvenc-internal.h"
- #include "nvenc-helpers.h"
- /*
- * NVENC implementation using CUDA context and OpenGL textures
- */
- void cuda_opengl_free(struct nvenc_data *enc)
- {
- if (!enc->cu_ctx)
- return;
- cu->cuCtxPushCurrent(enc->cu_ctx);
- for (size_t i = 0; i < enc->input_textures.num; i++) {
- CUgraphicsResource res_y = enc->input_textures.array[i].res_y;
- CUgraphicsResource res_uv = enc->input_textures.array[i].res_uv;
- cu->cuGraphicsUnregisterResource(res_y);
- cu->cuGraphicsUnregisterResource(res_uv);
- }
- cu->cuCtxPopCurrent(NULL);
- }
- /* ------------------------------------------------------------------------- */
- /* Actual encoding stuff */
- static inline bool get_res_for_tex_ids(struct nvenc_data *enc, GLuint tex_id_y,
- GLuint tex_id_uv,
- CUgraphicsResource *tex_y,
- CUgraphicsResource *tex_uv)
- {
- bool success = true;
- for (size_t idx = 0; idx < enc->input_textures.num; idx++) {
- struct handle_tex *ht = &enc->input_textures.array[idx];
- if (ht->tex_id != tex_id_y)
- continue;
- *tex_y = ht->res_y;
- *tex_uv = ht->res_uv;
- return success;
- }
- CU_CHECK(cu->cuGraphicsGLRegisterImage(
- tex_y, tex_id_y, GL_TEXTURE_2D,
- CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY))
- CU_CHECK(cu->cuGraphicsGLRegisterImage(
- tex_uv, tex_id_uv, GL_TEXTURE_2D,
- CU_GRAPHICS_REGISTER_FLAGS_READ_ONLY))
- struct handle_tex ht = {tex_id_y, *tex_y, *tex_uv};
- da_push_back(enc->input_textures, &ht);
- unmap:
- if (!success) {
- cu->cuGraphicsUnregisterResource(*tex_y);
- cu->cuGraphicsUnregisterResource(*tex_uv);
- }
- return success;
- }
- static inline bool copy_tex_data(struct nvenc_data *enc, const bool p010,
- GLuint tex[2], struct nv_cuda_surface *surf)
- {
- bool success = true;
- CUgraphicsResource mapped_tex[2] = {0};
- CUarray mapped_cuda;
- if (!get_res_for_tex_ids(enc, tex[0], tex[1], &mapped_tex[0],
- &mapped_tex[1]))
- return false;
- CU_CHECK(cu->cuGraphicsMapResources(2, mapped_tex, 0))
- CUDA_MEMCPY2D m = {0};
- m.dstMemoryType = CU_MEMORYTYPE_ARRAY;
- m.srcMemoryType = CU_MEMORYTYPE_ARRAY;
- m.dstArray = surf->tex;
- m.WidthInBytes = p010 ? enc->cx * 2 : enc->cx;
- m.Height = enc->cy;
- // Map and copy Y texture
- CU_CHECK(cu->cuGraphicsSubResourceGetMappedArray(&mapped_cuda,
- mapped_tex[0], 0, 0));
- m.srcArray = mapped_cuda;
- CU_CHECK(cu->cuMemcpy2D(&m))
- // Map and copy UV texture
- CU_CHECK(cu->cuGraphicsSubResourceGetMappedArray(&mapped_cuda,
- mapped_tex[1], 0, 0))
- m.srcArray = mapped_cuda;
- m.dstY += enc->cy;
- m.Height = enc->cy / 2;
- CU_CHECK(cu->cuMemcpy2D(&m))
- unmap:
- cu->cuGraphicsUnmapResources(2, mapped_tex, 0);
- return success;
- }
- bool cuda_opengl_encode(void *data, struct encoder_texture *tex, int64_t pts,
- uint64_t lock_key, uint64_t *next_key,
- struct encoder_packet *packet, bool *received_packet)
- {
- struct nvenc_data *enc = data;
- struct nv_cuda_surface *surf;
- struct nv_bitstream *bs;
- const bool p010 = obs_p010_tex_active();
- GLuint input_tex[2];
- if (tex == NULL || tex->tex[0] == NULL) {
- error("Encode failed: bad texture handle");
- *next_key = lock_key;
- return false;
- }
- bs = &enc->bitstreams.array[enc->next_bitstream];
- surf = &enc->surfaces.array[enc->next_bitstream];
- deque_push_back(&enc->dts_list, &pts, sizeof(pts));
- /* ------------------------------------ */
- /* copy to CUDA data */
- CU_FAILED(cu->cuCtxPushCurrent(enc->cu_ctx))
- obs_enter_graphics();
- input_tex[0] = *(GLuint *)gs_texture_get_obj(tex->tex[0]);
- input_tex[1] = *(GLuint *)gs_texture_get_obj(tex->tex[1]);
- bool success = copy_tex_data(enc, p010, input_tex, surf);
- obs_leave_graphics();
- CU_FAILED(cu->cuCtxPopCurrent(NULL))
- if (!success)
- return false;
- /* ------------------------------------ */
- /* map output tex so nvenc can use it */
- NV_ENC_MAP_INPUT_RESOURCE map = {NV_ENC_MAP_INPUT_RESOURCE_VER};
- map.registeredResource = surf->res;
- map.mappedBufferFmt = p010 ? NV_ENC_BUFFER_FORMAT_YUV420_10BIT
- : NV_ENC_BUFFER_FORMAT_NV12;
- if (NV_FAILED(nv.nvEncMapInputResource(enc->session, &map)))
- return false;
- surf->mapped_res = map.mappedResource;
- /* ------------------------------------ */
- /* do actual encode call */
- return nvenc_encode_base(enc, bs, surf->mapped_res, pts, packet,
- received_packet);
- }
|