1
0
Эх сурвалжийг харах

libobs/graphics: Add texture sharing functions

jp9000 7 жил өмнө
parent
commit
b64d7d71d0

+ 47 - 5
libobs-d3d11/d3d11-subsystem.cpp

@@ -736,8 +736,7 @@ gs_texture_t *device_texture_create(gs_device_t *device, uint32_t width,
 	gs_texture *texture = NULL;
 	try {
 		texture = new gs_texture_2d(device, width, height, color_format,
-				levels, data, flags, GS_TEXTURE_2D, false,
-				false);
+				levels, data, flags, GS_TEXTURE_2D, false);
 	} catch (HRError error) {
 		blog(LOG_ERROR, "device_texture_create (D3D11): %s (%08lX)",
 				error.str, error.hr);
@@ -756,8 +755,7 @@ gs_texture_t *device_cubetexture_create(gs_device_t *device, uint32_t size,
 	gs_texture *texture = NULL;
 	try {
 		texture = new gs_texture_2d(device, size, size, color_format,
-				levels, data, flags, GS_TEXTURE_CUBE, false,
-				false);
+				levels, data, flags, GS_TEXTURE_CUBE, false);
 	} catch (HRError error) {
 		blog(LOG_ERROR, "device_cubetexture_create (D3D11): %s "
 		                "(%08lX)",
@@ -2063,7 +2061,7 @@ extern "C" EXPORT gs_texture_t *device_texture_create_gdi(gs_device_t *device,
 	try {
 		texture = new gs_texture_2d(device, width, height, GS_BGRA,
 				1, nullptr, GS_RENDER_TARGET, GS_TEXTURE_2D,
-				true, false);
+				true);
 	} catch (HRError error) {
 		blog(LOG_ERROR, "device_texture_create_gdi (D3D11): %s (%08lX)",
 				error.str, error.hr);
@@ -2132,3 +2130,47 @@ extern "C" EXPORT gs_texture_t *device_texture_open_shared(gs_device_t *device,
 
 	return texture;
 }
+
+extern "C" EXPORT uint32_t device_texture_get_shared_handle(gs_texture_t *tex)
+{
+	gs_texture_2d *tex2d = reinterpret_cast<gs_texture_2d *>(tex);
+	if (tex->type != GS_TEXTURE_2D)
+		return GS_INVALID_HANDLE;
+
+	return tex2d->isShared ? tex2d->sharedHandle : GS_INVALID_HANDLE;
+}
+
+extern "C" EXPORT int device_texture_acquire_sync(gs_texture_t *tex,
+		uint64_t key, uint32_t ms)
+{
+	gs_texture_2d *tex2d = reinterpret_cast<gs_texture_2d *>(tex);
+	if (tex->type != GS_TEXTURE_2D)
+		return -1;
+
+	ComQIPtr<IDXGIKeyedMutex> keyedMutex(tex2d->texture);
+	if (!keyedMutex)
+		return -1;
+
+	HRESULT hr = keyedMutex->AcquireSync(key, ms);
+	if (hr == S_OK)
+		return 0;
+	else if (hr == WAIT_TIMEOUT)
+		return ETIMEDOUT;
+
+	return -1;
+}
+
+extern "C" EXPORT int device_texture_release_sync(gs_texture_t *tex,
+		uint64_t key)
+{
+	gs_texture_2d *tex2d = reinterpret_cast<gs_texture_2d *>(tex);
+	if (tex->type != GS_TEXTURE_2D)
+		return -1;
+
+	ComQIPtr<IDXGIKeyedMutex> keyedMutex(tex2d->texture);
+	if (!keyedMutex)
+		return -1;
+
+	HRESULT hr = keyedMutex->ReleaseSync(key);
+	return hr == S_OK ? 0 : -1;
+}

+ 3 - 2
libobs-d3d11/d3d11-subsystem.hpp

@@ -344,13 +344,14 @@ struct gs_texture_2d : gs_texture {
 	ComPtr<IDXGISurface1>            gdiSurface;
 
 	uint32_t        width = 0, height = 0;
+	uint32_t        flags = 0;
 	DXGI_FORMAT     dxgiFormat = DXGI_FORMAT_UNKNOWN;
 	bool            isRenderTarget = false;
 	bool            isGDICompatible = false;
 	bool            isDynamic = false;
 	bool            isShared = false;
 	bool            genMipmaps = false;
-	uint32_t        sharedHandle = 0;
+	uint32_t        sharedHandle = GS_INVALID_HANDLE;
 
 	vector<vector<uint8_t>> data;
 	vector<D3D11_SUBRESOURCE_DATA> srd;
@@ -382,7 +383,7 @@ struct gs_texture_2d : gs_texture {
 	gs_texture_2d(gs_device_t *device, uint32_t width, uint32_t height,
 			gs_color_format colorFormat, uint32_t levels,
 			const uint8_t **data, uint32_t flags,
-			gs_texture_type type, bool gdiCompatible, bool shared);
+			gs_texture_type type, bool gdiCompatible);
 
 	gs_texture_2d(gs_device_t *device, uint32_t handle);
 };

+ 51 - 6
libobs-d3d11/d3d11-texture2d.cpp

@@ -96,6 +96,11 @@ void gs_texture_2d::InitTexture(const uint8_t **data)
 	if (isGDICompatible)
 		td.MiscFlags |= D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
 
+	if ((flags & GS_SHARED_KM_TEX) != 0)
+		td.MiscFlags |= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
+	else if ((flags & GS_SHARED_TEX) != 0)
+		td.MiscFlags |= D3D11_RESOURCE_MISC_SHARED;
+
 	if (data) {
 		BackupTexture(data);
 		InitSRD(srd);
@@ -112,6 +117,42 @@ void gs_texture_2d::InitTexture(const uint8_t **data)
 		if (FAILED(hr))
 			throw HRError("Failed to create GDI surface", hr);
 	}
+
+	if (isShared) {
+		ComPtr<IDXGIResource> dxgi_res;
+
+		texture->SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
+
+		hr = texture->QueryInterface(__uuidof(IDXGIResource),
+				(void**)&dxgi_res);
+		if (FAILED(hr)) {
+			blog(LOG_WARNING, "InitTexture: Failed to query "
+					"interface: %08lX", hr);
+		} else {
+			HANDLE handle;
+			hr = dxgi_res->GetSharedHandle(&handle);
+			if (FAILED(hr)) {
+				blog(LOG_WARNING, "InitTexture: Failed to "
+						"get shared handle: %08lX", hr);
+			} else {
+				sharedHandle = (uint32_t)(uintptr_t)handle;
+			}
+
+			if (flags & GS_SHARED_KM_TEX) {
+				ComPtr<IDXGIKeyedMutex> km;
+				hr = texture->QueryInterface(
+						__uuidof(IDXGIKeyedMutex),
+						(void**)&km);
+				if (FAILED(hr)) {
+					throw HRError("Failed to query "
+							"IDXGIKeyedMutex",
+							hr);
+				}
+
+				km->AcquireSync(0, INFINITE);
+			}
+		}
+	}
 }
 
 void gs_texture_2d::InitResourceView()
@@ -164,20 +205,24 @@ void gs_texture_2d::InitRenderTargets()
 	}
 }
 
+#define SHARED_FLAGS (GS_SHARED_TEX | GS_SHARED_KM_TEX)
+
 gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t width,
 		uint32_t height, gs_color_format colorFormat, uint32_t levels,
-		const uint8_t **data, uint32_t flags, gs_texture_type type,
-		bool gdiCompatible, bool shared)
+		const uint8_t **data, uint32_t flags_, gs_texture_type type,
+		bool gdiCompatible)
 	: gs_texture      (device, gs_type::gs_texture_2d, type, levels,
 	                   colorFormat),
 	  width           (width),
 	  height          (height),
