diff --git a/libobs-d3d11/CMakeLists.txt b/libobs-d3d11/CMakeLists.txt index 95d85c0c5c2da552d99c6f7dbcd78c6278348f54..e30828b237dfe56ead151751ec7d295a85c44ea6 100644 --- a/libobs-d3d11/CMakeLists.txt +++ b/libobs-d3d11/CMakeLists.txt @@ -14,6 +14,7 @@ set(libobs-d3d11_SOURCES d3d11-texture2d.cpp d3d11-vertexbuffer.cpp d3d11-duplicator.cpp + d3d11-rebuild.cpp d3d11-zstencilbuffer.cpp) set(libobs-d3d11_HEADERS diff --git a/libobs-d3d11/d3d11-rebuild.cpp b/libobs-d3d11/d3d11-rebuild.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03824c42c595e07061871ca57d76609d68631935 --- /dev/null +++ b/libobs-d3d11/d3d11-rebuild.cpp @@ -0,0 +1,313 @@ +/****************************************************************************** + Copyright (C) 2016 by Hugh Bailey + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +******************************************************************************/ + +#include "d3d11-subsystem.hpp" + +inline void gs_vertex_buffer::Rebuild() +{ + uvBuffers.clear(); + uvSizes.clear(); + BuildBuffers(); +} + +inline void gs_index_buffer::Rebuild(ID3D11Device *dev) +{ + HRESULT hr = dev->CreateBuffer(&bd, &srd, &indexBuffer); + if (FAILED(hr)) + throw HRError("Failed to create buffer", hr); +} + +inline void gs_texture_2d::Rebuild(ID3D11Device *dev) +{ + HRESULT hr; + if (isShared) { + hr = dev->OpenSharedResource((HANDLE)(uintptr_t)sharedHandle, + __uuidof(ID3D11Texture2D), (void**)&texture); + if (FAILED(hr)) + throw HRError("Failed to open shared 2D texture", hr); + } else { + hr = dev->CreateTexture2D(&td, + data.size() ? srd.data() : nullptr, + &texture); + if (FAILED(hr)) + throw HRError("Failed to create 2D texture", hr); + } + + hr = dev->CreateShaderResourceView(texture, &resourceDesc, &shaderRes); + if (FAILED(hr)) + throw HRError("Failed to create resource view", hr); + + if (isRenderTarget) + InitRenderTargets(); +} + +inline void gs_zstencil_buffer::Rebuild(ID3D11Device *dev) +{ + HRESULT hr; + hr = dev->CreateTexture2D(&td, nullptr, &texture); + if (FAILED(hr)) + throw HRError("Failed to create depth stencil texture", hr); + + hr = dev->CreateDepthStencilView(texture, &dsvd, &view); + if (FAILED(hr)) + throw HRError("Failed to create depth stencil view", hr); +} + +inline void gs_stage_surface::Rebuild(ID3D11Device *dev) +{ + HRESULT hr = dev->CreateTexture2D(&td, nullptr, &texture); + if (FAILED(hr)) + throw HRError("Failed to create staging surface", hr); +} + +inline void gs_sampler_state::Rebuild(ID3D11Device *dev) +{ + HRESULT hr = dev->CreateSamplerState(&sd, state.Assign()); + if (FAILED(hr)) + throw HRError("Failed to create sampler state", hr); +} + +inline void gs_vertex_shader::Rebuild(ID3D11Device *dev) +{ + HRESULT hr; + hr = dev->CreateVertexShader(data.data(), data.size(), nullptr, &shader); + if (FAILED(hr)) + throw HRError("Failed to create vertex shader", hr); + + hr = dev->CreateInputLayout(layoutData.data(), (UINT)layoutData.size(), + data.data(), data.size(), &layout); + if (FAILED(hr)) + throw HRError("Failed to create input layout", hr); + + if (constantSize) { + hr = dev->CreateBuffer(&bd, NULL, &constants); + if (FAILED(hr)) + throw HRError("Failed to create constant buffer", hr); + } + + for (gs_shader_param ¶m : params) { + param.nextSampler = nullptr; + param.curValue.clear(); + gs_shader_set_default(¶m); + } +} + +inline void gs_pixel_shader::Rebuild(ID3D11Device *dev) +{ + HRESULT hr; + + hr = dev->CreatePixelShader(data.data(), data.size(), nullptr, + &shader); + if (FAILED(hr)) + throw HRError("Failed to create pixel shader", hr); + + if (constantSize) { + hr = dev->CreateBuffer(&bd, NULL, &constants); + if (FAILED(hr)) + throw HRError("Failed to create constant buffer", hr); + } + + for (gs_shader_param ¶m : params) { + param.nextSampler = nullptr; + param.curValue.clear(); + gs_shader_set_default(¶m); + } +} + +inline void gs_swap_chain::Rebuild(ID3D11Device *dev) +{ + HRESULT hr = device->factory->CreateSwapChain(dev, &swapDesc, &swap); + if (FAILED(hr)) + throw HRError("Failed to create swap chain", hr); + Init(); +} + +inline void SavedBlendState::Rebuild(ID3D11Device *dev) +{ + HRESULT hr = dev->CreateBlendState(&bd, &state); + if (FAILED(hr)) + throw HRError("Failed to create blend state", hr); +} + +inline void SavedZStencilState::Rebuild(ID3D11Device *dev) +{ + HRESULT hr = dev->CreateDepthStencilState(&dsd, &state); + if (FAILED(hr)) + throw HRError("Failed to create depth stencil state", hr); +} + +inline void SavedRasterState::Rebuild(ID3D11Device *dev) +{ + HRESULT hr = dev->CreateRasterizerState(&rd, &state); + if (FAILED(hr)) + throw HRError("Failed to create rasterizer state", hr); +} + +const static D3D_FEATURE_LEVEL featureLevels[] = +{ + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, +}; + +void gs_device::RebuildDevice() +try { + ID3D11Device *dev = nullptr; + HRESULT hr; + + blog(LOG_WARNING, "Device Remove/Reset! Rebuilding all assets..."); + + /* ----------------------------------------------------------------- */ + + gs_obj *obj = first_obj; + + while (obj) { + switch (obj->obj_type) { + case gs_type::gs_vertex_buffer: + ((gs_vertex_buffer*)obj)->Release(); + break; + case gs_type::gs_index_buffer: + ((gs_index_buffer*)obj)->Release(); + break; + case gs_type::gs_texture_2d: + ((gs_texture_2d*)obj)->Release(); + break; + case gs_type::gs_zstencil_buffer: + ((gs_zstencil_buffer*)obj)->Release(); + break; + case gs_type::gs_stage_surface: + ((gs_stage_surface*)obj)->Release(); + break; + case gs_type::gs_sampler_state: + ((gs_sampler_state*)obj)->Release(); + break; + case gs_type::gs_vertex_shader: + ((gs_vertex_shader*)obj)->Release(); + break; + case gs_type::gs_pixel_shader: + ((gs_pixel_shader*)obj)->Release(); + break; + case gs_type::gs_duplicator: + ((gs_duplicator*)obj)->Release(); + break; + case gs_type::gs_swap_chain: + ((gs_swap_chain*)obj)->Release(); + break; + } + + obj = obj->next; + } + + for (auto &state : zstencilStates) + state.Release(); + for (auto &state : rasterStates) + state.Release(); + for (auto &state : blendStates) + state.Release(); + + context->ClearState(); + + context.Release(); + device.Release(); + adapter.Release(); + factory.Release(); + + /* ----------------------------------------------------------------- */ + + InitFactory(adpIdx); + + uint32_t createFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + hr = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, + nullptr, createFlags, featureLevels, + sizeof(featureLevels) / sizeof(D3D_FEATURE_LEVEL), + D3D11_SDK_VERSION, &device, nullptr, &context); + if (FAILED(hr)) + throw HRError("Failed to create device", hr); + + dev = device; + + obj = first_obj; + while (obj) { + switch (obj->obj_type) { + case gs_type::gs_vertex_buffer: + ((gs_vertex_buffer*)obj)->Rebuild(); + break; + case gs_type::gs_index_buffer: + ((gs_index_buffer*)obj)->Rebuild(dev); + break; + case gs_type::gs_texture_2d: + ((gs_texture_2d*)obj)->Rebuild(dev); + break; + case gs_type::gs_zstencil_buffer: + ((gs_zstencil_buffer*)obj)->Rebuild(dev); + break; + case gs_type::gs_stage_surface: + ((gs_stage_surface*)obj)->Rebuild(dev); + break; + case gs_type::gs_sampler_state: + ((gs_sampler_state*)obj)->Rebuild(dev); + break; + case gs_type::gs_vertex_shader: + ((gs_vertex_shader*)obj)->Rebuild(dev); + break; + case gs_type::gs_pixel_shader: + ((gs_pixel_shader*)obj)->Rebuild(dev); + break; + case gs_type::gs_duplicator: + ((gs_duplicator*)obj)->Start(); + break; + case gs_type::gs_swap_chain: + ((gs_swap_chain*)obj)->Rebuild(dev); + break; + } + + obj = obj->next; + } + + curRenderTarget = nullptr; + curZStencilBuffer = nullptr; + curRenderSide = 0; + memset(&curTextures, 0, sizeof(curTextures)); + memset(&curSamplers, 0, sizeof(curSamplers)); + curVertexBuffer = nullptr; + curIndexBuffer = nullptr; + curVertexShader = nullptr; + curPixelShader = nullptr; + curSwapChain = nullptr; + zstencilStateChanged = true; + rasterStateChanged = true; + blendStateChanged = true; + curDepthStencilState = nullptr; + curRasterState = nullptr; + curBlendState = nullptr; + curToplogy = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + + for (auto &state : zstencilStates) + state.Rebuild(dev); + for (auto &state : rasterStates) + state.Rebuild(dev); + for (auto &state : blendStates) + state.Rebuild(dev); + +} catch (const char *error) { + bcrash("Failed to recreate D3D11: %s", error); + +} catch (HRError error) { + bcrash("Failed to recreate D3D11: %s (%08lX)", + error.str, error.hr); +} diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index a665fcffc5a40ce465a61c7e7528afa27f7a4a1d..dbd6afb808b841be0bf9e0fde0c91db6cd0f939c 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -1432,8 +1432,14 @@ void device_clear(gs_device_t *device, uint32_t clear_flags, void device_present(gs_device_t *device) { + HRESULT hr; + if (device->curSwapChain) { - device->curSwapChain->swap->Present(0, 0); + hr = device->curSwapChain->swap->Present(0, 0); + if (hr == DXGI_ERROR_DEVICE_REMOVED || + hr == DXGI_ERROR_DEVICE_RESET) { + device->RebuildDevice(); + } } else { blog(LOG_WARNING, "device_present (D3D11): No active swap"); } diff --git a/libobs-d3d11/d3d11-subsystem.hpp b/libobs-d3d11/d3d11-subsystem.hpp index ae97a83976b085bed2251011f3394100dbf91ed4..1771dbf621d6cb6654629a923dc96c031a2fbcff 100644 --- a/libobs-d3d11/d3d11-subsystem.hpp +++ b/libobs-d3d11/d3d11-subsystem.hpp @@ -265,6 +265,8 @@ struct gs_vertex_buffer : gs_obj { uvBuffers.clear(); } + inline void Rebuild(); + gs_vertex_buffer(gs_device_t *device, struct gs_vb_data *data, uint32_t flags); }; @@ -290,6 +292,8 @@ struct gs_index_buffer : gs_obj { void InitBuffer(); + inline void Rebuild(ID3D11Device *dev); + inline void Release() {indexBuffer.Release();} gs_index_buffer(gs_device_t *device, enum gs_index_type type, @@ -304,6 +308,8 @@ struct gs_texture : gs_obj { ComPtr shaderRes; D3D11_SHADER_RESOURCE_VIEW_DESC resourceDesc = {}; + inline void Rebuild(ID3D11Device *dev); + inline gs_texture(gs_texture_type type, uint32_t levels, gs_color_format format) : type (type), @@ -354,6 +360,8 @@ struct gs_texture_2d : gs_texture { void InitRenderTargets(); void BackupTexture(const uint8_t **data); + inline void Rebuild(ID3D11Device *dev); + inline void Release() { texture.Release(); @@ -389,6 +397,8 @@ struct gs_zstencil_buffer : gs_obj { void InitBuffer(); + inline void Rebuild(ID3D11Device *dev); + inline void Release() { texture.Release(); @@ -414,6 +424,8 @@ struct gs_stage_surface : gs_obj { gs_color_format format; DXGI_FORMAT dxgiFormat; + inline void Rebuild(ID3D11Device *dev); + inline void Release() { texture.Release(); @@ -428,6 +440,8 @@ struct gs_sampler_state : gs_obj { D3D11_SAMPLER_DESC sd = {}; gs_sampler_info info; + inline void Rebuild(ID3D11Device *dev); + inline void Release() {state.Release();} gs_sampler_state(gs_device_t *device, const gs_sampler_info *info); @@ -515,6 +529,8 @@ struct gs_vertex_shader : gs_shader { bool hasTangents; uint32_t nTexUnits; + inline void Rebuild(ID3D11Device *dev); + inline void Release() { shader.Release(); @@ -558,6 +574,8 @@ struct gs_pixel_shader : gs_shader { ComPtr shader; vector> samplers; + inline void Rebuild(ID3D11Device *dev); + inline void Release() { shader.Release(); @@ -592,6 +610,8 @@ struct gs_swap_chain : gs_obj { void Resize(uint32_t cx, uint32_t cy); void Init(); + inline void Rebuild(ID3D11Device *dev); + inline void Release() { target.Release(); @@ -637,6 +657,8 @@ struct SavedBlendState : BlendState { ComPtr state; D3D11_BLEND_DESC bd; + inline void Rebuild(ID3D11Device *dev); + inline void Release() { state.Release(); @@ -692,6 +714,8 @@ struct SavedZStencilState : ZStencilState { ComPtr state; D3D11_DEPTH_STENCIL_DESC dsd; + inline void Rebuild(ID3D11Device *dev); + inline void Release() { state.Release(); @@ -725,6 +749,8 @@ struct SavedRasterState : RasterState { ComPtr state; D3D11_RASTERIZER_DESC rd; + inline void Rebuild(ID3D11Device *dev); + inline void Release() { state.Release(); @@ -804,6 +830,8 @@ struct gs_device { void UpdateViewProjMatrix(); + void RebuildDevice(); + gs_device(uint32_t adapterIdx); ~gs_device(); };