libobs/graphics: Add NV12 texture support

This commit is contained in:
jp9000
2018-10-05 03:15:13 -07:00
parent b64d7d71d0
commit 93fc61fa82
8 changed files with 237 additions and 8 deletions

View File

@@ -41,3 +41,28 @@ gs_stage_surface::gs_stage_surface(gs_device_t *device, uint32_t width,
if (FAILED(hr))
throw HRError("Failed to create staging surface", hr);
}
gs_stage_surface::gs_stage_surface(gs_device_t *device, uint32_t width,
uint32_t height)
: gs_obj (device, gs_type::gs_stage_surface),
width (width),
height (height),
format (GS_UNKNOWN),
dxgiFormat (DXGI_FORMAT_NV12)
{
HRESULT hr;
memset(&td, 0, sizeof(td));
td.Width = width;
td.Height = height;
td.MipLevels = 1;
td.ArraySize = 1;
td.Format = dxgiFormat;
td.SampleDesc.Count = 1;
td.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
td.Usage = D3D11_USAGE_STAGING;
hr = device->device->CreateTexture2D(&td, NULL, texture.Assign());
if (FAILED(hr))
throw HRError("Failed to create staging surface", hr);
}

View File

@@ -258,6 +258,17 @@ void gs_device::InitDevice(uint32_t adapterIdx)
if (FAILED(hr))
throw UnsupportedHWError("Failed to create device", hr);
ComQIPtr<ID3D11Device1> d3d11_1(device);
if (!!d3d11_1) {
D3D11_FEATURE_DATA_D3D11_OPTIONS opts = {};
hr = d3d11_1->CheckFeatureSupport(
D3D11_FEATURE_D3D11_OPTIONS,
&opts, sizeof(opts));
if (SUCCEEDED(hr)) {
nv12Supported = !!opts.ExtendedResourceSharing;
}
}
blog(LOG_INFO, "D3D11 loaded successfully, feature level used: %u",
(unsigned int)levelUsed);
}
@@ -1315,7 +1326,7 @@ void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst,
throw "Source texture must be a 2D texture";
if (!dst)
throw "Destination surface is NULL";
if (dst->format != src->format)
if (dst->format != GS_UNKNOWN && dst->format != src->format)
throw "Source and destination formats do not match";
if (dst->width != src2d->width ||
dst->height != src2d->height)
@@ -2054,6 +2065,11 @@ extern "C" EXPORT bool device_shared_texture_available(void)
return true;
}
extern "C" EXPORT bool device_nv12_available(gs_device_t *device)
{
return device->nv12Supported;
}
extern "C" EXPORT gs_texture_t *device_texture_create_gdi(gs_device_t *device,
uint32_t width, uint32_t height)
{
@@ -2174,3 +2190,53 @@ extern "C" EXPORT int device_texture_release_sync(gs_texture_t *tex,
HRESULT hr = keyedMutex->ReleaseSync(key);
return hr == S_OK ? 0 : -1;
}
extern "C" EXPORT bool device_texture_create_nv12(gs_device_t *device,
gs_texture_t **p_tex_y, gs_texture_t **p_tex_uv,
uint32_t width, uint32_t height, uint32_t flags)
{
if (!device->nv12Supported)
return false;
*p_tex_y = nullptr;
*p_tex_uv = nullptr;
gs_texture_2d *tex_y;
gs_texture_2d *tex_uv;
try {
tex_y = new gs_texture_2d(device, width, height, GS_R8, 1,
nullptr, flags, GS_TEXTURE_2D, false, true);
tex_uv = new gs_texture_2d(device, tex_y->texture, flags);
} catch (HRError error) {
blog(LOG_ERROR, "gs_texture_create_nv12 (D3D11): %s (%08lX)",
error.str, error.hr);
LogD3D11ErrorDetails(error, device);
return false;
} catch (const char *error) {
blog(LOG_ERROR, "gs_texture_create_nv12 (D3D11): %s", error);
return false;
}
*p_tex_y = tex_y;
*p_tex_uv = tex_uv;
return true;
}
extern "C" EXPORT gs_stagesurf_t *device_stagesurface_create_nv12(
gs_device_t *device, uint32_t width, uint32_t height)
{
gs_stage_surface *surf = NULL;
try {
surf = new gs_stage_surface(device, width, height);
} catch (HRError error) {
blog(LOG_ERROR, "device_stagesurface_create (D3D11): %s "
"(%08lX)",
error.str, error.hr);
LogD3D11ErrorDetails(error, device);
}
return surf;
}

View File

@@ -27,7 +27,7 @@
#include <windows.h>
#include <dxgi.h>
#include <dxgi1_2.h>
#include <d3d11.h>
#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <util/base.h>
@@ -80,6 +80,7 @@ static inline DXGI_FORMAT ConvertGSTextureFormat(gs_color_format format)
case GS_DXT1: return DXGI_FORMAT_BC1_UNORM;
case GS_DXT3: return DXGI_FORMAT_BC2_UNORM;
case GS_DXT5: return DXGI_FORMAT_BC3_UNORM;
case GS_R8G8: return DXGI_FORMAT_R8G8_UNORM;
}
return DXGI_FORMAT_UNKNOWN;
@@ -90,6 +91,7 @@ static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format)
switch ((unsigned long)format) {
case DXGI_FORMAT_A8_UNORM: return GS_A8;
case DXGI_FORMAT_R8_UNORM: return GS_R8;
case DXGI_FORMAT_R8G8_UNORM: return GS_R8G8;
case DXGI_FORMAT_R8G8B8A8_UNORM: return GS_RGBA;
case DXGI_FORMAT_B8G8R8X8_UNORM: return GS_BGRX;
case DXGI_FORMAT_B8G8R8A8_UNORM: return GS_BGRA;
@@ -353,6 +355,10 @@ struct gs_texture_2d : gs_texture {
bool genMipmaps = false;
uint32_t sharedHandle = GS_INVALID_HANDLE;
gs_texture_2d *pairedNV12texture = nullptr;
bool nv12 = false;
bool chroma = false;
vector<vector<uint8_t>> data;
vector<D3D11_SUBRESOURCE_DATA> srd;
D3D11_TEXTURE2D_DESC td = {};
@@ -383,8 +389,11 @@ 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);
gs_texture_type type, bool gdiCompatible,
bool nv12 = false);
gs_texture_2d(gs_device_t *device, ID3D11Texture2D *nv12,
uint32_t flags);
gs_texture_2d(gs_device_t *device, uint32_t handle);
};
@@ -437,6 +446,7 @@ struct gs_stage_surface : gs_obj {
gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height,
gs_color_format colorFormat);
gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height);
};
struct gs_sampler_state : gs_obj {
@@ -780,6 +790,7 @@ struct gs_device {
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
uint32_t adpIdx = 0;
bool nv12Supported = false;
gs_texture_2d *curRenderTarget = nullptr;
gs_zstencil_buffer *curZStencilBuffer = nullptr;

View File

@@ -80,7 +80,7 @@ void gs_texture_2d::InitTexture(const uint8_t **data)
td.Height = height;
td.MipLevels = genMipmaps ? 0 : levels;
td.ArraySize = type == GS_TEXTURE_CUBE ? 6 : 1;
td.Format = dxgiFormat;
td.Format = nv12 ? DXGI_FORMAT_NV12 : dxgiFormat;
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
td.SampleDesc.Count = 1;
td.CPUAccessFlags = isDynamic ? D3D11_CPU_ACCESS_WRITE : 0;
@@ -182,7 +182,12 @@ void gs_texture_2d::InitRenderTargets()
{
HRESULT hr;
if (type == GS_TEXTURE_2D) {
hr = device->device->CreateRenderTargetView(texture, NULL,
D3D11_RENDER_TARGET_VIEW_DESC rtv;
rtv.Format = dxgiFormat;
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtv.Texture2D.MipSlice = 0;
hr = device->device->CreateRenderTargetView(texture, &rtv,
renderTarget[0].Assign());
if (FAILED(hr))
throw HRError("Failed to create render target view",
@@ -210,7 +215,7 @@ void gs_texture_2d::InitRenderTargets()
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 gdiCompatible, bool nv12_)
: gs_texture (device, gs_type::gs_texture_2d, type, levels,
colorFormat),
width (width),
@@ -222,7 +227,8 @@ gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t width,
isDynamic ((flags_ & GS_DYNAMIC) != 0),
isShared ((flags_ & SHARED_FLAGS) != 0),
genMipmaps ((flags_ & GS_BUILD_MIPMAPS) != 0),
sharedHandle (GS_INVALID_HANDLE)
sharedHandle (GS_INVALID_HANDLE),
nv12 (nv12_)
{
InitTexture(data);
InitResourceView();
@@ -231,6 +237,33 @@ gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t width,
InitRenderTargets();
}
gs_texture_2d::gs_texture_2d(gs_device_t *device, ID3D11Texture2D *nv12tex,
uint32_t flags_)
: gs_texture (device, gs_type::gs_texture_2d, GS_TEXTURE_2D),
isRenderTarget ((flags_ & GS_RENDER_TARGET) != 0),
isDynamic ((flags_ & GS_DYNAMIC) != 0),
isShared ((flags_ & SHARED_FLAGS) != 0),
genMipmaps ((flags_ & GS_BUILD_MIPMAPS) != 0),
nv12 (true)
{
texture = nv12tex;
texture->GetDesc(&td);
this->type = GS_TEXTURE_2D;
this->format = GS_R8G8;
this->flags = flags_;
this->levels = 1;
this->device = device;
this->chroma = true;
this->width = td.Width / 2;
this->height = td.Height / 2;
this->dxgiFormat = DXGI_FORMAT_R8G8_UNORM;
InitResourceView();
if (isRenderTarget)
InitRenderTargets();
}
gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t handle)
: gs_texture (device, gs_type::gs_texture_2d,
GS_TEXTURE_2D),