+	  flags           (flags_),
 	  dxgiFormat      (ConvertGSTextureFormat(format)),
-	  isRenderTarget  ((flags & GS_RENDER_TARGET) != 0),
+	  isRenderTarget  ((flags_ & GS_RENDER_TARGET) != 0),
 	  isGDICompatible (gdiCompatible),
-	  isDynamic       ((flags & GS_DYNAMIC) != 0),
-	  isShared        (shared),
-	  genMipmaps      ((flags & GS_BUILD_MIPMAPS) != 0)
+	  isDynamic       ((flags_ & GS_DYNAMIC) != 0),
+	  isShared        ((flags_ & SHARED_FLAGS) != 0),
+	  genMipmaps      ((flags_ & GS_BUILD_MIPMAPS) != 0),
+	  sharedHandle    (GS_INVALID_HANDLE)
 {
 	InitTexture(data);
 	InitResourceView();

+ 3 - 0
libobs/graphics/graphics-imports.c

@@ -189,6 +189,9 @@ bool load_graphics_imports(struct gs_exports *exports, void *module,
 	GRAPHICS_IMPORT_OPTIONAL(gs_texture_get_dc);
 	GRAPHICS_IMPORT_OPTIONAL(gs_texture_release_dc);
 	GRAPHICS_IMPORT_OPTIONAL(device_texture_open_shared);
+	GRAPHICS_IMPORT_OPTIONAL(device_texture_get_shared_handle);
+	GRAPHICS_IMPORT_OPTIONAL(device_texture_acquire_sync);
+	GRAPHICS_IMPORT_OPTIONAL(device_texture_release_sync);
 #endif
 
 	return success;

+ 4 - 0
libobs/graphics/graphics-internal.h

@@ -261,6 +261,10 @@ struct gs_exports {
 
 	gs_texture_t *(*device_texture_open_shared)(gs_device_t *device,
 				uint32_t handle);
+	uint32_t (*device_texture_get_shared_handle)(gs_texture_t *tex);
+	int (*device_texture_acquire_sync)(gs_texture_t *tex, uint64_t key,
+			uint32_t ms);
+	int (*device_texture_release_sync)(gs_texture_t *tex, uint64_t key);
 #endif
 };
 

+ 34 - 0
libobs/graphics/graphics.c

@@ -2692,4 +2692,38 @@ gs_texture_t *gs_texture_open_shared(uint32_t handle)
 	return NULL;
 }
 
+uint32_t gs_texture_get_shared_handle(gs_texture_t *tex)
+{
+	graphics_t *graphics = thread_graphics;
+	if (!gs_valid("gs_texture_get_shared_handle"))
+		return GS_INVALID_HANDLE;
+
+	if (graphics->exports.device_texture_get_shared_handle)
+		return graphics->exports.device_texture_get_shared_handle(tex);
+	return GS_INVALID_HANDLE;
+}
+
+int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms)
+{
+	graphics_t *graphics = thread_graphics;
+	if (!gs_valid("gs_texture_acquire_sync"))
+		return -1;
+
+	if (graphics->exports.device_texture_acquire_sync)
+		return graphics->exports.device_texture_acquire_sync(tex,
+				key, ms);
+	return -1;
+}
+
+int gs_texture_release_sync(gs_texture_t *tex, uint64_t key)
+{
+	graphics_t *graphics = thread_graphics;
+	if (!gs_valid("gs_texture_release_sync"))
+		return -1;
+
+	if (graphics->exports.device_texture_release_sync)
+		return graphics->exports.device_texture_release_sync(tex, key);
+	return -1;
+}
+
 #endif

