Skip to content

Commit

Permalink
Source: Add support for WGL_NV_DX_interop on windows
Browse files Browse the repository at this point in the history
Allows us to share textures between OpenGL and Direct3D saving us the
reading into ram and then copying back into vram. On a 720p video it
saved ~1ms in Debug build.
  • Loading branch information
univrsal committed Nov 11, 2023
1 parent 2f5b1a0 commit 7c386fe
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 17 deletions.
36 changes: 24 additions & 12 deletions src/mpv-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,18 @@ void mpvs_handle_events(struct mpv_source* context)

void mpvs_render(struct mpv_source* context)
{
#if !defined(WIN32)
#if defined(WIN32)
if (wgl_have_NV_DX_interop)
wgl_lock_shared_texture(context);
#else
// make sure that we restore the current program after mpv is done
// as obs will not load the progam because it internally keeps track
// of the current program and only loads it if it has changed
GLuint currentProgram;
context->_glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&currentProgram);
#endif


mpv_render_frame_info info;

mpv_render_param params[] = {
Expand All @@ -234,20 +239,23 @@ void mpvs_render(struct mpv_source* context)
obs_log(LOG_ERROR, "mpv render error: %s", mpv_error_string(result));

#if defined(WIN32)
if (context->media_state == OBS_MEDIA_STATE_PLAYING) {
uint8_t* ptr;
uint32_t linesize;
if (gs_texture_map(context->video_buffer, &ptr, &linesize)) {
context->_glBindFramebuffer(GL_FRAMEBUFFER, context->fbo);
context->_glReadPixels(0, 0, context->d3d_width, context->d3d_height, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
if (wgl_have_NV_DX_interop) {
wgl_unlock_shared_texture(context);
} else {
if (context->media_state == OBS_MEDIA_STATE_PLAYING) {
uint8_t* ptr;
uint32_t linesize;
if (gs_texture_map(context->video_buffer, &ptr, &linesize)) {
context->_glBindFramebuffer(GL_FRAMEBUFFER, context->fbo);
context->_glReadPixels(0, 0, context->d3d_width, context->d3d_height, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
}
gs_texture_unmap(context->video_buffer);
}
gs_texture_unmap(context->video_buffer);
}
#endif

#if !defined(WIN32)
#else
context->_glUseProgram(currentProgram);
#endif

}

void mpvs_init(struct mpv_source* context)
Expand Down Expand Up @@ -461,7 +469,7 @@ void mpvs_generate_texture(struct mpv_source* context)
#if defined(WIN32)
if (context->video_buffer)
gs_texture_destroy(context->video_buffer);
context->video_buffer = gs_texture_create(context->d3d_width, context->d3d_height, GS_RGBA, 1, NULL, GS_DYNAMIC);
context->video_buffer = gs_texture_create(context->d3d_width, context->d3d_height, GS_RGBA, 1, NULL, wgl_have_NV_DX_interop ? 0 : GS_DYNAMIC);

context->_glBindTexture(GL_TEXTURE_2D, 0);

Expand All @@ -481,6 +489,10 @@ void mpvs_generate_texture(struct mpv_source* context)
context->_glGenFramebuffers(1, &context->fbo);
context->_glBindFramebuffer(GL_FRAMEBUFFER, context->fbo);
context->_glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, context->wgl_texture, 0);

if (wgl_have_NV_DX_interop) {
wgl_init_shared_gl_texture(context);
}
#else
if (context->video_buffer) {
gs_texture_destroy(context->video_buffer);
Expand Down
4 changes: 4 additions & 0 deletions src/mpv-source.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,8 @@ struct mpv_source {
obs_source_t* jack_source;
char* jack_port_name; // name of the jack capture source
char* jack_client_name; // name of the jack client mpv opens for audio output

#if defined(WIN32)
HANDLE gl_shared_texture_handle;
#endif
};
33 changes: 29 additions & 4 deletions src/wgl.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#include "wgl.h"

#include <glad/glad_wgl.h>
#include <obs-module.h>
#include <plugin-support.h>
#include <Windows.h>

WNDCLASSEX wc;
HWND hwnd;
HGLRC hrc;
HDC hdc;
HANDLE wgl_dx_device;

static const char* dummy_window_class = "GLDummyWindow-obs-mpv";
static bool registered_dummy_window_class = false;
bool wgl_have_NV_DX_interop = false;

struct dummy_context {
HWND hwnd;
Expand Down Expand Up @@ -389,6 +388,13 @@ bool wgl_init()
if (glVersion) {
obs_log(LOG_INFO, "OpenGL Version: %s\n", glVersion);
}

wgl_dx_device = wglDXOpenDeviceNV(gs_get_device_obj());
if (wgl_dx_device) {
wgl_have_NV_DX_interop = true;
obs_log(LOG_INFO, "NV_DX_interop extension is supported, sharing texture between OpenGL and Direct3D");
}

init_result = true;
return true;
fail:
Expand All @@ -398,8 +404,9 @@ bool wgl_init()

void wgl_deinit()
{
// Cleanup
wglMakeCurrent(NULL, NULL);
if (wgl_dx_device)
wglDXCloseDeviceNV(wgl_dx_device);
wglDeleteContext(hrc);
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
Expand All @@ -415,3 +422,21 @@ void wgl_exit_context()
{
wglMakeCurrent(NULL, NULL);
}

void wgl_init_shared_gl_texture(void* context)
{
struct mpv_source* src = context;
src->gl_shared_texture_handle = wglDXRegisterObjectNV(wgl_dx_device,
gs_texture_get_obj(src->video_buffer),
src->wgl_texture,
GL_TEXTURE_2D,
WGL_ACCESS_WRITE_DISCARD_NV);
}

void wgl_free_shared_gl_texture(void* context)
{
struct mpv_source* src = context;
if (src->gl_shared_texture_handle)
wglDXUnregisterObjectNV(wgl_dx_device, src->gl_shared_texture_handle);
src->gl_shared_texture_handle = 0;
}
41 changes: 40 additions & 1 deletion src/wgl.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,49 @@
#pragma once
#include <stdbool.h>

#if defined(WIN32)
#include <Windows.h>
#include <glad/glad_wgl.h>
#include "mpv-source.h"

extern bool wgl_have_NV_DX_interop;
extern HANDLE wgl_dx_device;

static inline void wgl_lock_shared_texture(void* context)
{
struct mpv_source* src = context;
wglDXLockObjectsNV(wgl_dx_device, 1, &src->gl_shared_texture_handle);
}

static inline void wgl_unlock_shared_texture(void* context)
{
struct mpv_source* src = context;
wglDXUnlockObjectsNV(wgl_dx_device, 1, &src->gl_shared_texture_handle);
}

#else
# define wgl_have_NV_DX_interop 0

static inline void wgl_lock_shared_texture(void* context)
{
UNUSED_PARAMETER(context);
}

static inline void wgl_unlock_shared_texture(void* context)
{
UNUSED_PARAMETER(context);
}
#endif

bool wgl_init();

void wgl_deinit();

bool wgl_enter_context();

void wgl_exit_context();
void wgl_exit_context();

void wgl_init_shared_gl_texture(void* context);

void wgl_free_shared_gl_texture(void* context);

0 comments on commit 7c386fe

Please sign in to comment.