| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #include "nvenc-internal.h"
- #include "nvenc-helpers.h"
- /*
- * NVENC implementation using Direct3D 11 context and textures
- */
- /* ------------------------------------------------------------------------- */
- /* D3D11 Context/Device management */
- static HANDLE get_lib(struct nvenc_data *enc, const char *lib)
- {
- HMODULE mod = GetModuleHandleA(lib);
- if (mod)
- return mod;
- mod = LoadLibraryA(lib);
- if (!mod)
- error("Failed to load %s", lib);
- return mod;
- }
- typedef HRESULT(WINAPI *CREATEDXGIFACTORY1PROC)(REFIID, void **);
- bool d3d11_init(struct nvenc_data *enc, obs_data_t *settings)
- {
- HMODULE dxgi = get_lib(enc, "DXGI.dll");
- HMODULE d3d11 = get_lib(enc, "D3D11.dll");
- CREATEDXGIFACTORY1PROC create_dxgi;
- PFN_D3D11_CREATE_DEVICE create_device;
- IDXGIFactory1 *factory;
- IDXGIAdapter *adapter;
- ID3D11Device *device;
- ID3D11DeviceContext *context;
- HRESULT hr;
- if (!dxgi || !d3d11) {
- return false;
- }
- create_dxgi = (CREATEDXGIFACTORY1PROC)GetProcAddress(dxgi, "CreateDXGIFactory1");
- create_device = (PFN_D3D11_CREATE_DEVICE)GetProcAddress(d3d11, "D3D11CreateDevice");
- if (!create_dxgi || !create_device) {
- error("Failed to load D3D11/DXGI procedures");
- return false;
- }
- hr = create_dxgi(&IID_IDXGIFactory1, &factory);
- if (FAILED(hr)) {
- error_hr("CreateDXGIFactory1 failed");
- return false;
- }
- hr = factory->lpVtbl->EnumAdapters(factory, 0, &adapter);
- factory->lpVtbl->Release(factory);
- if (FAILED(hr)) {
- error_hr("EnumAdapters failed");
- return false;
- }
- hr = create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &device, NULL,
- &context);
- adapter->lpVtbl->Release(adapter);
- if (FAILED(hr)) {
- error_hr("D3D11CreateDevice failed");
- return false;
- }
- enc->device = device;
- enc->context = context;
- return true;
- }
- void d3d11_free(struct nvenc_data *enc)
- {
- for (size_t i = 0; i < enc->input_textures.num; i++) {
- ID3D11Texture2D *tex = enc->input_textures.array[i].tex;
- IDXGIKeyedMutex *km = enc->input_textures.array[i].km;
- tex->lpVtbl->Release(tex);
- km->lpVtbl->Release(km);
- }
- if (enc->context) {
- enc->context->lpVtbl->Release(enc->context);
- }
- if (enc->device) {
- enc->device->lpVtbl->Release(enc->device);
- }
- }
- /* ------------------------------------------------------------------------- */
- /* D3D11 Surface management */
- static bool d3d11_texture_init(struct nvenc_data *enc, struct nv_texture *nvtex)
- {
- const bool p010 = obs_encoder_video_tex_active(enc->encoder, VIDEO_FORMAT_P010);
- D3D11_TEXTURE2D_DESC desc = {0};
- desc.Width = enc->cx;
- desc.Height = enc->cy;
- desc.MipLevels = 1;
- desc.ArraySize = 1;
- desc.Format = p010 ? DXGI_FORMAT_P010 : DXGI_FORMAT_NV12;
- desc.SampleDesc.Count = 1;
- desc.BindFlags = D3D11_BIND_RENDER_TARGET;
- ID3D11Device *const device = enc->device;
- ID3D11Texture2D *tex;
- HRESULT hr = device->lpVtbl->CreateTexture2D(device, &desc, NULL, &tex);
- if (FAILED(hr)) {
- error_hr("Failed to create texture");
- return false;
- }
- tex->lpVtbl->SetEvictionPriority(tex, DXGI_RESOURCE_PRIORITY_MAXIMUM);
- NV_ENC_REGISTER_RESOURCE res = {NV_ENC_REGISTER_RESOURCE_VER};
- res.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX;
- res.resourceToRegister = tex;
- res.width = enc->cx;
- res.height = enc->cy;
- res.bufferFormat = p010 ? NV_ENC_BUFFER_FORMAT_YUV420_10BIT : NV_ENC_BUFFER_FORMAT_NV12;
- if (NV_FAILED(nv.nvEncRegisterResource(enc->session, &res))) {
- tex->lpVtbl->Release(tex);
- return false;
- }
- nvtex->res = res.registeredResource;
- nvtex->tex = tex;
- nvtex->mapped_res = NULL;
- return true;
- }
- bool d3d11_init_textures(struct nvenc_data *enc)
- {
- //blog(LOG_DEBUG, "buf count: %d", enc->buf_count);
- da_reserve(enc->textures, enc->buf_count);
- for (uint32_t i = 0; i < enc->buf_count; i++) {
- struct nv_texture texture;
- if (!d3d11_texture_init(enc, &texture)) {
- return false;
- }
- da_push_back(enc->textures, &texture);
- }
- return true;
- }
- static void d3d11_texture_free(struct nvenc_data *enc, struct nv_texture *nvtex)
- {
- if (nvtex->res) {
- if (nvtex->mapped_res) {
- nv.nvEncUnmapInputResource(enc->session, nvtex->mapped_res);
- }
- nv.nvEncUnregisterResource(enc->session, nvtex->res);
- nvtex->tex->lpVtbl->Release(nvtex->tex);
- }
- }
- void d3d11_free_textures(struct nvenc_data *enc)
- {
- for (size_t i = 0; i < enc->textures.num; i++) {
- d3d11_texture_free(enc, &enc->textures.array[i]);
- }
- }
- /* ------------------------------------------------------------------------- */
- /* Actual encoding stuff */
- static ID3D11Texture2D *get_tex_from_handle(struct nvenc_data *enc, uint32_t handle, IDXGIKeyedMutex **km_out)
- {
- ID3D11Device *device = enc->device;
- IDXGIKeyedMutex *km;
- ID3D11Texture2D *input_tex;
- HRESULT hr;
- for (size_t i = 0; i < enc->input_textures.num; i++) {
- struct handle_tex *ht = &enc->input_textures.array[i];
- if (ht->handle == handle) {
- *km_out = ht->km;
- return ht->tex;
- }
- }
- hr = device->lpVtbl->OpenSharedResource(device, (HANDLE)(uintptr_t)handle, &IID_ID3D11Texture2D, &input_tex);
- if (FAILED(hr)) {
- error_hr("OpenSharedResource failed");
- return NULL;
- }
- hr = input_tex->lpVtbl->QueryInterface(input_tex, &IID_IDXGIKeyedMutex, &km);
- if (FAILED(hr)) {
- error_hr("QueryInterface(IDXGIKeyedMutex) failed");
- input_tex->lpVtbl->Release(input_tex);
- return NULL;
- }
- input_tex->lpVtbl->SetEvictionPriority(input_tex, DXGI_RESOURCE_PRIORITY_MAXIMUM);
- *km_out = km;
- struct handle_tex new_ht = {handle, input_tex, km};
- da_push_back(enc->input_textures, &new_ht);
- return input_tex;
- }
- bool d3d11_encode(void *data, struct encoder_texture *texture, int64_t pts, uint64_t lock_key, uint64_t *next_key,
- struct encoder_packet *packet, bool *received_packet)
- {
- struct nvenc_data *enc = data;
- ID3D11DeviceContext *context = enc->context;
- ID3D11Texture2D *input_tex;
- ID3D11Texture2D *output_tex;
- IDXGIKeyedMutex *km;
- struct nv_texture *nvtex;
- struct nv_bitstream *bs;
- if (texture->handle == GS_INVALID_HANDLE) {
- error("Encode failed: bad texture handle");
- *next_key = lock_key;
- return false;
- }
- bs = &enc->bitstreams.array[enc->next_bitstream];
- nvtex = &enc->textures.array[enc->next_bitstream];
- input_tex = get_tex_from_handle(enc, texture->handle, &km);
- output_tex = nvtex->tex;
- if (!input_tex) {
- *next_key = lock_key;
- return false;
- }
- deque_push_back(&enc->dts_list, &pts, sizeof(pts));
- /* ------------------------------------ */
- /* copy to output tex */
- km->lpVtbl->AcquireSync(km, lock_key, INFINITE);
- context->lpVtbl->CopyResource(context, (ID3D11Resource *)output_tex, (ID3D11Resource *)input_tex);
- km->lpVtbl->ReleaseSync(km, *next_key);
- /* ------------------------------------ */
- /* map output tex so nvenc can use it */
- NV_ENC_MAP_INPUT_RESOURCE map = {NV_ENC_MAP_INPUT_RESOURCE_VER};
- map.registeredResource = nvtex->res;
- if (NV_FAILED(nv.nvEncMapInputResource(enc->session, &map))) {
- return false;
- }
- nvtex->mapped_res = map.mappedResource;
- /* ------------------------------------ */
- /* do actual encode call */
- return nvenc_encode_base(enc, bs, nvtex->mapped_res, pts, packet, received_packet);
- }
|