+ 20 - 0
libobs/graphics/graphics.h

@@ -444,6 +444,8 @@ EXPORT gs_texture_t *gs_texrender_get_texture(const gs_texrender_t *texrender);
 #define GS_GL_DUMMYTEX   (1<<3) /**<< texture with no allocated texture data */
 #define GS_DUP_BUFFER    (1<<4) /**<< do not pass buffer ownership when
 				 *    creating a vertex/index buffer */
+#define GS_SHARED_TEX    (1<<5)
+#define GS_SHARED_KM_TEX (1<<6)
 
 /* ---------------- */
 /* global functions */
@@ -794,6 +796,24 @@ EXPORT void gs_texture_release_dc(gs_texture_t *gdi_tex);
 
 /** creates a windows shared texture from a texture handle */
 EXPORT gs_texture_t *gs_texture_open_shared(uint32_t handle);
+
+#define GS_INVALID_HANDLE (uint32_t)-1
+EXPORT uint32_t gs_texture_get_shared_handle(gs_texture_t *tex);
+
+#define GS_WAIT_INFINITE (uint32_t)-1
+
+/**
+ * acquires a lock on a keyed mutex texture.
+ * returns -1 on generic failure, ETIMEDOUT if timed out
+ */
+EXPORT int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms);
+
+/**
+ * releases a lock on a keyed mutex texture to another device.
+ * return 0 on success, -1 on error
+ */
+EXPORT int gs_texture_release_sync(gs_texture_t *tex, uint64_t key);
+
 #endif
 
 /* inline functions used by modules */