libobs/graphics: Add texture sharing functions

master
jp9000 2018-10-05 02:38:11 -07:00
parent 0a202ab77b
commit b64d7d71d0
7 changed files with 162 additions and 13 deletions

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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();

View File

@ -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;

View File

@ -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
};

View File

@ -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

View File

@ -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 */