2013-09-30 19:37:13 -07:00
|
|
|
/******************************************************************************
|
|
|
|
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
|
|
|
|
|
|
|
|
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
|
2013-12-02 21:24:38 -08:00
|
|
|
the Free Software Foundation, either version 2 of the License, or
|
2013-09-30 19:37:13 -07:00
|
|
|
(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 <http://www.gnu.org/licenses/>.
|
|
|
|
******************************************************************************/
|
|
|
|
|
2015-02-06 16:27:23 -08:00
|
|
|
#include <cinttypes>
|
2013-11-26 22:07:27 -08:00
|
|
|
#include <util/base.h>
|
|
|
|
#include <util/platform.h>
|
2019-02-26 08:37:23 -08:00
|
|
|
#include <util/dstr.h>
|
|
|
|
#include <util/util.hpp>
|
2013-11-26 22:07:27 -08:00
|
|
|
#include <graphics/matrix3.h>
|
2019-10-07 02:23:46 -07:00
|
|
|
#include <winternl.h>
|
2019-04-02 23:22:19 -07:00
|
|
|
#include <d3d9.h>
|
2013-10-10 08:01:09 -07:00
|
|
|
#include "d3d11-subsystem.hpp"
|
2019-10-07 02:23:46 -07:00
|
|
|
#include "d3d11-config.h"
|
2020-02-25 23:38:18 -08:00
|
|
|
#include "intel-nv12-support.hpp"
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-07-20 17:40:57 -07:00
|
|
|
struct UnsupportedHWError : HRError {
|
|
|
|
inline UnsupportedHWError(const char *str, HRESULT hr)
|
|
|
|
: HRError(str, hr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-12-14 15:01:30 -08:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
/* alignment warning - despite the fact that alignment is already fixed */
|
2019-06-22 22:13:45 -07:00
|
|
|
#pragma warning(disable : 4316)
|
2013-12-14 15:01:30 -08:00
|
|
|
#endif
|
|
|
|
|
2016-10-06 23:39:35 -07:00
|
|
|
static inline void LogD3D11ErrorDetails(HRError error, gs_device_t *device)
|
|
|
|
{
|
|
|
|
if (error.hr == DXGI_ERROR_DEVICE_REMOVED) {
|
|
|
|
HRESULT DeviceRemovedReason =
|
2019-06-22 22:13:45 -07:00
|
|
|
device->device->GetDeviceRemovedReason();
|
2016-10-06 23:39:35 -07:00
|
|
|
blog(LOG_ERROR, " Device Removed Reason: %08lX",
|
2019-06-22 22:13:45 -07:00
|
|
|
DeviceRemovedReason);
|
2016-10-06 23:39:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
static const IID dxgiFactory2 = {0x50c83a1c,
|
|
|
|
0xe072,
|
|
|
|
0x4c48,
|
|
|
|
{0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6,
|
|
|
|
0xd0}};
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_obj::gs_obj(gs_device_t *device_, gs_type type)
|
|
|
|
: device(device_), obj_type(type)
|
2016-11-03 07:37:05 -07:00
|
|
|
{
|
|
|
|
prev_next = &device->first_obj;
|
|
|
|
next = device->first_obj;
|
|
|
|
device->first_obj = this;
|
|
|
|
if (next)
|
|
|
|
next->prev_next = &next;
|
|
|
|
}
|
|
|
|
|
|
|
|
gs_obj::~gs_obj()
|
|
|
|
{
|
|
|
|
if (prev_next)
|
|
|
|
*prev_next = next;
|
|
|
|
if (next)
|
|
|
|
next->prev_next = prev_next;
|
|
|
|
}
|
|
|
|
|
2020-03-11 09:35:47 -07:00
|
|
|
static inline void make_swap_desc(DXGI_SWAP_CHAIN_DESC &desc,
|
|
|
|
const gs_init_data *data)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
memset(&desc, 0, sizeof(desc));
|
2020-03-11 09:35:47 -07:00
|
|
|
desc.BufferCount = data->num_backbuffers;
|
|
|
|
desc.BufferDesc.Format = ConvertGSTextureFormat(data->format);
|
2019-06-22 22:13:45 -07:00
|
|
|
desc.BufferDesc.Width = data->cx;
|
2013-09-30 19:37:13 -07:00
|
|
|
desc.BufferDesc.Height = data->cy;
|
2019-06-22 22:13:45 -07:00
|
|
|
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
|
|
|
desc.OutputWindow = (HWND)data->window.hwnd;
|
2020-03-11 09:35:47 -07:00
|
|
|
desc.SampleDesc.Count = 1;
|
2019-06-22 22:13:45 -07:00
|
|
|
desc.Windowed = true;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void gs_swap_chain::InitTarget(uint32_t cx, uint32_t cy)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
target.width = cx;
|
2013-09-30 19:37:13 -07:00
|
|
|
target.height = cy;
|
|
|
|
|
|
|
|
hr = swap->GetBuffer(0, __uuidof(ID3D11Texture2D),
|
2019-06-22 22:13:45 -07:00
|
|
|
(void **)target.texture.Assign());
|
2013-09-30 19:37:13 -07:00
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to get swap buffer texture", hr);
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
hr = device->device->CreateRenderTargetView(
|
|
|
|
target.texture, NULL, target.renderTarget[0].Assign());
|
2013-09-30 19:37:13 -07:00
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to create swap render target view", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_swap_chain::InitZStencilBuffer(uint32_t cx, uint32_t cy)
|
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
zs.width = cx;
|
2013-09-30 19:37:13 -07:00
|
|
|
zs.height = cy;
|
|
|
|
|
|
|
|
if (zs.format != GS_ZS_NONE && cx != 0 && cy != 0) {
|
|
|
|
zs.InitBuffer();
|
|
|
|
} else {
|
|
|
|
zs.texture.Clear();
|
|
|
|
zs.view.Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_swap_chain::Resize(uint32_t cx, uint32_t cy)
|
|
|
|
{
|
|
|
|
RECT clientRect;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
target.texture.Clear();
|
|
|
|
target.renderTarget[0].Clear();
|
|
|
|
zs.texture.Clear();
|
|
|
|
zs.view.Clear();
|
|
|
|
|
2016-11-03 07:09:13 -07:00
|
|
|
initData.cx = cx;
|
|
|
|
initData.cy = cy;
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
if (cx == 0 || cy == 0) {
|
|
|
|
GetClientRect(hwnd, &clientRect);
|
2019-06-22 22:13:45 -07:00
|
|
|
if (cx == 0)
|
|
|
|
cx = clientRect.right;
|
|
|
|
if (cy == 0)
|
|
|
|
cy = clientRect.bottom;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
hr = swap->ResizeBuffers(numBuffers, cx, cy, target.dxgiFormat, 0);
|
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to resize swap buffers", hr);
|
|
|
|
|
|
|
|
InitTarget(cx, cy);
|
|
|
|
InitZStencilBuffer(cx, cy);
|
|
|
|
}
|
|
|
|
|
2016-11-03 07:09:13 -07:00
|
|
|
void gs_swap_chain::Init()
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
target.device = device;
|
2013-09-30 19:37:13 -07:00
|
|
|
target.isRenderTarget = true;
|
2019-06-22 22:13:45 -07:00
|
|
|
target.format = initData.format;
|
|
|
|
target.dxgiFormat = ConvertGSTextureFormat(initData.format);
|
2016-11-03 07:09:13 -07:00
|
|
|
InitTarget(initData.cx, initData.cy);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
zs.device = device;
|
|
|
|
zs.format = initData.zsformat;
|
2016-11-03 07:09:13 -07:00
|
|
|
zs.dxgiFormat = ConvertGSZStencilFormat(initData.zsformat);
|
|
|
|
InitZStencilBuffer(initData.cx, initData.cy);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data)
|
2019-06-22 22:13:45 -07:00
|
|
|
: gs_obj(device, gs_type::gs_swap_chain),
|
|
|
|
numBuffers(data->num_backbuffers),
|
|
|
|
hwnd((HWND)data->window.hwnd),
|
|
|
|
initData(*data)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
2020-03-11 09:35:47 -07:00
|
|
|
make_swap_desc(swapDesc, data);
|
2013-09-30 19:37:13 -07:00
|
|
|
hr = device->factory->CreateSwapChain(device->device, &swapDesc,
|
2019-06-22 22:13:45 -07:00
|
|
|
swap.Assign());
|
2020-03-11 09:35:47 -07:00
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to create swap chain", hr);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2018-03-29 12:25:56 -07:00
|
|
|
/* Ignore Alt+Enter */
|
|
|
|
device->factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER);
|
|
|
|
|
2016-11-03 07:09:13 -07:00
|
|
|
Init();
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-10-03 14:29:47 -07:00
|
|
|
void gs_device::InitCompiler()
|
|
|
|
{
|
|
|
|
char d3dcompiler[40] = {};
|
|
|
|
int ver = 49;
|
|
|
|
|
|
|
|
while (ver > 30) {
|
2015-02-06 16:38:02 -08:00
|
|
|
sprintf(d3dcompiler, "D3DCompiler_%02d.dll", ver);
|
2014-10-03 14:29:47 -07:00
|
|
|
|
|
|
|
HMODULE module = LoadLibraryA(d3dcompiler);
|
|
|
|
if (module) {
|
|
|
|
d3dCompile = (pD3DCompile)GetProcAddress(module,
|
2019-06-22 22:13:45 -07:00
|
|
|
"D3DCompile");
|
2016-11-25 12:01:31 -08:00
|
|
|
|
|
|
|
#ifdef DISASSEMBLE_SHADERS
|
|
|
|
d3dDisassemble = (pD3DDisassemble)GetProcAddress(
|
2019-06-22 22:13:45 -07:00
|
|
|
module, "D3DDisassemble");
|
2016-11-25 12:01:31 -08:00
|
|
|
#endif
|
2014-10-03 14:29:47 -07:00
|
|
|
if (d3dCompile) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(module);
|
|
|
|
}
|
|
|
|
|
|
|
|
ver--;
|
|
|
|
}
|
|
|
|
|
2017-06-25 13:26:31 -07:00
|
|
|
throw "Could not find any D3DCompiler libraries. Make sure you've "
|
2019-06-22 22:13:45 -07:00
|
|
|
"installed the <a href=\"https://obsproject.com/go/dxwebsetup\">"
|
|
|
|
"DirectX components</a> that OBS Studio requires.";
|
2014-10-03 14:29:47 -07:00
|
|
|
}
|
|
|
|
|
2016-11-03 06:39:24 -07:00
|
|
|
void gs_device::InitFactory(uint32_t adapterIdx)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
2019-06-22 22:13:45 -07:00
|
|
|
IID factoryIID = (GetWinVer() >= 0x602) ? dxgiFactory2
|
|
|
|
: __uuidof(IDXGIFactory1);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
hr = CreateDXGIFactory1(factoryIID, (void **)factory.Assign());
|
2013-09-30 19:37:13 -07:00
|
|
|
if (FAILED(hr))
|
2014-07-20 17:40:57 -07:00
|
|
|
throw UnsupportedHWError("Failed to create DXGIFactory", hr);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2016-11-03 06:39:24 -07:00
|
|
|
hr = factory->EnumAdapters1(adapterIdx, &adapter);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (FAILED(hr))
|
2014-07-20 17:40:57 -07:00
|
|
|
throw UnsupportedHWError("Failed to enumerate DXGIAdapter", hr);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
const static D3D_FEATURE_LEVEL featureLevels[] = {
|
2013-09-30 19:37:13 -07:00
|
|
|
D3D_FEATURE_LEVEL_11_0,
|
|
|
|
D3D_FEATURE_LEVEL_10_1,
|
|
|
|
D3D_FEATURE_LEVEL_10_0,
|
|
|
|
};
|
|
|
|
|
2019-03-04 14:06:10 -08:00
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
#define VERT_IN_OUT \
|
|
|
|
"\
|
2019-03-04 14:06:10 -08:00
|
|
|
struct VertInOut { \
|
|
|
|
float4 pos : POSITION; \
|
|
|
|
}; "
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
#define NV12_Y_PS \
|
|
|
|
VERT_IN_OUT "\
|
2019-03-04 14:06:10 -08:00
|
|
|
float main(VertInOut vert_in) : TARGET \
|
|
|
|
{ \
|
|
|
|
return 1.0; \
|
|
|
|
}"
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
#define NV12_UV_PS \
|
|
|
|
VERT_IN_OUT "\
|
2019-03-04 14:06:10 -08:00
|
|
|
float2 main(VertInOut vert_in) : TARGET \
|
|
|
|
{ \
|
|
|
|
return float2(1.0, 1.0); \
|
|
|
|
}"
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
#define NV12_VS \
|
|
|
|
VERT_IN_OUT "\
|
2019-03-04 14:06:10 -08:00
|
|
|
VertInOut main(VertInOut vert_in) \
|
|
|
|
{ \
|
|
|
|
VertInOut vert_out; \
|
|
|
|
vert_out.pos = float4(vert_in.pos.xyz, 1.0); \
|
|
|
|
return vert_out; \
|
|
|
|
} "
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
#define NV12_CX 128
|
|
|
|
#define NV12_CY 128
|
|
|
|
|
2019-03-04 15:40:53 -08:00
|
|
|
bool gs_device::HasBadNV12Output()
|
2019-03-04 14:06:10 -08:00
|
|
|
try {
|
|
|
|
vec3 points[4];
|
|
|
|
vec3_set(&points[0], -1.0f, -1.0f, 0.0f);
|
2019-06-22 22:13:45 -07:00
|
|
|
vec3_set(&points[1], -1.0f, 1.0f, 0.0f);
|
|
|
|
vec3_set(&points[2], 1.0f, -1.0f, 0.0f);
|
|
|
|
vec3_set(&points[3], 1.0f, 1.0f, 0.0f);
|
2019-03-04 14:06:10 -08:00
|
|
|
|
|
|
|
gs_texture_2d nv12_y(this, NV12_CX, NV12_CY, GS_R8, 1, nullptr,
|
2019-06-22 22:13:45 -07:00
|
|
|
GS_RENDER_TARGET | GS_SHARED_KM_TEX, GS_TEXTURE_2D,
|
|
|
|
false, true);
|
2019-03-11 13:34:22 -07:00
|
|
|
gs_texture_2d nv12_uv(this, nv12_y.texture,
|
2019-06-22 22:13:45 -07:00
|
|
|
GS_RENDER_TARGET | GS_SHARED_KM_TEX);
|
2019-03-04 14:06:10 -08:00
|
|
|
gs_vertex_shader nv12_vs(this, "", NV12_VS);
|
|
|
|
gs_pixel_shader nv12_y_ps(this, "", NV12_Y_PS);
|
|
|
|
gs_pixel_shader nv12_uv_ps(this, "", NV12_UV_PS);
|
|
|
|
gs_stage_surface nv12_stage(this, NV12_CX, NV12_CY);
|
|
|
|
|
|
|
|
gs_vb_data *vbd = gs_vbdata_create();
|
2019-06-22 22:13:45 -07:00
|
|
|
vbd->num = 4;
|
|
|
|
vbd->points = (vec3 *)bmemdup(&points, sizeof(points));
|
2019-03-04 14:06:10 -08:00
|
|
|
|
|
|
|
gs_vertex_buffer buf(this, vbd, 0);
|
|
|
|
|
|
|
|
device_load_vertexbuffer(this, &buf);
|
|
|
|
device_load_vertexshader(this, &nv12_vs);
|
|
|
|
|
|
|
|
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
|
|
|
|
|
|
|
device_set_viewport(this, 0, 0, NV12_CX, NV12_CY);
|
|
|
|
device_set_cull_mode(this, GS_NEITHER);
|
|
|
|
device_enable_depth_test(this, false);
|
|
|
|
device_enable_blending(this, false);
|
|
|
|
LoadVertexBufferData();
|
|
|
|
|
|
|
|
device_set_render_target(this, &nv12_y, nullptr);
|
|
|
|
device_load_pixelshader(this, &nv12_y_ps);
|
|
|
|
UpdateBlendState();
|
|
|
|
UpdateRasterState();
|
|
|
|
UpdateZStencilState();
|
|
|
|
context->Draw(4, 0);
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
device_set_viewport(this, 0, 0, NV12_CX / 2, NV12_CY / 2);
|
2019-03-04 14:06:10 -08:00
|
|
|
device_set_render_target(this, &nv12_uv, nullptr);
|
|
|
|
device_load_pixelshader(this, &nv12_uv_ps);
|
|
|
|
UpdateBlendState();
|
|
|
|
UpdateRasterState();
|
|
|
|
UpdateZStencilState();
|
|
|
|
context->Draw(4, 0);
|
|
|
|
|
|
|
|
device_load_pixelshader(this, nullptr);
|
2019-06-24 15:51:01 -07:00
|
|
|
device_load_vertexbuffer(this, nullptr);
|
2019-03-04 14:06:10 -08:00
|
|
|
device_load_vertexshader(this, nullptr);
|
|
|
|
device_set_render_target(this, nullptr, nullptr);
|
|
|
|
|
|
|
|
device_stage_texture(this, &nv12_stage, &nv12_y);
|
|
|
|
|
|
|
|
uint8_t *data;
|
|
|
|
uint32_t linesize;
|
|
|
|
bool bad_driver = false;
|
|
|
|
|
|
|
|
if (gs_stagesurface_map(&nv12_stage, &data, &linesize)) {
|
|
|
|
bad_driver = data[linesize * NV12_CY] == 0;
|
|
|
|
gs_stagesurface_unmap(&nv12_stage);
|
2019-03-11 13:41:29 -07:00
|
|
|
} else {
|
|
|
|
throw "Could not map surface";
|
2019-03-04 14:06:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (bad_driver) {
|
|
|
|
blog(LOG_WARNING, "Bad NV12 texture handling detected! "
|
|
|
|
"Disabling NV12 texture support.");
|
|
|
|
}
|
|
|
|
return bad_driver;
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_WARNING, "HasBadNV12Output failed: %s (%08lX)", error.str,
|
|
|
|
error.hr);
|
2019-03-04 14:06:10 -08:00
|
|
|
return false;
|
2019-03-11 13:41:29 -07:00
|
|
|
} catch (const char *error) {
|
|
|
|
blog(LOG_WARNING, "HasBadNV12Output failed: %s", error);
|
2019-03-04 14:06:10 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-19 10:00:59 -08:00
|
|
|
static bool increase_maximum_frame_latency(ID3D11Device *device)
|
|
|
|
{
|
|
|
|
ComQIPtr<IDXGIDevice1> dxgiDevice(device);
|
|
|
|
if (!dxgiDevice) {
|
|
|
|
blog(LOG_DEBUG, "%s: Failed to get IDXGIDevice1", __FUNCTION__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const HRESULT hr = dxgiDevice->SetMaximumFrameLatency(16);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
blog(LOG_DEBUG, "%s: SetMaximumFrameLatency failed",
|
|
|
|
__FUNCTION__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
blog(LOG_INFO, "DXGI increase maximum frame latency success");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-07 02:23:46 -07:00
|
|
|
#if USE_GPU_PRIORITY
|
|
|
|
static bool set_priority(ID3D11Device *device)
|
|
|
|
{
|
|
|
|
typedef enum _D3DKMT_SCHEDULINGPRIORITYCLASS {
|
|
|
|
D3DKMT_SCHEDULINGPRIORITYCLASS_IDLE,
|
|
|
|
D3DKMT_SCHEDULINGPRIORITYCLASS_BELOW_NORMAL,
|
|
|
|
D3DKMT_SCHEDULINGPRIORITYCLASS_NORMAL,
|
|
|
|
D3DKMT_SCHEDULINGPRIORITYCLASS_ABOVE_NORMAL,
|
|
|
|
D3DKMT_SCHEDULINGPRIORITYCLASS_HIGH,
|
|
|
|
D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME
|
|
|
|
} D3DKMT_SCHEDULINGPRIORITYCLASS;
|
|
|
|
|
|
|
|
ComQIPtr<IDXGIDevice> dxgiDevice(device);
|
|
|
|
if (!dxgiDevice) {
|
|
|
|
blog(LOG_DEBUG, "%s: Failed to get IDXGIDevice", __FUNCTION__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
HMODULE gdi32 = GetModuleHandleW(L"GDI32");
|
|
|
|
if (!gdi32) {
|
|
|
|
blog(LOG_DEBUG, "%s: Failed to get GDI32", __FUNCTION__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-11 17:40:50 -07:00
|
|
|
NTSTATUS(WINAPI * d3dkmt_spspc)(HANDLE, D3DKMT_SCHEDULINGPRIORITYCLASS);
|
2019-10-07 02:23:46 -07:00
|
|
|
d3dkmt_spspc = (decltype(d3dkmt_spspc))GetProcAddress(
|
|
|
|
gdi32, "D3DKMTSetProcessSchedulingPriorityClass");
|
|
|
|
if (!d3dkmt_spspc) {
|
|
|
|
blog(LOG_DEBUG, "%s: Failed to get d3dkmt_spspc", __FUNCTION__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS status = d3dkmt_spspc(GetCurrentProcess(),
|
|
|
|
D3DKMT_SCHEDULINGPRIORITYCLASS_REALTIME);
|
|
|
|
if (status != 0) {
|
|
|
|
blog(LOG_DEBUG, "%s: Failed to set process priority class: %d",
|
|
|
|
__FUNCTION__, (int)status);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT hr = dxgiDevice->SetGPUThreadPriority(GPU_PRIORITY_VAL);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
blog(LOG_DEBUG, "%s: SetGPUThreadPriority failed",
|
|
|
|
__FUNCTION__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
blog(LOG_INFO, "D3D11 GPU priority setup success");
|
|
|
|
return true;
|
|
|
|
}
|
2019-10-10 03:02:58 -07:00
|
|
|
|
2019-10-07 02:23:46 -07:00
|
|
|
#endif
|
|
|
|
|
2016-11-03 06:39:24 -07:00
|
|
|
void gs_device::InitDevice(uint32_t adapterIdx)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
wstring adapterName;
|
|
|
|
DXGI_ADAPTER_DESC desc;
|
2019-09-08 22:41:17 -07:00
|
|
|
D3D_FEATURE_LEVEL levelUsed = D3D_FEATURE_LEVEL_10_0;
|
2015-02-09 01:08:26 -08:00
|
|
|
HRESULT hr = 0;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2016-11-03 07:10:58 -07:00
|
|
|
adpIdx = adapterIdx;
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
uint32_t createFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
|
|
|
|
#ifdef _DEBUG
|
2013-11-07 15:45:03 -08:00
|
|
|
//createFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
2013-09-30 19:37:13 -07:00
|
|
|
#endif
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
adapterName = (adapter->GetDesc(&desc) == S_OK) ? desc.Description
|
|
|
|
: L"<unknown>";
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-02-26 08:37:23 -08:00
|
|
|
BPtr<char> adapterNameUTF8;
|
2014-03-04 06:07:13 -08:00
|
|
|
os_wcs_to_utf8_ptr(adapterName.c_str(), 0, &adapterNameUTF8);
|
2015-01-14 21:26:23 -08:00
|
|
|
blog(LOG_INFO, "Loading up D3D11 on adapter %s (%" PRIu32 ")",
|
2019-06-22 22:13:45 -07:00
|
|
|
adapterNameUTF8.Get(), adapterIdx);
|
|
|
|
|
|
|
|
hr = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL,
|
|
|
|
createFlags, featureLevels,
|
|
|
|
sizeof(featureLevels) /
|
|
|
|
sizeof(D3D_FEATURE_LEVEL),
|
|
|
|
D3D11_SDK_VERSION, device.Assign(), &levelUsed,
|
|
|
|
context.Assign());
|
2013-09-30 19:37:13 -07:00
|
|
|
if (FAILED(hr))
|
2015-07-31 23:09:48 -07:00
|
|
|
throw UnsupportedHWError("Failed to create device", hr);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-08-28 21:11:48 -07:00
|
|
|
blog(LOG_INFO, "D3D11 loaded successfully, feature level used: %x",
|
2019-06-22 22:13:45 -07:00
|
|
|
(unsigned int)levelUsed);
|
2019-02-25 23:02:54 -08:00
|
|
|
|
2019-12-19 10:00:59 -08:00
|
|
|
/* prevent stalls sometimes seen in Present calls */
|
|
|
|
if (!increase_maximum_frame_latency(device)) {
|
|
|
|
blog(LOG_INFO, "DXGI increase maximum frame latency failed");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adjust gpu thread priority on non-intel GPUs */
|
2019-10-07 02:23:46 -07:00
|
|
|
#if USE_GPU_PRIORITY
|
2019-10-14 14:06:33 -07:00
|
|
|
if (desc.VendorId != 0x8086 && !set_priority(device)) {
|
2019-10-10 03:02:58 -07:00
|
|
|
blog(LOG_INFO, "D3D11 GPU priority setup "
|
|
|
|
"failed (not admin?)");
|
2019-10-07 02:23:46 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-02-25 23:02:54 -08:00
|
|
|
/* ---------------------------------------- */
|
|
|
|
/* check for nv12 texture output support */
|
|
|
|
|
|
|
|
nv12Supported = false;
|
2019-02-26 12:09:00 -08:00
|
|
|
|
2019-10-06 20:30:49 -07:00
|
|
|
/* WARP NV12 support is suspected to be buggy on older Windows */
|
|
|
|
if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-15 22:55:48 -07:00
|
|
|
/* Intel CopyResource is very slow with NV12 */
|
2020-02-25 23:38:18 -08:00
|
|
|
if (desc.VendorId == 0x8086 && IsOldIntelPlatform(desc.DeviceId)) {
|
2019-08-15 22:55:48 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-05 03:15:13 -07:00
|
|
|
ComQIPtr<ID3D11Device1> d3d11_1(device);
|
2019-02-25 23:02:54 -08:00
|
|
|
if (!d3d11_1) {
|
|
|
|
return;
|
2018-10-05 03:15:13 -07:00
|
|
|
}
|
|
|
|
|
2019-02-25 23:02:54 -08:00
|
|
|
/* needs to support extended resource sharing */
|
|
|
|
D3D11_FEATURE_DATA_D3D11_OPTIONS opts = {};
|
2019-06-22 22:13:45 -07:00
|
|
|
hr = d3d11_1->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &opts,
|
|
|
|
sizeof(opts));
|
2019-02-25 23:02:54 -08:00
|
|
|
if (FAILED(hr) || !opts.ExtendedResourceSharing) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* needs to support the actual format */
|
|
|
|
UINT support = 0;
|
2019-06-22 22:13:45 -07:00
|
|
|
hr = device->CheckFormatSupport(DXGI_FORMAT_NV12, &support);
|
2019-02-25 23:02:54 -08:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((support & D3D11_FORMAT_SUPPORT_TEXTURE2D) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* must be usable as a render target */
|
|
|
|
if ((support & D3D11_FORMAT_SUPPORT_RENDER_TARGET) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-04 15:40:53 -08:00
|
|
|
if (HasBadNV12Output()) {
|
2019-03-04 14:06:10 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-25 23:02:54 -08:00
|
|
|
nv12Supported = true;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void ConvertStencilSide(D3D11_DEPTH_STENCILOP_DESC &desc,
|
2019-06-22 22:13:45 -07:00
|
|
|
const StencilSide &side)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
desc.StencilFunc = ConvertGSDepthTest(side.test);
|
|
|
|
desc.StencilFailOp = ConvertGSStencilOp(side.fail);
|
2013-09-30 19:37:13 -07:00
|
|
|
desc.StencilDepthFailOp = ConvertGSStencilOp(side.zfail);
|
2019-06-22 22:13:45 -07:00
|
|
|
desc.StencilPassOp = ConvertGSStencilOp(side.zpass);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ID3D11DepthStencilState *gs_device::AddZStencilState()
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
D3D11_DEPTH_STENCIL_DESC dsd;
|
|
|
|
ID3D11DepthStencilState *state;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
dsd.DepthEnable = zstencilState.depthEnabled;
|
|
|
|
dsd.DepthFunc = ConvertGSDepthTest(zstencilState.depthFunc);
|
|
|
|
dsd.DepthWriteMask = zstencilState.depthWriteEnabled
|
|
|
|
? D3D11_DEPTH_WRITE_MASK_ALL
|
|
|
|
: D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
|
|
dsd.StencilEnable = zstencilState.stencilEnabled;
|
|
|
|
dsd.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
|
|
|
dsd.StencilWriteMask = zstencilState.stencilWriteEnabled
|
|
|
|
? D3D11_DEFAULT_STENCIL_WRITE_MASK
|
|
|
|
: 0;
|
2013-09-30 19:37:13 -07:00
|
|
|
ConvertStencilSide(dsd.FrontFace, zstencilState.stencilFront);
|
2019-06-22 22:13:45 -07:00
|
|
|
ConvertStencilSide(dsd.BackFace, zstencilState.stencilBack);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2016-11-03 07:30:22 -07:00
|
|
|
SavedZStencilState savedState(zstencilState, dsd);
|
2013-09-30 19:37:13 -07:00
|
|
|
hr = device->CreateDepthStencilState(&dsd, savedState.state.Assign());
|
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to create depth stencil state", hr);
|
|
|
|
|
|
|
|
state = savedState.state;
|
|
|
|
zstencilStates.push_back(savedState);
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
ID3D11RasterizerState *gs_device::AddRasterState()
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
D3D11_RASTERIZER_DESC rd;
|
|
|
|
ID3D11RasterizerState *state;
|
|
|
|
|
|
|
|
memset(&rd, 0, sizeof(rd));
|
2013-10-17 17:21:42 -07:00
|
|
|
/* use CCW to convert to a right-handed coordinate system */
|
2013-10-16 23:31:18 -07:00
|
|
|
rd.FrontCounterClockwise = true;
|
2019-06-22 22:13:45 -07:00
|
|
|
rd.FillMode = D3D11_FILL_SOLID;
|
|
|
|
rd.CullMode = ConvertGSCullMode(rasterState.cullMode);
|
|
|
|
rd.DepthClipEnable = true;
|
|
|
|
rd.ScissorEnable = rasterState.scissorEnabled;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2016-11-03 07:30:22 -07:00
|
|
|
SavedRasterState savedState(rasterState, rd);
|
2013-09-30 19:37:13 -07:00
|
|
|
hr = device->CreateRasterizerState(&rd, savedState.state.Assign());
|
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to create rasterizer state", hr);
|
|
|
|
|
|
|
|
state = savedState.state;
|
|
|
|
rasterStates.push_back(savedState);
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
ID3D11BlendState *gs_device::AddBlendState()
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
D3D11_BLEND_DESC bd;
|
|
|
|
ID3D11BlendState *state;
|
|
|
|
|
|
|
|
memset(&bd, 0, sizeof(bd));
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2019-06-22 22:13:45 -07:00
|
|
|
bd.RenderTarget[i].BlendEnable = blendState.blendEnabled;
|
|
|
|
bd.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD;
|
|
|
|
bd.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
2013-09-30 19:37:13 -07:00
|
|
|
bd.RenderTarget[i].SrcBlend =
|
2015-03-27 11:18:02 -07:00
|
|
|
ConvertGSBlendType(blendState.srcFactorC);
|
2013-09-30 19:37:13 -07:00
|
|
|
bd.RenderTarget[i].DestBlend =
|
2015-03-27 11:18:02 -07:00
|
|
|
ConvertGSBlendType(blendState.destFactorC);
|
2014-08-11 17:40:35 -07:00
|
|
|
bd.RenderTarget[i].SrcBlendAlpha =
|
2015-03-27 11:18:02 -07:00
|
|
|
ConvertGSBlendType(blendState.srcFactorA);
|
2014-08-11 17:40:35 -07:00
|
|
|
bd.RenderTarget[i].DestBlendAlpha =
|
2015-03-27 11:18:02 -07:00
|
|
|
ConvertGSBlendType(blendState.destFactorA);
|
2013-09-30 19:37:13 -07:00
|
|
|
bd.RenderTarget[i].RenderTargetWriteMask =
|
2019-06-22 22:13:45 -07:00
|
|
|
(blendState.redEnabled ? D3D11_COLOR_WRITE_ENABLE_RED
|
|
|
|
: 0) |
|
|
|
|
(blendState.greenEnabled
|
|
|
|
? D3D11_COLOR_WRITE_ENABLE_GREEN
|
|
|
|
: 0) |
|
|
|
|
(blendState.blueEnabled ? D3D11_COLOR_WRITE_ENABLE_BLUE
|
|
|
|
: 0) |
|
|
|
|
(blendState.alphaEnabled
|
|
|
|
? D3D11_COLOR_WRITE_ENABLE_ALPHA
|
|
|
|
: 0);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2016-11-03 07:30:22 -07:00
|
|
|
SavedBlendState savedState(blendState, bd);
|
2013-09-30 19:37:13 -07:00
|
|
|
hr = device->CreateBlendState(&bd, savedState.state.Assign());
|
|
|
|
if (FAILED(hr))
|
2016-11-03 06:56:49 -07:00
|
|
|
throw HRError("Failed to create blend state", hr);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
state = savedState.state;
|
|
|
|
blendStates.push_back(savedState);
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_device::UpdateZStencilState()
|
|
|
|
{
|
|
|
|
ID3D11DepthStencilState *state = NULL;
|
|
|
|
|
|
|
|
if (!zstencilStateChanged)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < zstencilStates.size(); i++) {
|
|
|
|
SavedZStencilState &s = zstencilStates[i];
|
|
|
|
if (memcmp(&s, &zstencilState, sizeof(zstencilState)) == 0) {
|
|
|
|
state = s.state;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!state)
|
|
|
|
state = AddZStencilState();
|
|
|
|
|
|
|
|
if (state != curDepthStencilState) {
|
|
|
|
context->OMSetDepthStencilState(state, 0);
|
|
|
|
curDepthStencilState = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
zstencilStateChanged = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_device::UpdateRasterState()
|
|
|
|
{
|
|
|
|
ID3D11RasterizerState *state = NULL;
|
|
|
|
|
|
|
|
if (!rasterStateChanged)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < rasterStates.size(); i++) {
|
|
|
|
SavedRasterState &s = rasterStates[i];
|
|
|
|
if (memcmp(&s, &rasterState, sizeof(rasterState)) == 0) {
|
|
|
|
state = s.state;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!state)
|
|
|
|
state = AddRasterState();
|
|
|
|
|
|
|
|
if (state != curRasterState) {
|
|
|
|
context->RSSetState(state);
|
|
|
|
curRasterState = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
rasterStateChanged = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_device::UpdateBlendState()
|
|
|
|
{
|
|
|
|
ID3D11BlendState *state = NULL;
|
|
|
|
|
|
|
|
if (!blendStateChanged)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < blendStates.size(); i++) {
|
|
|
|
SavedBlendState &s = blendStates[i];
|
|
|
|
if (memcmp(&s, &blendState, sizeof(blendState)) == 0) {
|
|
|
|
state = s.state;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!state)
|
|
|
|
state = AddBlendState();
|
|
|
|
|
|
|
|
if (state != curBlendState) {
|
|
|
|
float f[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
|
|
|
context->OMSetBlendState(state, f, 0xFFFFFFFF);
|
|
|
|
curBlendState = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
blendStateChanged = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_device::UpdateViewProjMatrix()
|
|
|
|
{
|
2014-06-14 23:09:13 -07:00
|
|
|
gs_matrix_get(&curViewMatrix);
|
2013-10-16 23:31:18 -07:00
|
|
|
|
|
|
|
/* negate Z col of the view matrix for right-handed coordinate system */
|
|
|
|
curViewMatrix.x.z = -curViewMatrix.x.z;
|
|
|
|
curViewMatrix.y.z = -curViewMatrix.y.z;
|
|
|
|
curViewMatrix.z.z = -curViewMatrix.z.z;
|
|
|
|
curViewMatrix.t.z = -curViewMatrix.t.z;
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
matrix4_mul(&curViewProjMatrix, &curViewMatrix, &curProjMatrix);
|
|
|
|
matrix4_transpose(&curViewProjMatrix, &curViewProjMatrix);
|
|
|
|
|
|
|
|
if (curVertexShader->viewProj)
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_shader_set_matrix4(curVertexShader->viewProj,
|
2019-06-22 22:13:45 -07:00
|
|
|
&curViewProjMatrix);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2015-07-31 23:09:48 -07:00
|
|
|
gs_device::gs_device(uint32_t adapterIdx)
|
2019-06-22 22:13:45 -07:00
|
|
|
: curToplogy(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
matrix4_identity(&curProjMatrix);
|
|
|
|
matrix4_identity(&curViewMatrix);
|
|
|
|
matrix4_identity(&curViewProjMatrix);
|
|
|
|
|
|
|
|
memset(&viewport, 0, sizeof(viewport));
|
|
|
|
|
2013-10-10 12:37:03 -07:00
|
|
|
for (size_t i = 0; i < GS_MAX_TEXTURES; i++) {
|
2013-09-30 19:37:13 -07:00
|
|
|
curTextures[i] = NULL;
|
|
|
|
curSamplers[i] = NULL;
|
|
|
|
}
|
|
|
|
|
2014-10-03 14:29:47 -07:00
|
|
|
InitCompiler();
|
2016-11-03 06:39:24 -07:00
|
|
|
InitFactory(adapterIdx);
|
|
|
|
InitDevice(adapterIdx);
|
2014-08-07 23:42:07 -07:00
|
|
|
device_set_render_target(this, NULL, NULL);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2016-11-03 07:03:02 -07:00
|
|
|
gs_device::~gs_device()
|
|
|
|
{
|
|
|
|
context->ClearState();
|
|
|
|
}
|
|
|
|
|
2014-08-07 23:42:07 -07:00
|
|
|
const char *device_get_name(void)
|
2014-07-20 15:31:45 -07:00
|
|
|
{
|
|
|
|
return "Direct3D 11";
|
|
|
|
}
|
|
|
|
|
2014-08-07 23:42:07 -07:00
|
|
|
int device_get_type(void)
|
2014-07-20 16:19:43 -07:00
|
|
|
{
|
|
|
|
return GS_DEVICE_DIRECT3D_11;
|
|
|
|
}
|
|
|
|
|
2014-02-16 18:28:21 -08:00
|
|
|
const char *device_preprocessor_name(void)
|
|
|
|
{
|
|
|
|
return "_D3D11";
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
static inline void
|
|
|
|
EnumD3DAdapters(bool (*callback)(void *, const char *, uint32_t), void *param)
|
2015-01-14 21:08:33 -08:00
|
|
|
{
|
|
|
|
ComPtr<IDXGIFactory1> factory;
|
|
|
|
ComPtr<IDXGIAdapter1> adapter;
|
|
|
|
HRESULT hr;
|
2019-05-22 23:06:00 -07:00
|
|
|
UINT i;
|
2015-01-14 21:08:33 -08:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
IID factoryIID = (GetWinVer() >= 0x602) ? dxgiFactory2
|
|
|
|
: __uuidof(IDXGIFactory1);
|
2015-01-14 21:08:33 -08:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
hr = CreateDXGIFactory1(factoryIID, (void **)factory.Assign());
|
2015-01-14 21:08:33 -08:00
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to create DXGIFactory", hr);
|
|
|
|
|
2019-05-22 23:06:00 -07:00
|
|
|
for (i = 0; factory->EnumAdapters1(i, adapter.Assign()) == S_OK; ++i) {
|
2015-01-14 21:08:33 -08:00
|
|
|
DXGI_ADAPTER_DESC desc;
|
|
|
|
char name[512] = "";
|
|
|
|
|
|
|
|
hr = adapter->GetDesc(&desc);
|
|
|
|
if (FAILED(hr))
|
|
|
|
continue;
|
|
|
|
|
2017-03-19 04:35:51 -07:00
|
|
|
/* ignore Microsoft's 'basic' renderer' */
|
2015-01-14 21:08:33 -08:00
|
|
|
if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
os_wcs_to_utf8(desc.Description, 0, name, sizeof(name));
|
|
|
|
|
2019-05-22 23:06:00 -07:00
|
|
|
if (!callback(param, name, i))
|
2015-01-14 21:08:33 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
bool device_enum_adapters(bool (*callback)(void *param, const char *name,
|
|
|
|
uint32_t id),
|
|
|
|
void *param)
|
2015-01-14 21:08:33 -08:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
EnumD3DAdapters(callback, param);
|
|
|
|
return true;
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2015-01-14 21:08:33 -08:00
|
|
|
blog(LOG_WARNING, "Failed enumerating devices: %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2015-01-14 21:08:33 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 20:00:43 -07:00
|
|
|
static bool GetMonitorTarget(const MONITORINFOEX &info,
|
|
|
|
DISPLAYCONFIG_TARGET_DEVICE_NAME &target)
|
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
UINT32 numPath, numMode;
|
|
|
|
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath,
|
|
|
|
&numMode) == ERROR_SUCCESS) {
|
|
|
|
std::vector<DISPLAYCONFIG_PATH_INFO> paths(numPath);
|
|
|
|
std::vector<DISPLAYCONFIG_MODE_INFO> modes(numMode);
|
|
|
|
if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPath,
|
|
|
|
paths.data(), &numMode, modes.data(),
|
|
|
|
nullptr) == ERROR_SUCCESS) {
|
|
|
|
paths.resize(numPath);
|
|
|
|
for (size_t i = 0; i < numPath; ++i) {
|
|
|
|
const DISPLAYCONFIG_PATH_INFO &path = paths[i];
|
|
|
|
|
|
|
|
DISPLAYCONFIG_SOURCE_DEVICE_NAME
|
|
|
|
source;
|
|
|
|
source.header.type =
|
|
|
|
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
|
|
|
|
source.header.size = sizeof(source);
|
|
|
|
source.header.adapterId =
|
|
|
|
path.sourceInfo.adapterId;
|
|
|
|
source.header.id = path.sourceInfo.id;
|
|
|
|
if (DisplayConfigGetDeviceInfo(
|
|
|
|
&source.header) == ERROR_SUCCESS &&
|
|
|
|
wcscmp(info.szDevice,
|
|
|
|
source.viewGdiDeviceName) == 0) {
|
|
|
|
target.header.type =
|
|
|
|
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
|
|
|
|
target.header.size = sizeof(target);
|
|
|
|
target.header.adapterId =
|
|
|
|
path.sourceInfo.adapterId;
|
|
|
|
target.header.id = path.targetInfo.id;
|
|
|
|
found = DisplayConfigGetDeviceInfo(
|
|
|
|
&target.header) ==
|
|
|
|
ERROR_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2015-12-21 14:19:20 -08:00
|
|
|
static inline void LogAdapterMonitors(IDXGIAdapter1 *adapter)
|
2015-01-14 21:27:00 -08:00
|
|
|
{
|
2019-05-22 23:06:00 -07:00
|
|
|
UINT i;
|
2015-12-21 14:19:20 -08:00
|
|
|
ComPtr<IDXGIOutput> output;
|
|
|
|
|
2019-05-22 23:06:00 -07:00
|
|
|
for (i = 0; adapter->EnumOutputs(i, &output) == S_OK; ++i) {
|
2015-12-21 14:19:20 -08:00
|
|
|
DXGI_OUTPUT_DESC desc;
|
|
|
|
if (FAILED(output->GetDesc(&desc)))
|
|
|
|
continue;
|
|
|
|
|
2019-09-29 16:24:03 -07:00
|
|
|
unsigned refresh = 0;
|
|
|
|
|
2019-10-01 20:00:43 -07:00
|
|
|
bool target_found = false;
|
|
|
|
DISPLAYCONFIG_TARGET_DEVICE_NAME target;
|
|
|
|
|
2019-09-29 16:24:03 -07:00
|
|
|
MONITORINFOEX info;
|
|
|
|
info.cbSize = sizeof(info);
|
|
|
|
if (GetMonitorInfo(desc.Monitor, &info)) {
|
2019-10-01 20:00:43 -07:00
|
|
|
target_found = GetMonitorTarget(info, target);
|
|
|
|
|
2019-09-29 16:24:03 -07:00
|
|
|
DEVMODE mode;
|
|
|
|
mode.dmSize = sizeof(mode);
|
|
|
|
mode.dmDriverExtra = 0;
|
|
|
|
if (EnumDisplaySettings(info.szDevice,
|
|
|
|
ENUM_CURRENT_SETTINGS, &mode)) {
|
|
|
|
refresh = mode.dmDisplayFrequency;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 20:00:43 -07:00
|
|
|
if (!target_found) {
|
|
|
|
target.monitorFriendlyDeviceName[0] = 0;
|
|
|
|
}
|
|
|
|
|
2019-09-29 16:24:03 -07:00
|
|
|
const RECT &rect = desc.DesktopCoordinates;
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_INFO,
|
|
|
|
"\t output %u: "
|
|
|
|
"pos={%d, %d}, "
|
|
|
|
"size={%d, %d}, "
|
2019-09-29 16:24:03 -07:00
|
|
|
"attached=%s, "
|
2019-10-01 20:00:43 -07:00
|
|
|
"refresh=%u, "
|
|
|
|
"name=%ls",
|
2019-06-22 22:13:45 -07:00
|
|
|
i, rect.left, rect.top, rect.right - rect.left,
|
|
|
|
rect.bottom - rect.top,
|
2019-10-01 20:00:43 -07:00
|
|
|
desc.AttachedToDesktop ? "true" : "false", refresh,
|
|
|
|
target.monitorFriendlyDeviceName);
|
2015-12-21 14:19:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void LogD3DAdapters()
|
|
|
|
{
|
|
|
|
ComPtr<IDXGIFactory1> factory;
|
|
|
|
ComPtr<IDXGIAdapter1> adapter;
|
|
|
|
HRESULT hr;
|
2019-05-22 23:06:00 -07:00
|
|
|
UINT i;
|
2015-12-21 14:19:20 -08:00
|
|
|
|
|
|
|
blog(LOG_INFO, "Available Video Adapters: ");
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
IID factoryIID = (GetWinVer() >= 0x602) ? dxgiFactory2
|
|
|
|
: __uuidof(IDXGIFactory1);
|
2015-12-21 14:19:20 -08:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
hr = CreateDXGIFactory1(factoryIID, (void **)factory.Assign());
|
2015-12-21 14:19:20 -08:00
|
|
|
if (FAILED(hr))
|
|
|
|
throw HRError("Failed to create DXGIFactory", hr);
|
|
|
|
|
2019-05-22 23:06:00 -07:00
|
|
|
for (i = 0; factory->EnumAdapters1(i, adapter.Assign()) == S_OK; ++i) {
|
2015-12-21 14:19:20 -08:00
|
|
|
DXGI_ADAPTER_DESC desc;
|
|
|
|
char name[512] = "";
|
|
|
|
|
|
|
|
hr = adapter->GetDesc(&desc);
|
|
|
|
if (FAILED(hr))
|
|
|
|
continue;
|
|
|
|
|
2017-03-19 04:35:51 -07:00
|
|
|
/* ignore Microsoft's 'basic' renderer' */
|
2015-12-21 14:19:20 -08:00
|
|
|
if (desc.VendorId == 0x1414 && desc.DeviceId == 0x8c)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
os_wcs_to_utf8(desc.Description, 0, name, sizeof(name));
|
|
|
|
blog(LOG_INFO, "\tAdapter %u: %s", i, name);
|
|
|
|
blog(LOG_INFO, "\t Dedicated VRAM: %u",
|
2019-06-22 22:13:45 -07:00
|
|
|
desc.DedicatedVideoMemory);
|
2015-12-21 14:19:20 -08:00
|
|
|
blog(LOG_INFO, "\t Shared VRAM: %u",
|
2019-06-22 22:13:45 -07:00
|
|
|
desc.SharedSystemMemory);
|
2020-03-23 12:54:38 -07:00
|
|
|
blog(LOG_INFO, "\t PCI ID: %x:%x", desc.VendorId,
|
|
|
|
desc.DeviceId);
|
2015-12-21 14:19:20 -08:00
|
|
|
|
2019-10-05 15:03:23 -07:00
|
|
|
/* driver version */
|
|
|
|
LARGE_INTEGER umd;
|
|
|
|
hr = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice),
|
|
|
|
&umd);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
const uint64_t version = umd.QuadPart;
|
|
|
|
const uint16_t aa = (version >> 48) & 0xffff;
|
|
|
|
const uint16_t bb = (version >> 32) & 0xffff;
|
|
|
|
const uint16_t ccccc = (version >> 16) & 0xffff;
|
|
|
|
const uint16_t ddddd = version & 0xffff;
|
|
|
|
blog(LOG_INFO,
|
|
|
|
"\t Driver Version: %" PRIu16 ".%" PRIu16
|
|
|
|
".%" PRIu16 ".%" PRIu16,
|
|
|
|
aa, bb, ccccc, ddddd);
|
|
|
|
} else {
|
|
|
|
blog(LOG_INFO, "\t Driver Version: Unknown (0x%X)",
|
|
|
|
(unsigned)hr);
|
|
|
|
}
|
|
|
|
|
2015-12-21 14:19:20 -08:00
|
|
|
LogAdapterMonitors(adapter);
|
|
|
|
}
|
2015-01-14 21:27:00 -08:00
|
|
|
}
|
|
|
|
|
2015-07-31 23:09:48 -07:00
|
|
|
int device_create(gs_device_t **p_device, uint32_t adapter)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_device *device = NULL;
|
2014-07-20 17:40:57 -07:00
|
|
|
int errorcode = GS_SUCCESS;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
try {
|
2015-01-14 21:27:00 -08:00
|
|
|
blog(LOG_INFO, "---------------------------------");
|
2017-03-19 04:35:51 -07:00
|
|
|
blog(LOG_INFO, "Initializing D3D11...");
|
2015-12-21 14:19:20 -08:00
|
|
|
LogD3DAdapters();
|
2015-01-14 21:27:00 -08:00
|
|
|
|
2015-07-31 23:09:48 -07:00
|
|
|
device = new gs_device(adapter);
|
2014-07-20 17:40:57 -07:00
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const UnsupportedHWError &error) {
|
2014-07-20 17:40:57 -07:00
|
|
|
blog(LOG_ERROR, "device_create (D3D11): %s (%08lX)", error.str,
|
2019-06-22 22:13:45 -07:00
|
|
|
error.hr);
|
2014-07-20 17:40:57 -07:00
|
|
|
errorcode = GS_ERROR_NOT_SUPPORTED;
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2013-09-30 19:37:13 -07:00
|
|
|
blog(LOG_ERROR, "device_create (D3D11): %s (%08lX)", error.str,
|
2019-06-22 22:13:45 -07:00
|
|
|
error.hr);
|
2014-07-20 17:40:57 -07:00
|
|
|
errorcode = GS_ERROR_FAIL;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-07-20 17:40:57 -07:00
|
|
|
*p_device = device;
|
|
|
|
return errorcode;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_destroy(gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
delete device;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_enter_context(gs_device_t *device)
|
2013-10-14 12:37:52 -07:00
|
|
|
{
|
|
|
|
/* does nothing */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(device);
|
2013-10-14 12:37:52 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_leave_context(gs_device_t *device)
|
2013-10-14 12:37:52 -07:00
|
|
|
{
|
|
|
|
/* does nothing */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(device);
|
2013-10-14 12:37:52 -07:00
|
|
|
}
|
|
|
|
|
2019-08-29 12:43:10 -07:00
|
|
|
void *device_get_device_obj(gs_device_t *device)
|
|
|
|
{
|
|
|
|
return (void *)device->device.Get();
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_swapchain_t *device_swapchain_create(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
const struct gs_init_data *data)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_swap_chain *swap = NULL;
|
|
|
|
|
|
|
|
try {
|
|
|
|
swap = new gs_swap_chain(device, data);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_swapchain_create (D3D11): %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return swap;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_resize(gs_device_t *device, uint32_t cx, uint32_t cy)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2015-07-30 17:16:24 -07:00
|
|
|
if (!device->curSwapChain) {
|
|
|
|
blog(LOG_WARNING, "device_resize (D3D11): No active swap");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
try {
|
|
|
|
ID3D11RenderTargetView *renderView = NULL;
|
2019-06-22 22:13:45 -07:00
|
|
|
ID3D11DepthStencilView *depthView = NULL;
|
2013-09-30 19:37:13 -07:00
|
|
|
int i = device->curRenderSide;
|
|
|
|
|
|
|
|
device->context->OMSetRenderTargets(1, &renderView, depthView);
|
|
|
|
device->curSwapChain->Resize(cx, cy);
|
|
|
|
|
|
|
|
if (device->curRenderTarget)
|
|
|
|
renderView = device->curRenderTarget->renderTarget[i];
|
|
|
|
if (device->curZStencilBuffer)
|
2019-06-22 22:13:45 -07:00
|
|
|
depthView = device->curZStencilBuffer->view;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->context->OMSetRenderTargets(1, &renderView, depthView);
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR, "device_resize (D3D11): %s (%08lX)", error.str,
|
|
|
|
error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
void device_get_size(const gs_device_t *device, uint32_t *cx, uint32_t *cy)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2015-07-30 17:16:24 -07:00
|
|
|
if (device->curSwapChain) {
|
|
|
|
*cx = device->curSwapChain->target.width;
|
|
|
|
*cy = device->curSwapChain->target.height;
|
|
|
|
} else {
|
|
|
|
blog(LOG_ERROR, "device_get_size (D3D11): no active swap");
|
|
|
|
*cx = 0;
|
|
|
|
*cy = 0;
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t device_get_width(const gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2015-07-30 17:16:24 -07:00
|
|
|
if (device->curSwapChain) {
|
|
|
|
return device->curSwapChain->target.width;
|
|
|
|
} else {
|
|
|
|
blog(LOG_ERROR, "device_get_size (D3D11): no active swap");
|
|
|
|
return 0;
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t device_get_height(const gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2015-07-30 17:16:24 -07:00
|
|
|
if (device->curSwapChain) {
|
|
|
|
return device->curSwapChain->target.height;
|
|
|
|
} else {
|
|
|
|
blog(LOG_ERROR, "device_get_size (D3D11): no active swap");
|
|
|
|
return 0;
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_texture_t *device_texture_create(gs_device_t *device, uint32_t width,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t height,
|
|
|
|
enum gs_color_format color_format,
|
|
|
|
uint32_t levels, const uint8_t **data,
|
|
|
|
uint32_t flags)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_texture *texture = NULL;
|
|
|
|
try {
|
|
|
|
texture = new gs_texture_2d(device, width, height, color_format,
|
2019-06-22 22:13:45 -07:00
|
|
|
levels, data, flags, GS_TEXTURE_2D,
|
|
|
|
false);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_texture_create (D3D11): %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
} catch (const char *error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_texture_create (D3D11): %s", error);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_texture_t *device_cubetexture_create(gs_device_t *device, uint32_t size,
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_color_format color_format,
|
|
|
|
uint32_t levels, const uint8_t **data,
|
|
|
|
uint32_t flags)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_texture *texture = NULL;
|
|
|
|
try {
|
|
|
|
texture = new gs_texture_2d(device, size, size, color_format,
|
2019-06-22 22:13:45 -07:00
|
|
|
levels, data, flags,
|
|
|
|
GS_TEXTURE_CUBE, false);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_cubetexture_create (D3D11): %s "
|
|
|
|
"(%08lX)",
|
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
} catch (const char *error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR, "device_cubetexture_create (D3D11): %s", error);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_texture_t *device_voltexture_create(gs_device_t *device, uint32_t width,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t height, uint32_t depth,
|
|
|
|
enum gs_color_format color_format,
|
2019-12-15 11:36:24 -08:00
|
|
|
uint32_t levels,
|
|
|
|
const uint8_t *const *data,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t flags)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-12-15 11:36:24 -08:00
|
|
|
gs_texture *texture = NULL;
|
|
|
|
try {
|
|
|
|
texture = new gs_texture_3d(device, width, height, depth,
|
|
|
|
color_format, levels, data, flags);
|
|
|
|
} catch (const HRError &error) {
|
|
|
|
blog(LOG_ERROR, "device_voltexture_create (D3D11): %s (%08lX)",
|
|
|
|
error.str, error.hr);
|
|
|
|
LogD3D11ErrorDetails(error, device);
|
|
|
|
} catch (const char *error) {
|
|
|
|
blog(LOG_ERROR, "device_voltexture_create (D3D11): %s", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return texture;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_zstencil_t *device_zstencil_create(gs_device_t *device, uint32_t width,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t height,
|
|
|
|
enum gs_zstencil_format format)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_zstencil_buffer *zstencil = NULL;
|
|
|
|
try {
|
2019-06-22 22:13:45 -07:00
|
|
|
zstencil =
|
|
|
|
new gs_zstencil_buffer(device, width, height, format);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_zstencil_create (D3D11): %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return zstencil;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_stagesurf_t *device_stagesurface_create(gs_device_t *device, uint32_t width,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t height,
|
|
|
|
enum gs_color_format color_format)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_stage_surface *surf = NULL;
|
|
|
|
try {
|
|
|
|
surf = new gs_stage_surface(device, width, height,
|
2019-06-22 22:13:45 -07:00
|
|
|
color_format);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_stagesurface_create (D3D11): %s "
|
|
|
|
"(%08lX)",
|
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return surf;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_samplerstate_t *
|
|
|
|
device_samplerstate_create(gs_device_t *device,
|
|
|
|
const struct gs_sampler_info *info)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_sampler_state *ss = NULL;
|
|
|
|
try {
|
|
|
|
ss = new gs_sampler_state(device, info);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_samplerstate_create (D3D11): %s "
|
|
|
|
"(%08lX)",
|
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return ss;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_shader_t *device_vertexshader_create(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
const char *shader_string,
|
|
|
|
const char *file, char **error_string)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_vertex_shader *shader = NULL;
|
|
|
|
try {
|
|
|
|
shader = new gs_vertex_shader(device, file, shader_string);
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_vertexshader_create (D3D11): %s "
|
|
|
|
"(%08lX)",
|
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const ShaderError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
const char *buf =
|
|
|
|
(const char *)error.errors->GetBufferPointer();
|
2013-09-30 19:37:13 -07:00
|
|
|
if (error_string)
|
|
|
|
*error_string = bstrdup(buf);
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_vertexshader_create (D3D11): "
|
|
|
|
"Compile warnings/errors for %s:\n%s",
|
|
|
|
file, buf);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
} catch (const char *error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_vertexshader_create (D3D11): %s",
|
2019-06-22 22:13:45 -07:00
|
|
|
error);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_shader_t *device_pixelshader_create(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
const char *shader_string,
|
|
|
|
const char *file, char **error_string)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_pixel_shader *shader = NULL;
|
|
|
|
try {
|
|
|
|
shader = new gs_pixel_shader(device, file, shader_string);
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_pixelshader_create (D3D11): %s "
|
|
|
|
"(%08lX)",
|
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const ShaderError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
const char *buf =
|
|
|
|
(const char *)error.errors->GetBufferPointer();
|
2013-09-30 19:37:13 -07:00
|
|
|
if (error_string)
|
|
|
|
*error_string = bstrdup(buf);
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_pixelshader_create (D3D11): "
|
|
|
|
"Compiler warnings/errors for %s:\n%s",
|
|
|
|
file, buf);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
} catch (const char *error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR, "device_pixelshader_create (D3D11): %s", error);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_vertbuffer_t *device_vertexbuffer_create(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
struct gs_vb_data *data,
|
|
|
|
uint32_t flags)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_vertex_buffer *buffer = NULL;
|
|
|
|
try {
|
|
|
|
buffer = new gs_vertex_buffer(device, data, flags);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_vertexbuffer_create (D3D11): %s "
|
|
|
|
"(%08lX)",
|
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
} catch (const char *error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_vertexbuffer_create (D3D11): %s",
|
2019-06-22 22:13:45 -07:00
|
|
|
error);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_indexbuffer_t *device_indexbuffer_create(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_index_type type,
|
|
|
|
void *indices, size_t num,
|
|
|
|
uint32_t flags)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
gs_index_buffer *buffer = NULL;
|
|
|
|
try {
|
|
|
|
buffer = new gs_index_buffer(device, type, indices, num, flags);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_indexbuffer_create (D3D11): %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2019-07-27 13:31:07 -07:00
|
|
|
gs_timer_t *device_timer_create(gs_device_t *device)
|
|
|
|
{
|
|
|
|
gs_timer *timer = NULL;
|
|
|
|
try {
|
|
|
|
timer = new gs_timer(device);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-07-27 13:31:07 -07:00
|
|
|
blog(LOG_ERROR, "device_timer_create (D3D11): %s (%08lX)",
|
|
|
|
error.str, error.hr);
|
|
|
|
LogD3D11ErrorDetails(error, device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
gs_timer_range_t *device_timer_range_create(gs_device_t *device)
|
|
|
|
{
|
|
|
|
gs_timer_range *range = NULL;
|
|
|
|
try {
|
|
|
|
range = new gs_timer_range(device);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-07-27 13:31:07 -07:00
|
|
|
blog(LOG_ERROR, "device_timer_range_create (D3D11): %s (%08lX)",
|
|
|
|
error.str, error.hr);
|
|
|
|
LogD3D11ErrorDetails(error, device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
enum gs_texture_type device_get_texture_type(const gs_texture_t *texture)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return texture->type;
|
|
|
|
}
|
|
|
|
|
2017-05-15 23:35:50 -07:00
|
|
|
void gs_device::LoadVertexBufferData()
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2017-05-15 23:35:50 -07:00
|
|
|
if (curVertexBuffer == lastVertexBuffer &&
|
|
|
|
curVertexShader == lastVertexShader)
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
vector<ID3D11Buffer *> buffers;
|
2013-09-30 19:37:13 -07:00
|
|
|
vector<uint32_t> strides;
|
|
|
|
vector<uint32_t> offsets;
|
|
|
|
|
2017-05-15 23:35:50 -07:00
|
|
|
if (curVertexBuffer && curVertexShader) {
|
2019-06-22 22:13:45 -07:00
|
|
|
curVertexBuffer->MakeBufferList(curVertexShader, buffers,
|
|
|
|
strides);
|
2013-09-30 19:37:13 -07:00
|
|
|
} else {
|
2019-06-22 22:13:45 -07:00
|
|
|
size_t buffersToClear =
|
|
|
|
curVertexShader ? curVertexShader->NumBuffersExpected()
|
|
|
|
: 0;
|
2013-09-30 19:37:13 -07:00
|
|
|
buffers.resize(buffersToClear);
|
|
|
|
strides.resize(buffersToClear);
|
|
|
|
}
|
|
|
|
|
|
|
|
offsets.resize(buffers.size());
|
2019-06-22 22:13:45 -07:00
|
|
|
context->IASetVertexBuffers(0, (UINT)buffers.size(), buffers.data(),
|
|
|
|
strides.data(), offsets.data());
|
2017-05-15 23:35:50 -07:00
|
|
|
|
|
|
|
lastVertexBuffer = curVertexBuffer;
|
|
|
|
lastVertexShader = curVertexShader;
|
|
|
|
}
|
|
|
|
|
|
|
|
void device_load_vertexbuffer(gs_device_t *device, gs_vertbuffer_t *vertbuffer)
|
|
|
|
{
|
|
|
|
if (device->curVertexBuffer == vertbuffer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
device->curVertexBuffer = vertbuffer;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_load_indexbuffer(gs_device_t *device, gs_indexbuffer_t *indexbuffer)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
DXGI_FORMAT format;
|
|
|
|
ID3D11Buffer *buffer;
|
|
|
|
|
|
|
|
if (device->curIndexBuffer == indexbuffer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (indexbuffer) {
|
|
|
|
switch (indexbuffer->indexSize) {
|
2019-06-22 22:13:45 -07:00
|
|
|
case 2:
|
|
|
|
format = DXGI_FORMAT_R16_UINT;
|
|
|
|
break;
|
2014-06-25 01:32:11 -07:00
|
|
|
default:
|
2019-06-22 22:13:45 -07:00
|
|
|
case 4:
|
|
|
|
format = DXGI_FORMAT_R32_UINT;
|
|
|
|
break;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer = indexbuffer->indexBuffer;
|
|
|
|
} else {
|
|
|
|
buffer = NULL;
|
|
|
|
format = DXGI_FORMAT_R32_UINT;
|
|
|
|
}
|
|
|
|
|
|
|
|
device->curIndexBuffer = indexbuffer;
|
|
|
|
device->context->IASetIndexBuffer(buffer, format, 0);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_load_texture(gs_device_t *device, gs_texture_t *tex, int unit)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
ID3D11ShaderResourceView *view = NULL;
|
|
|
|
|
|
|
|
if (device->curTextures[unit] == tex)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (tex)
|
|
|
|
view = tex->shaderRes;
|
|
|
|
|
|
|
|
device->curTextures[unit] = tex;
|
|
|
|
device->context->PSSetShaderResources(unit, 1, &view);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_load_samplerstate(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_samplerstate_t *samplerstate, int unit)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
ID3D11SamplerState *state = NULL;
|
|
|
|
|
|
|
|
if (device->curSamplers[unit] == samplerstate)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (samplerstate)
|
|
|
|
state = samplerstate->state;
|
|
|
|
|
|
|
|
device->curSamplers[unit] = samplerstate;
|
|
|
|
device->context->PSSetSamplers(unit, 1, &state);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_load_vertexshader(gs_device_t *device, gs_shader_t *vertshader)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
ID3D11VertexShader *shader = NULL;
|
|
|
|
ID3D11InputLayout *layout = NULL;
|
|
|
|
ID3D11Buffer *constants = NULL;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
if (device->curVertexShader == vertshader)
|
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_vertex_shader *vs = static_cast<gs_vertex_shader *>(vertshader);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
if (vertshader) {
|
2014-08-07 23:42:07 -07:00
|
|
|
if (vertshader->type != GS_SHADER_VERTEX) {
|
2013-09-30 19:37:13 -07:00
|
|
|
blog(LOG_ERROR, "device_load_vertexshader (D3D11): "
|
2019-06-22 22:13:45 -07:00
|
|
|
"Specified shader is not a vertex "
|
|
|
|
"shader");
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
shader = vs->shader;
|
|
|
|
layout = vs->layout;
|
2013-09-30 19:37:13 -07:00
|
|
|
constants = vs->constants;
|
|
|
|
}
|
|
|
|
|
|
|
|
device->curVertexShader = vs;
|
|
|
|
device->context->VSSetShader(shader, NULL, 0);
|
|
|
|
device->context->IASetInputLayout(layout);
|
|
|
|
device->context->VSSetConstantBuffers(0, 1, &constants);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
static inline void clear_textures(gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2013-10-10 12:37:03 -07:00
|
|
|
ID3D11ShaderResourceView *views[GS_MAX_TEXTURES];
|
2019-06-22 22:13:45 -07:00
|
|
|
memset(views, 0, sizeof(views));
|
2013-09-30 19:37:13 -07:00
|
|
|
memset(device->curTextures, 0, sizeof(device->curTextures));
|
2013-10-10 12:37:03 -07:00
|
|
|
device->context->PSSetShaderResources(0, GS_MAX_TEXTURES, views);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_load_pixelshader(gs_device_t *device, gs_shader_t *pixelshader)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
ID3D11PixelShader *shader = NULL;
|
|
|
|
ID3D11Buffer *constants = NULL;
|
2013-10-10 12:37:03 -07:00
|
|
|
ID3D11SamplerState *states[GS_MAX_TEXTURES];
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
if (device->curPixelShader == pixelshader)
|
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_pixel_shader *ps = static_cast<gs_pixel_shader *>(pixelshader);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
if (pixelshader) {
|
2014-08-07 23:42:07 -07:00
|
|
|
if (pixelshader->type != GS_SHADER_PIXEL) {
|
2013-09-30 19:37:13 -07:00
|
|
|
blog(LOG_ERROR, "device_load_pixelshader (D3D11): "
|
2019-06-22 22:13:45 -07:00
|
|
|
"Specified shader is not a pixel "
|
|
|
|
"shader");
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
shader = ps->shader;
|
2013-09-30 19:37:13 -07:00
|
|
|
constants = ps->constants;
|
|
|
|
ps->GetSamplerStates(states);
|
|
|
|
} else {
|
|
|
|
memset(states, 0, sizeof(states));
|
|
|
|
}
|
|
|
|
|
|
|
|
clear_textures(device);
|
|
|
|
|
|
|
|
device->curPixelShader = ps;
|
|
|
|
device->context->PSSetShader(shader, NULL, 0);
|
|
|
|
device->context->PSSetConstantBuffers(0, 1, &constants);
|
2013-10-10 12:37:03 -07:00
|
|
|
device->context->PSSetSamplers(0, GS_MAX_TEXTURES, states);
|
2014-04-18 20:24:55 -07:00
|
|
|
|
|
|
|
for (int i = 0; i < GS_MAX_TEXTURES; i++)
|
|
|
|
if (device->curSamplers[i] &&
|
2019-06-22 22:13:45 -07:00
|
|
|
device->curSamplers[i]->state != states[i])
|
2014-04-18 20:24:55 -07:00
|
|
|
device->curSamplers[i] = nullptr;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_load_default_samplerstate(gs_device_t *device, bool b_3d, int unit)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
/* TODO */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(device);
|
|
|
|
UNUSED_PARAMETER(b_3d);
|
|
|
|
UNUSED_PARAMETER(unit);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
gs_shader_t *device_get_vertex_shader(const gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return device->curVertexShader;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
gs_shader_t *device_get_pixel_shader(const gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return device->curPixelShader;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
gs_texture_t *device_get_render_target(const gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (device->curRenderTarget == &device->curSwapChain->target)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return device->curRenderTarget;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
gs_zstencil_t *device_get_zstencil_target(const gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (device->curZStencilBuffer == &device->curSwapChain->zs)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return device->curZStencilBuffer;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_set_render_target(gs_device_t *device, gs_texture_t *tex,
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_zstencil_t *zstencil)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2015-07-30 17:16:24 -07:00
|
|
|
if (device->curSwapChain) {
|
|
|
|
if (!tex)
|
|
|
|
tex = &device->curSwapChain->target;
|
|
|
|
if (!zstencil)
|
|
|
|
zstencil = &device->curSwapChain->zs;
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
if (device->curRenderTarget == tex &&
|
2013-09-30 19:37:13 -07:00
|
|
|
device->curZStencilBuffer == zstencil)
|
|
|
|
return;
|
|
|
|
|
2015-07-31 23:09:48 -07:00
|
|
|
if (tex && tex->type != GS_TEXTURE_2D) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_set_render_target (D3D11): "
|
2019-06-22 22:13:45 -07:00
|
|
|
"texture is not a 2D texture");
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
2015-07-31 23:09:48 -07:00
|
|
|
if (tex2d && !tex2d->renderTarget[0]) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_set_render_target (D3D11): "
|
2019-06-22 22:13:45 -07:00
|
|
|
"texture is not a render target");
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-27 06:55:26 -07:00
|
|
|
ID3D11RenderTargetView *rt = tex2d ? tex2d->renderTarget[0].Get()
|
|
|
|
: nullptr;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
device->curRenderTarget = tex2d;
|
|
|
|
device->curRenderSide = 0;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->curZStencilBuffer = zstencil;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->context->OMSetRenderTargets(
|
|
|
|
1, &rt, zstencil ? zstencil->view : nullptr);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_set_cube_render_target(gs_device_t *device, gs_texture_t *tex,
|
2019-06-22 22:13:45 -07:00
|
|
|
int side, gs_zstencil_t *zstencil)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2015-07-30 17:16:24 -07:00
|
|
|
if (device->curSwapChain) {
|
|
|
|
if (!tex) {
|
|
|
|
tex = &device->curSwapChain->target;
|
|
|
|
side = 0;
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2015-07-30 17:16:24 -07:00
|
|
|
if (!zstencil)
|
|
|
|
zstencil = &device->curSwapChain->zs;
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
if (device->curRenderTarget == tex && device->curRenderSide == side &&
|
2013-09-30 19:37:13 -07:00
|
|
|
device->curZStencilBuffer == zstencil)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (tex->type != GS_TEXTURE_CUBE) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_set_cube_render_target (D3D11): "
|
2019-06-22 22:13:45 -07:00
|
|
|
"texture is not a cube texture");
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (!tex2d->renderTarget[side]) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_set_cube_render_target (D3D11): "
|
2013-09-30 19:37:13 -07:00
|
|
|
"texture is not a render target");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ID3D11RenderTargetView *rt = tex2d->renderTarget[0];
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
device->curRenderTarget = tex2d;
|
|
|
|
device->curRenderSide = side;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->curZStencilBuffer = zstencil;
|
|
|
|
device->context->OMSetRenderTargets(1, &rt, zstencil->view);
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
inline void gs_device::CopyTex(ID3D11Texture2D *dst, uint32_t dst_x,
|
|
|
|
uint32_t dst_y, gs_texture_t *src,
|
|
|
|
uint32_t src_x, uint32_t src_y, uint32_t src_w,
|
|
|
|
uint32_t src_h)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (src->type != GS_TEXTURE_2D)
|
|
|
|
throw "Source texture must be a 2D texture";
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(src);
|
2014-04-09 11:04:58 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
if (dst_x == 0 && dst_y == 0 && src_x == 0 && src_y == 0 &&
|
2014-04-12 11:21:47 -07:00
|
|
|
src_w == 0 && src_h == 0) {
|
2014-04-09 11:04:58 -07:00
|
|
|
context->CopyResource(dst, tex2d->texture);
|
2014-04-12 11:21:47 -07:00
|
|
|
} else {
|
2014-04-09 11:04:58 -07:00
|
|
|
D3D11_BOX sbox;
|
|
|
|
|
|
|
|
sbox.left = src_x;
|
2014-04-12 11:21:47 -07:00
|
|
|
if (src_w > 0)
|
2014-04-09 11:04:58 -07:00
|
|
|
sbox.right = src_x + src_w;
|
|
|
|
else
|
|
|
|
sbox.right = tex2d->width - 1;
|
|
|
|
|
|
|
|
sbox.top = src_y;
|
2014-04-12 11:21:47 -07:00
|
|
|
if (src_h > 0)
|
2014-04-09 11:04:58 -07:00
|
|
|
sbox.bottom = src_y + src_h;
|
|
|
|
else
|
|
|
|
sbox.bottom = tex2d->height - 1;
|
|
|
|
|
|
|
|
sbox.front = 0;
|
|
|
|
sbox.back = 1;
|
|
|
|
|
2014-04-12 11:21:47 -07:00
|
|
|
context->CopySubresourceRegion(dst, 0, dst_x, dst_y, 0,
|
2019-06-22 22:13:45 -07:00
|
|
|
tex2d->texture, 0, &sbox);
|
2014-04-09 11:04:58 -07:00
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
void device_copy_texture_region(gs_device_t *device, gs_texture_t *dst,
|
|
|
|
uint32_t dst_x, uint32_t dst_y,
|
|
|
|
gs_texture_t *src, uint32_t src_x,
|
|
|
|
uint32_t src_y, uint32_t src_w, uint32_t src_h)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2014-04-12 11:21:47 -07:00
|
|
|
try {
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *src2d = static_cast<gs_texture_2d *>(src);
|
|
|
|
gs_texture_2d *dst2d = static_cast<gs_texture_2d *>(dst);
|
2013-10-16 23:31:18 -07:00
|
|
|
|
2014-04-12 11:21:47 -07:00
|
|
|
if (!src)
|
2013-10-16 23:31:18 -07:00
|
|
|
throw "Source texture is NULL";
|
2014-04-12 11:21:47 -07:00
|
|
|
if (!dst)
|
2013-10-16 23:31:18 -07:00
|
|
|
throw "Destination texture is NULL";
|
2014-04-12 11:21:47 -07:00
|
|
|
if (src->type != GS_TEXTURE_2D || dst->type != GS_TEXTURE_2D)
|
2013-10-16 23:31:18 -07:00
|
|
|
throw "Source and destination textures must be a 2D "
|
2014-04-12 11:21:47 -07:00
|
|
|
"textures";
|
|
|
|
if (dst->format != src->format)
|
2013-10-16 23:31:18 -07:00
|
|
|
throw "Source and destination formats do not match";
|
2014-04-09 11:04:58 -07:00
|
|
|
|
2014-04-12 11:21:47 -07:00
|
|
|
/* apparently casting to the same type that the variable
|
|
|
|
* already exists as is supposed to prevent some warning
|
|
|
|
* when used with the conditional operator? */
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t copyWidth = (uint32_t)src_w ? (uint32_t)src_w
|
|
|
|
: (src2d->width - src_x);
|
|
|
|
uint32_t copyHeight = (uint32_t)src_h ? (uint32_t)src_h
|
|
|
|
: (src2d->height - src_y);
|
2014-04-09 11:04:58 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t dstWidth = dst2d->width - dst_x;
|
2014-04-12 11:21:47 -07:00
|
|
|
uint32_t dstHeight = dst2d->height - dst_y;
|
|
|
|
|
|
|
|
if (dstWidth < copyWidth || dstHeight < copyHeight)
|
2014-04-09 11:04:58 -07:00
|
|
|
throw "Destination texture region is not big "
|
|
|
|
"enough to hold the source region";
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
if (dst_x == 0 && dst_y == 0 && src_x == 0 && src_y == 0 &&
|
2014-04-12 11:21:47 -07:00
|
|
|
src_w == 0 && src_h == 0) {
|
2019-06-22 22:13:45 -07:00
|
|
|
copyWidth = 0;
|
2014-04-12 11:21:47 -07:00
|
|
|
copyHeight = 0;
|
2014-04-09 11:04:58 -07:00
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
device->CopyTex(dst2d->texture, dst_x, dst_y, src, src_x, src_y,
|
|
|
|
copyWidth, copyHeight);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
} catch (const char *error) {
|
2013-09-30 19:37:13 -07:00
|
|
|
blog(LOG_ERROR, "device_copy_texture (D3D11): %s", error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_copy_texture(gs_device_t *device, gs_texture_t *dst,
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_t *src)
|
2014-04-09 11:04:58 -07:00
|
|
|
{
|
|
|
|
device_copy_texture_region(device, dst, 0, 0, src, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_stage_texture(gs_device_t *device, gs_stagesurf_t *dst,
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_t *src)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
try {
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *src2d = static_cast<gs_texture_2d *>(src);
|
2013-10-16 23:31:18 -07:00
|
|
|
|
|
|
|
if (!src)
|
|
|
|
throw "Source texture is NULL";
|
|
|
|
if (src->type != GS_TEXTURE_2D)
|
|
|
|
throw "Source texture must be a 2D texture";
|
2013-09-30 19:37:13 -07:00
|
|
|
if (!dst)
|
2013-10-16 23:31:18 -07:00
|
|
|
throw "Destination surface is NULL";
|
2018-10-05 03:15:13 -07:00
|
|
|
if (dst->format != GS_UNKNOWN && dst->format != src->format)
|
2013-10-16 23:31:18 -07:00
|
|
|
throw "Source and destination formats do not match";
|
2019-06-22 22:13:45 -07:00
|
|
|
if (dst->width != src2d->width || dst->height != src2d->height)
|
2013-10-16 23:31:18 -07:00
|
|
|
throw "Source and destination must have the same "
|
|
|
|
"dimensions";
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2014-04-09 11:04:58 -07:00
|
|
|
device->CopyTex(dst->texture, 0, 0, src, 0, 0, 0, 0);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
} catch (const char *error) {
|
|
|
|
blog(LOG_ERROR, "device_copy_texture (D3D11): %s", error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 21:06:01 -07:00
|
|
|
extern "C" void reset_duplicators(void);
|
|
|
|
|
|
|
|
void device_begin_frame(gs_device_t *device)
|
|
|
|
{
|
|
|
|
/* does nothing in D3D11 */
|
|
|
|
UNUSED_PARAMETER(device);
|
|
|
|
|
|
|
|
reset_duplicators();
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_begin_scene(gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
clear_textures(device);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_draw(gs_device_t *device, enum gs_draw_mode draw_mode,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t start_vert, uint32_t num_verts)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
if (!device->curVertexShader)
|
|
|
|
throw "No vertex shader specified";
|
|
|
|
|
|
|
|
if (!device->curPixelShader)
|
|
|
|
throw "No pixel shader specified";
|
|
|
|
|
2019-06-02 06:49:38 -07:00
|
|
|
if (!device->curVertexBuffer && (num_verts == 0))
|
2013-09-30 19:37:13 -07:00
|
|
|
throw "No vertex buffer specified";
|
|
|
|
|
2015-07-30 17:16:24 -07:00
|
|
|
if (!device->curSwapChain && !device->curRenderTarget)
|
|
|
|
throw "No render target or swap chain to render to";
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
gs_effect_t *effect = gs_get_effect();
|
2013-09-30 19:37:13 -07:00
|
|
|
if (effect)
|
2014-08-07 23:42:07 -07:00
|
|
|
gs_effect_update_params(effect);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2017-05-15 23:35:50 -07:00
|
|
|
device->LoadVertexBufferData();
|
2013-09-30 19:37:13 -07:00
|
|
|
device->UpdateBlendState();
|
|
|
|
device->UpdateRasterState();
|
|
|
|
device->UpdateZStencilState();
|
|
|
|
device->UpdateViewProjMatrix();
|
|
|
|
device->curVertexShader->UploadParams();
|
|
|
|
device->curPixelShader->UploadParams();
|
|
|
|
|
|
|
|
} catch (const char *error) {
|
|
|
|
blog(LOG_ERROR, "device_draw (D3D11): %s", error);
|
|
|
|
return;
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2013-09-30 19:37:13 -07:00
|
|
|
blog(LOG_ERROR, "device_draw (D3D11): %s (%08lX)", error.str,
|
2019-06-22 22:13:45 -07:00
|
|
|
error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-10 05:31:55 -08:00
|
|
|
D3D11_PRIMITIVE_TOPOLOGY newTopology = ConvertGSTopology(draw_mode);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (device->curToplogy != newTopology) {
|
|
|
|
device->context->IASetPrimitiveTopology(newTopology);
|
|
|
|
device->curToplogy = newTopology;
|
|
|
|
}
|
|
|
|
|
2013-10-16 23:31:18 -07:00
|
|
|
if (device->curIndexBuffer) {
|
|
|
|
if (num_verts == 0)
|
|
|
|
num_verts = (uint32_t)device->curIndexBuffer->num;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->context->DrawIndexed(num_verts, start_vert, 0);
|
2013-10-16 23:31:18 -07:00
|
|
|
} else {
|
|
|
|
if (num_verts == 0)
|
|
|
|
num_verts = (uint32_t)device->curVertexBuffer->numVerts;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->context->Draw(num_verts, start_vert);
|
2013-10-16 23:31:18 -07:00
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_end_scene(gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
/* does nothing in D3D11 */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(device);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swapchain)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_t *target = device->curRenderTarget;
|
|
|
|
gs_zstencil_t *zs = device->curZStencilBuffer;
|
|
|
|
bool is_cube =
|
|
|
|
device->curRenderTarget
|
|
|
|
? (device->curRenderTarget->type == GS_TEXTURE_CUBE)
|
|
|
|
: false;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2015-07-31 23:09:48 -07:00
|
|
|
if (device->curSwapChain) {
|
|
|
|
if (target == &device->curSwapChain->target)
|
|
|
|
target = NULL;
|
|
|
|
if (zs == &device->curSwapChain->zs)
|
|
|
|
zs = NULL;
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
device->curSwapChain = swapchain;
|
|
|
|
|
|
|
|
if (is_cube)
|
2014-08-07 23:42:07 -07:00
|
|
|
device_set_cube_render_target(device, target,
|
2019-06-22 22:13:45 -07:00
|
|
|
device->curRenderSide, zs);
|
2013-09-30 19:37:13 -07:00
|
|
|
else
|
2014-08-07 23:42:07 -07:00
|
|
|
device_set_render_target(device, target, zs);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
void device_clear(gs_device_t *device, uint32_t clear_flags,
|
2019-06-22 22:13:45 -07:00
|
|
|
const struct vec4 *color, float depth, uint8_t stencil)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
int side = device->curRenderSide;
|
|
|
|
if ((clear_flags & GS_CLEAR_COLOR) != 0 && device->curRenderTarget)
|
|
|
|
device->context->ClearRenderTargetView(
|
2019-06-22 22:13:45 -07:00
|
|
|
device->curRenderTarget->renderTarget[side],
|
|
|
|
color->ptr);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
if (device->curZStencilBuffer) {
|
|
|
|
uint32_t flags = 0;
|
|
|
|
if ((clear_flags & GS_CLEAR_DEPTH) != 0)
|
|
|
|
flags |= D3D11_CLEAR_DEPTH;
|
|
|
|
if ((clear_flags & GS_CLEAR_STENCIL) != 0)
|
|
|
|
flags |= D3D11_CLEAR_STENCIL;
|
|
|
|
|
|
|
|
if (flags && device->curZStencilBuffer->view)
|
|
|
|
device->context->ClearDepthStencilView(
|
2019-06-22 22:13:45 -07:00
|
|
|
device->curZStencilBuffer->view, flags, depth,
|
|
|
|
stencil);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_present(gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
libobs-d3d11: Rebuild device and assets if device removed/reset
Due to an NVIDIA driver bug with the Windows 10 Anniversary Update,
there are an increasingly large number of reports of "Device Removed"
errors and TDRs. When this happens, OBS stops outputting all data
because all graphics functions are failing, and it appears to just
"freeze up" for users.
To temporarily alleviate this issue while waiting for it to be fixed,
the D3D subsystem can be rebuilt when that happens, all assets can be
reloaded to ensure that it can continue functioning (with a minor hiccup
in playback).
To allow rebuilding the entire D3D subsystem, all objects that contain
D3D references must be part of a linked list (with a few exceptions) so
we can quickly traverse them all whenever needed, and all data for those
resources (static resources primarily, such as shaders, textures, index
buffers, vertex buffers) must be stored in RAM so they can be recreated
whenever needed.
Then if D3D reports a "device removed" or "device reset" error, all D3D
references must first be fully released with no stray references; the
linked list must be fully traversed until all references are released.
Then, the linked list must once again be traversed again, and all those
D3D objects must be recreated with the same data and descriptors (which
are now saved in each object). Finally, all states need to be reset.
After that's complete, the device is able to continue functioning almost
as it was before, although the output to recording/stream may get a few
green frames due to texture data being reset.
This will temporarily alleviate the "Device Removed" issue while waiting
for a fix from NVIDIA.
2016-11-03 07:41:23 -07:00
|
|
|
HRESULT hr;
|
|
|
|
|
2015-07-30 17:16:24 -07:00
|
|
|
if (device->curSwapChain) {
|
libobs-d3d11: Rebuild device and assets if device removed/reset
Due to an NVIDIA driver bug with the Windows 10 Anniversary Update,
there are an increasingly large number of reports of "Device Removed"
errors and TDRs. When this happens, OBS stops outputting all data
because all graphics functions are failing, and it appears to just
"freeze up" for users.
To temporarily alleviate this issue while waiting for it to be fixed,
the D3D subsystem can be rebuilt when that happens, all assets can be
reloaded to ensure that it can continue functioning (with a minor hiccup
in playback).
To allow rebuilding the entire D3D subsystem, all objects that contain
D3D references must be part of a linked list (with a few exceptions) so
we can quickly traverse them all whenever needed, and all data for those
resources (static resources primarily, such as shaders, textures, index
buffers, vertex buffers) must be stored in RAM so they can be recreated
whenever needed.
Then if D3D reports a "device removed" or "device reset" error, all D3D
references must first be fully released with no stray references; the
linked list must be fully traversed until all references are released.
Then, the linked list must once again be traversed again, and all those
D3D objects must be recreated with the same data and descriptors (which
are now saved in each object). Finally, all states need to be reset.
After that's complete, the device is able to continue functioning almost
as it was before, although the output to recording/stream may get a few
green frames due to texture data being reset.
This will temporarily alleviate the "Device Removed" issue while waiting
for a fix from NVIDIA.
2016-11-03 07:41:23 -07:00
|
|
|
hr = device->curSwapChain->swap->Present(0, 0);
|
|
|
|
if (hr == DXGI_ERROR_DEVICE_REMOVED ||
|
|
|
|
hr == DXGI_ERROR_DEVICE_RESET) {
|
|
|
|
device->RebuildDevice();
|
|
|
|
}
|
2015-07-30 17:16:24 -07:00
|
|
|
} else {
|
|
|
|
blog(LOG_WARNING, "device_present (D3D11): No active swap");
|
|
|
|
}
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_flush(gs_device_t *device)
|
2014-06-25 19:32:34 -07:00
|
|
|
{
|
|
|
|
device->context->Flush();
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_set_cull_mode(gs_device_t *device, enum gs_cull_mode mode)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (mode == device->rasterState.cullMode)
|
|
|
|
return;
|
|
|
|
|
|
|
|
device->rasterState.cullMode = mode;
|
|
|
|
device->rasterStateChanged = true;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
enum gs_cull_mode device_get_cull_mode(const gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return device->rasterState.cullMode;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_enable_blending(gs_device_t *device, bool enable)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (enable == device->blendState.blendEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
device->blendState.blendEnabled = enable;
|
|
|
|
device->blendStateChanged = true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_enable_depth_test(gs_device_t *device, bool enable)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (enable == device->zstencilState.depthEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
device->zstencilState.depthEnabled = enable;
|
|
|
|
device->zstencilStateChanged = true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_enable_stencil_test(gs_device_t *device, bool enable)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (enable == device->zstencilState.stencilEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
device->zstencilState.stencilEnabled = enable;
|
|
|
|
device->zstencilStateChanged = true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_enable_stencil_write(gs_device_t *device, bool enable)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (enable == device->zstencilState.stencilWriteEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
device->zstencilState.stencilWriteEnabled = enable;
|
|
|
|
device->zstencilStateChanged = true;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
void device_enable_color(gs_device_t *device, bool red, bool green, bool blue,
|
|
|
|
bool alpha)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
if (device->blendState.redEnabled == red &&
|
2013-09-30 19:37:13 -07:00
|
|
|
device->blendState.greenEnabled == green &&
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.blueEnabled == blue &&
|
2013-09-30 19:37:13 -07:00
|
|
|
device->blendState.alphaEnabled == alpha)
|
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.redEnabled = red;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->blendState.greenEnabled = green;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.blueEnabled = blue;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->blendState.alphaEnabled = alpha;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendStateChanged = true;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_blend_function(gs_device_t *device, enum gs_blend_type src,
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_blend_type dest)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
if (device->blendState.srcFactorC == src &&
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.destFactorC == dest &&
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.srcFactorA == src &&
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.destFactorA == dest)
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.srcFactorC = src;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.destFactorC = dest;
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.srcFactorA = src;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.destFactorA = dest;
|
|
|
|
device->blendStateChanged = true;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2015-03-27 11:18:02 -07:00
|
|
|
void device_blend_function_separate(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_blend_type src_c,
|
|
|
|
enum gs_blend_type dest_c,
|
|
|
|
enum gs_blend_type src_a,
|
|
|
|
enum gs_blend_type dest_a)
|
2015-03-27 11:18:02 -07:00
|
|
|
{
|
2019-06-22 22:13:45 -07:00
|
|
|
if (device->blendState.srcFactorC == src_c &&
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.destFactorC == dest_c &&
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.srcFactorA == src_a &&
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.destFactorA == dest_a)
|
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.srcFactorC = src_c;
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.destFactorC = dest_c;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendState.srcFactorA = src_a;
|
2015-03-27 11:18:02 -07:00
|
|
|
device->blendState.destFactorA = dest_a;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->blendStateChanged = true;
|
2015-03-27 11:18:02 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_depth_function(gs_device_t *device, enum gs_depth_test test)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (device->zstencilState.depthFunc == test)
|
|
|
|
return;
|
|
|
|
|
|
|
|
device->zstencilState.depthFunc = test;
|
2019-06-22 22:13:45 -07:00
|
|
|
device->zstencilStateChanged = true;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
static inline void update_stencilside_test(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
StencilSide &side,
|
|
|
|
gs_depth_test test)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (side.test == test)
|
|
|
|
return;
|
|
|
|
|
|
|
|
side.test = test;
|
|
|
|
device->zstencilStateChanged = true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_stencil_function(gs_device_t *device, enum gs_stencil_side side,
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_depth_test test)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
int sideVal = (int)side;
|
|
|
|
|
|
|
|
if (sideVal & GS_STENCIL_FRONT)
|
2019-06-22 22:13:45 -07:00
|
|
|
update_stencilside_test(
|
|
|
|
device, device->zstencilState.stencilFront, test);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (sideVal & GS_STENCIL_BACK)
|
2019-06-22 22:13:45 -07:00
|
|
|
update_stencilside_test(
|
|
|
|
device, device->zstencilState.stencilBack, test);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
static inline void update_stencilside_op(gs_device_t *device, StencilSide &side,
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_stencil_op_type fail,
|
|
|
|
enum gs_stencil_op_type zfail,
|
|
|
|
enum gs_stencil_op_type zpass)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (side.fail == fail && side.zfail == zfail && side.zpass == zpass)
|
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
side.fail = fail;
|
2013-09-30 19:37:13 -07:00
|
|
|
side.zfail = zfail;
|
|
|
|
side.zpass = zpass;
|
|
|
|
device->zstencilStateChanged = true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_stencil_op(gs_device_t *device, enum gs_stencil_side side,
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_stencil_op_type fail,
|
|
|
|
enum gs_stencil_op_type zfail,
|
|
|
|
enum gs_stencil_op_type zpass)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
int sideVal = (int)side;
|
|
|
|
|
|
|
|
if (sideVal & GS_STENCIL_FRONT)
|
|
|
|
update_stencilside_op(device,
|
2019-06-22 22:13:45 -07:00
|
|
|
device->zstencilState.stencilFront, fail,
|
|
|
|
zfail, zpass);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (sideVal & GS_STENCIL_BACK)
|
2019-06-22 22:13:45 -07:00
|
|
|
update_stencilside_op(device, device->zstencilState.stencilBack,
|
|
|
|
fail, zfail, zpass);
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_set_viewport(gs_device_t *device, int x, int y, int width,
|
2019-06-22 22:13:45 -07:00
|
|
|
int height)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
D3D11_VIEWPORT vp;
|
|
|
|
memset(&vp, 0, sizeof(vp));
|
|
|
|
vp.MaxDepth = 1.0f;
|
|
|
|
vp.TopLeftX = (float)x;
|
|
|
|
vp.TopLeftY = (float)y;
|
2019-06-22 22:13:45 -07:00
|
|
|
vp.Width = (float)width;
|
|
|
|
vp.Height = (float)height;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->context->RSSetViewports(1, &vp);
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
device->viewport.x = x;
|
|
|
|
device->viewport.y = y;
|
2013-09-30 19:37:13 -07:00
|
|
|
device->viewport.cx = width;
|
|
|
|
device->viewport.cy = height;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
void device_get_viewport(const gs_device_t *device, struct gs_rect *rect)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
memcpy(rect, &device->viewport, sizeof(gs_rect));
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
void device_set_scissor_rect(gs_device_t *device, const struct gs_rect *rect)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
D3D11_RECT d3drect;
|
2014-05-01 11:26:17 -07:00
|
|
|
|
|
|
|
device->rasterState.scissorEnabled = (rect != NULL);
|
|
|
|
|
|
|
|
if (rect != NULL) {
|
2019-06-22 22:13:45 -07:00
|
|
|
d3drect.left = rect->x;
|
|
|
|
d3drect.top = rect->y;
|
|
|
|
d3drect.right = rect->x + rect->cx;
|
2014-05-01 11:26:17 -07:00
|
|
|
d3drect.bottom = rect->y + rect->cy;
|
|
|
|
device->context->RSSetScissorRects(1, &d3drect);
|
|
|
|
}
|
2014-05-03 09:08:49 -07:00
|
|
|
|
|
|
|
device->rasterStateChanged = true;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_ortho(gs_device_t *device, float left, float right, float top,
|
2019-06-22 22:13:45 -07:00
|
|
|
float bottom, float zNear, float zFar)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2013-10-16 23:31:18 -07:00
|
|
|
matrix4 *dst = &device->curProjMatrix;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
float rml = right - left;
|
|
|
|
float bmt = bottom - top;
|
|
|
|
float fmn = zFar - zNear;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
|
|
|
vec4_zero(&dst->x);
|
|
|
|
vec4_zero(&dst->y);
|
|
|
|
vec4_zero(&dst->z);
|
|
|
|
vec4_zero(&dst->t);
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
dst->x.x = 2.0f / rml;
|
|
|
|
dst->t.x = (left + right) / -rml;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
dst->y.y = 2.0f / -bmt;
|
|
|
|
dst->t.y = (bottom + top) / bmt;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
dst->z.z = 1.0f / fmn;
|
|
|
|
dst->t.z = zNear / -fmn;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
|
|
|
dst->t.w = 1.0f;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_frustum(gs_device_t *device, float left, float right, float top,
|
2019-06-22 22:13:45 -07:00
|
|
|
float bottom, float zNear, float zFar)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2013-10-16 23:31:18 -07:00
|
|
|
matrix4 *dst = &device->curProjMatrix;
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
float rml = right - left;
|
|
|
|
float bmt = bottom - top;
|
|
|
|
float fmn = zFar - zNear;
|
|
|
|
float nearx2 = 2.0f * zNear;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
|
|
|
vec4_zero(&dst->x);
|
|
|
|
vec4_zero(&dst->y);
|
|
|
|
vec4_zero(&dst->z);
|
|
|
|
vec4_zero(&dst->t);
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
dst->x.x = nearx2 / rml;
|
|
|
|
dst->z.x = (left + right) / -rml;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
dst->y.y = nearx2 / -bmt;
|
|
|
|
dst->z.y = (bottom + top) / bmt;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
dst->z.z = zFar / fmn;
|
|
|
|
dst->t.z = (zNear * zFar) / -fmn;
|
2013-10-16 23:31:18 -07:00
|
|
|
|
|
|
|
dst->z.w = 1.0f;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_projection_push(gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
mat4float mat;
|
|
|
|
memcpy(&mat, &device->curProjMatrix, sizeof(matrix4));
|
|
|
|
device->projStack.push_back(mat);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void device_projection_pop(gs_device_t *device)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2019-06-08 09:52:20 -07:00
|
|
|
if (device->projStack.empty())
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
|
2019-06-08 09:52:20 -07:00
|
|
|
const mat4float &mat = device->projStack.back();
|
|
|
|
memcpy(&device->curProjMatrix, &mat, sizeof(matrix4));
|
2013-09-30 19:37:13 -07:00
|
|
|
device->projStack.pop_back();
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_swapchain_destroy(gs_swapchain_t *swapchain)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2015-07-31 23:09:48 -07:00
|
|
|
if (swapchain->device->curSwapChain == swapchain)
|
|
|
|
device_load_swapchain(swapchain->device, nullptr);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
delete swapchain;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_texture_destroy(gs_texture_t *tex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
delete tex;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t gs_texture_get_width(const gs_texture_t *tex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return 0;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
return static_cast<const gs_texture_2d *>(tex)->width;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t gs_texture_get_height(const gs_texture_t *tex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return 0;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
return static_cast<const gs_texture_2d *>(tex)->height;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
enum gs_color_format gs_texture_get_color_format(const gs_texture_t *tex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return GS_UNKNOWN;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
return static_cast<const gs_texture_2d *>(tex)->format;
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr, uint32_t *linesize)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return false;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
D3D11_MAPPED_SUBRESOURCE map;
|
|
|
|
hr = tex2d->device->context->Map(tex2d->texture, 0,
|
2019-06-22 22:13:45 -07:00
|
|
|
D3D11_MAP_WRITE_DISCARD, 0, &map);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (FAILED(hr))
|
|
|
|
return false;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
*ptr = (uint8_t *)map.pData;
|
2014-02-09 04:51:06 -08:00
|
|
|
*linesize = map.RowPitch;
|
2013-09-30 19:37:13 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_texture_unmap(gs_texture_t *tex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
2013-09-30 19:37:13 -07:00
|
|
|
tex2d->device->context->Unmap(tex2d->texture, 0);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void *gs_texture_get_obj(gs_texture_t *tex)
|
2014-03-29 17:19:31 -07:00
|
|
|
{
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return nullptr;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
2014-03-29 17:19:31 -07:00
|
|
|
return tex2d->texture.Get();
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_cubetexture_destroy(gs_texture_t *cubetex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
delete cubetex;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t gs_cubetexture_get_size(const gs_texture_t *cubetex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (cubetex->type != GS_TEXTURE_CUBE)
|
|
|
|
return 0;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
const gs_texture_2d *tex = static_cast<const gs_texture_2d *>(cubetex);
|
2013-09-30 19:37:13 -07:00
|
|
|
return tex->width;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_color_format
|
|
|
|
gs_cubetexture_get_color_format(const gs_texture_t *cubetex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
if (cubetex->type != GS_TEXTURE_CUBE)
|
|
|
|
return GS_UNKNOWN;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
const gs_texture_2d *tex = static_cast<const gs_texture_2d *>(cubetex);
|
2013-09-30 19:37:13 -07:00
|
|
|
return tex->format;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_voltexture_destroy(gs_texture_t *voltex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
delete voltex;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t gs_voltexture_get_width(const gs_texture_t *voltex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
/* TODO */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(voltex);
|
2013-09-30 19:37:13 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t gs_voltexture_get_height(const gs_texture_t *voltex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
/* TODO */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(voltex);
|
2013-09-30 19:37:13 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-21 07:43:02 -07:00
|
|
|
uint32_t gs_voltexture_get_depth(const gs_texture_t *voltex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
/* TODO */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(voltex);
|
2013-09-30 19:37:13 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
enum gs_color_format gs_voltexture_get_color_format(const gs_texture_t *voltex)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
/* TODO */
|
2014-06-25 01:32:11 -07:00
|
|
|
UNUSED_PARAMETER(voltex);
|
2013-09-30 19:37:13 -07:00
|
|
|
return GS_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
delete stagesurf;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t gs_stagesurface_get_width(const gs_stagesurf_t *stagesurf)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return stagesurf->width;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
uint32_t gs_stagesurface_get_height(const gs_stagesurf_t *stagesurf)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return stagesurf->height;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
enum gs_color_format
|
|
|
|
gs_stagesurface_get_color_format(const gs_stagesurf_t *stagesurf)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return stagesurf->format;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
bool gs_stagesurface_map(gs_stagesurf_t *stagesurf, uint8_t **data,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t *linesize)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
D3D11_MAPPED_SUBRESOURCE map;
|
|
|
|
if (FAILED(stagesurf->device->context->Map(stagesurf->texture, 0,
|
2019-06-22 22:13:45 -07:00
|
|
|
D3D11_MAP_READ, 0, &map)))
|
2013-09-30 19:37:13 -07:00
|
|
|
return false;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
*data = (uint8_t *)map.pData;
|
2014-02-09 04:51:06 -08:00
|
|
|
*linesize = map.RowPitch;
|
2013-09-30 19:37:13 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
stagesurf->device->context->Unmap(stagesurf->texture, 0);
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_zstencil_destroy(gs_zstencil_t *zstencil)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
delete zstencil;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_samplerstate_destroy(gs_samplerstate_t *samplerstate)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2014-04-18 20:21:00 -07:00
|
|
|
if (!samplerstate)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (samplerstate->device)
|
|
|
|
for (int i = 0; i < GS_MAX_TEXTURES; i++)
|
|
|
|
if (samplerstate->device->curSamplers[i] ==
|
2019-06-22 22:13:45 -07:00
|
|
|
samplerstate)
|
2014-04-18 20:21:00 -07:00
|
|
|
samplerstate->device->curSamplers[i] = nullptr;
|
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
delete samplerstate;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_vertexbuffer_destroy(gs_vertbuffer_t *vertbuffer)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2017-05-15 23:35:50 -07:00
|
|
|
if (vertbuffer && vertbuffer->device->lastVertexBuffer == vertbuffer)
|
|
|
|
vertbuffer->device->lastVertexBuffer = nullptr;
|
2013-09-30 19:37:13 -07:00
|
|
|
delete vertbuffer;
|
|
|
|
}
|
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
static inline void gs_vertexbuffer_flush_internal(gs_vertbuffer_t *vertbuffer,
|
2019-06-22 22:13:45 -07:00
|
|
|
const gs_vb_data *data)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
2017-11-27 02:19:48 -08:00
|
|
|
size_t num_tex = data->num_tex < vertbuffer->uvBuffers.size()
|
2019-06-22 22:13:45 -07:00
|
|
|
? data->num_tex
|
|
|
|
: vertbuffer->uvBuffers.size();
|
2017-11-27 02:19:48 -08:00
|
|
|
|
2013-09-30 19:37:13 -07:00
|
|
|
if (!vertbuffer->dynamic) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "gs_vertexbuffer_flush: vertex buffer is "
|
2019-06-22 22:13:45 -07:00
|
|
|
"not dynamic");
|
2013-09-30 19:37:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
if (data->points)
|
2019-06-22 22:13:45 -07:00
|
|
|
vertbuffer->FlushBuffer(vertbuffer->vertexBuffer, data->points,
|
|
|
|
sizeof(vec3));
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
if (vertbuffer->normalBuffer && data->normals)
|
2019-06-22 22:13:45 -07:00
|
|
|
vertbuffer->FlushBuffer(vertbuffer->normalBuffer, data->normals,
|
|
|
|
sizeof(vec3));
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
if (vertbuffer->tangentBuffer && data->tangents)
|
2013-09-30 19:37:13 -07:00
|
|
|
vertbuffer->FlushBuffer(vertbuffer->tangentBuffer,
|
2019-06-22 22:13:45 -07:00
|
|
|
data->tangents, sizeof(vec3));
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
if (vertbuffer->colorBuffer && data->colors)
|
2019-06-22 22:13:45 -07:00
|
|
|
vertbuffer->FlushBuffer(vertbuffer->colorBuffer, data->colors,
|
|
|
|
sizeof(uint32_t));
|
2013-09-30 19:37:13 -07:00
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
for (size_t i = 0; i < num_tex; i++) {
|
|
|
|
gs_tvertarray &tv = data->tvarray[i];
|
2019-06-22 22:13:45 -07:00
|
|
|
vertbuffer->FlushBuffer(vertbuffer->uvBuffers[i], tv.array,
|
|
|
|
tv.width * sizeof(float));
|
2013-09-30 19:37:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
void gs_vertexbuffer_flush(gs_vertbuffer_t *vertbuffer)
|
|
|
|
{
|
|
|
|
gs_vertexbuffer_flush_internal(vertbuffer, vertbuffer->vbd.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vertbuffer,
|
2019-06-22 22:13:45 -07:00
|
|
|
const gs_vb_data *data)
|
2017-11-27 02:19:48 -08:00
|
|
|
{
|
|
|
|
gs_vertexbuffer_flush_internal(vertbuffer, data);
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
struct gs_vb_data *gs_vertexbuffer_get_data(const gs_vertbuffer_t *vertbuffer)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return vertbuffer->vbd.data;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
void gs_indexbuffer_destroy(gs_indexbuffer_t *indexbuffer)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
delete indexbuffer;
|
|
|
|
}
|
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
static inline void gs_indexbuffer_flush_internal(gs_indexbuffer_t *indexbuffer,
|
2019-06-22 22:13:45 -07:00
|
|
|
const void *data)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (!indexbuffer->dynamic)
|
|
|
|
return;
|
|
|
|
|
|
|
|
D3D11_MAPPED_SUBRESOURCE map;
|
2019-06-22 22:13:45 -07:00
|
|
|
hr = indexbuffer->device->context->Map(
|
|
|
|
indexbuffer->indexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
|
2013-09-30 19:37:13 -07:00
|
|
|
if (FAILED(hr))
|
|
|
|
return;
|
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
memcpy(map.pData, data, indexbuffer->num * indexbuffer->indexSize);
|
2013-09-30 19:37:13 -07:00
|
|
|
|
|
|
|
indexbuffer->device->context->Unmap(indexbuffer->indexBuffer, 0);
|
|
|
|
}
|
|
|
|
|
2017-11-27 02:19:48 -08:00
|
|
|
void gs_indexbuffer_flush(gs_indexbuffer_t *indexbuffer)
|
|
|
|
{
|
|
|
|
gs_indexbuffer_flush_internal(indexbuffer, indexbuffer->indices.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_indexbuffer_flush_direct(gs_indexbuffer_t *indexbuffer,
|
2019-06-22 22:13:45 -07:00
|
|
|
const void *data)
|
2017-11-27 02:19:48 -08:00
|
|
|
{
|
|
|
|
gs_indexbuffer_flush_internal(indexbuffer, data);
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
void *gs_indexbuffer_get_data(const gs_indexbuffer_t *indexbuffer)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return indexbuffer->indices.data;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
size_t gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *indexbuffer)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return indexbuffer->num;
|
|
|
|
}
|
|
|
|
|
2014-09-26 15:25:59 -07:00
|
|
|
enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer)
|
2013-09-30 19:37:13 -07:00
|
|
|
{
|
|
|
|
return indexbuffer->type;
|
|
|
|
}
|
2014-03-05 09:43:14 -08:00
|
|
|
|
2019-07-27 13:31:07 -07:00
|
|
|
void gs_timer_destroy(gs_timer_t *timer)
|
|
|
|
{
|
|
|
|
delete timer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_timer_begin(gs_timer_t *timer)
|
|
|
|
{
|
|
|
|
timer->device->context->End(timer->query_begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_timer_end(gs_timer_t *timer)
|
|
|
|
{
|
|
|
|
timer->device->context->End(timer->query_end);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks)
|
|
|
|
{
|
|
|
|
uint64_t begin, end;
|
|
|
|
HRESULT hr_begin, hr_end;
|
|
|
|
do {
|
|
|
|
hr_begin = timer->device->context->GetData(
|
|
|
|
timer->query_begin, &begin, sizeof(begin), 0);
|
|
|
|
} while (hr_begin == S_FALSE);
|
|
|
|
do {
|
|
|
|
hr_end = timer->device->context->GetData(timer->query_end, &end,
|
|
|
|
sizeof(end), 0);
|
|
|
|
} while (hr_end == S_FALSE);
|
|
|
|
|
|
|
|
const bool succeeded = SUCCEEDED(hr_begin) && SUCCEEDED(hr_end);
|
|
|
|
if (succeeded)
|
|
|
|
*ticks = end - begin;
|
|
|
|
|
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_timer_range_destroy(gs_timer_range_t *range)
|
|
|
|
{
|
|
|
|
delete range;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_timer_range_begin(gs_timer_range_t *range)
|
|
|
|
{
|
|
|
|
range->device->context->Begin(range->query_disjoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gs_timer_range_end(gs_timer_range_t *range)
|
|
|
|
{
|
|
|
|
range->device->context->End(range->query_disjoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
|
|
|
|
uint64_t *frequency)
|
|
|
|
{
|
|
|
|
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timestamp_disjoint;
|
|
|
|
HRESULT hr;
|
|
|
|
do {
|
|
|
|
hr = range->device->context->GetData(range->query_disjoint,
|
|
|
|
×tamp_disjoint,
|
|
|
|
sizeof(timestamp_disjoint),
|
|
|
|
0);
|
|
|
|
} while (hr == S_FALSE);
|
|
|
|
|
|
|
|
const bool succeeded = SUCCEEDED(hr);
|
|
|
|
if (succeeded) {
|
|
|
|
*disjoint = timestamp_disjoint.Disjoint;
|
|
|
|
*frequency = timestamp_disjoint.Frequency;
|
|
|
|
}
|
|
|
|
|
|
|
|
return succeeded;
|
|
|
|
}
|
|
|
|
|
|
|
|
gs_timer::gs_timer(gs_device_t *device) : gs_obj(device, gs_type::gs_timer)
|
|
|
|
{
|
|
|
|
Rebuild(device->device);
|
|
|
|
}
|
|
|
|
|
|
|
|
gs_timer_range::gs_timer_range(gs_device_t *device)
|
|
|
|
: gs_obj(device, gs_type::gs_timer_range)
|
|
|
|
{
|
|
|
|
Rebuild(device->device);
|
|
|
|
}
|
|
|
|
|
2014-08-07 23:42:07 -07:00
|
|
|
extern "C" EXPORT bool device_gdi_texture_available(void)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-10-13 21:41:09 -07:00
|
|
|
extern "C" EXPORT bool device_shared_texture_available(void)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-10-05 03:15:13 -07:00
|
|
|
extern "C" EXPORT bool device_nv12_available(gs_device_t *device)
|
|
|
|
{
|
|
|
|
return device->nv12Supported;
|
|
|
|
}
|
|
|
|
|
2019-04-02 23:22:19 -07:00
|
|
|
extern "C" EXPORT void device_debug_marker_begin(gs_device_t *,
|
2019-06-22 22:13:45 -07:00
|
|
|
const char *markername,
|
|
|
|
const float color[4])
|
2019-04-02 23:22:19 -07:00
|
|
|
{
|
|
|
|
D3DCOLOR bgra = D3DCOLOR_ARGB((DWORD)(255.0f * color[3]),
|
2019-06-22 22:13:45 -07:00
|
|
|
(DWORD)(255.0f * color[0]),
|
|
|
|
(DWORD)(255.0f * color[1]),
|
|
|
|
(DWORD)(255.0f * color[2]));
|
2019-04-02 23:22:19 -07:00
|
|
|
|
|
|
|
wchar_t wide[64];
|
|
|
|
os_utf8_to_wcs(markername, 0, wide, _countof(wide));
|
|
|
|
|
|
|
|
D3DPERF_BeginEvent(bgra, wide);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" EXPORT void device_debug_marker_end(gs_device_t *)
|
|
|
|
{
|
|
|
|
D3DPERF_EndEvent();
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
extern "C" EXPORT gs_texture_t *
|
|
|
|
device_texture_create_gdi(gs_device_t *device, uint32_t width, uint32_t height)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
|
|
|
gs_texture *texture = nullptr;
|
|
|
|
try {
|
2019-06-22 22:13:45 -07:00
|
|
|
texture = new gs_texture_2d(device, width, height, GS_BGRA, 1,
|
|
|
|
nullptr, GS_RENDER_TARGET,
|
|
|
|
GS_TEXTURE_2D, true);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_texture_create_gdi (D3D11): %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2014-03-05 09:43:14 -08:00
|
|
|
} catch (const char *error) {
|
2014-08-07 23:42:07 -07:00
|
|
|
blog(LOG_ERROR, "device_texture_create_gdi (D3D11): %s", error);
|
2014-03-05 09:43:14 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool TextureGDICompatible(gs_texture_2d *tex2d, const char *func)
|
|
|
|
{
|
|
|
|
if (!tex2d->isGDICompatible) {
|
|
|
|
blog(LOG_ERROR, "%s (D3D11): Texture is not GDI compatible",
|
2019-06-22 22:13:45 -07:00
|
|
|
func);
|
2014-03-05 09:43:14 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
extern "C" EXPORT void *gs_texture_get_dc(gs_texture_t *tex)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
|
|
|
HDC hDC = nullptr;
|
|
|
|
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return nullptr;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
2014-08-07 23:42:07 -07:00
|
|
|
if (!TextureGDICompatible(tex2d, "gs_texture_get_dc"))
|
2014-03-05 09:43:14 -08:00
|
|
|
return nullptr;
|
|
|
|
|
2016-11-06 16:49:02 -08:00
|
|
|
if (!tex2d->gdiSurface)
|
|
|
|
return nullptr;
|
|
|
|
|
2014-03-05 09:43:14 -08:00
|
|
|
tex2d->gdiSurface->GetDC(true, &hDC);
|
|
|
|
return hDC;
|
|
|
|
}
|
|
|
|
|
2014-09-25 17:44:05 -07:00
|
|
|
extern "C" EXPORT void gs_texture_release_dc(gs_texture_t *tex)
|
2014-03-05 09:43:14 -08:00
|
|
|
{
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return;
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
gs_texture_2d *tex2d = static_cast<gs_texture_2d *>(tex);
|
2014-08-07 23:42:07 -07:00
|
|
|
if (!TextureGDICompatible(tex2d, "gs_texture_release_dc"))
|
2014-03-05 09:43:14 -08:00
|
|
|
return;
|
|
|
|
|
|
|
|
tex2d->gdiSurface->ReleaseDC(nullptr);
|
|
|
|
}
|
2014-10-13 21:41:09 -07:00
|
|
|
|
|
|
|
extern "C" EXPORT gs_texture_t *device_texture_open_shared(gs_device_t *device,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint32_t handle)
|
2014-10-13 21:41:09 -07:00
|
|
|
{
|
|
|
|
gs_texture *texture = nullptr;
|
|
|
|
try {
|
|
|
|
texture = new gs_texture_2d(device, handle);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2014-10-13 21:41:09 -07:00
|
|
|
blog(LOG_ERROR, "gs_texture_open_shared (D3D11): %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2016-10-06 23:39:35 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
2014-10-13 21:41:09 -07:00
|
|
|
} catch (const char *error) {
|
|
|
|
blog(LOG_ERROR, "gs_texture_open_shared (D3D11): %s", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
2018-10-05 02:38:11 -07:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-03-03 08:39:18 -08:00
|
|
|
int device_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms)
|
2018-10-05 02:38:11 -07:00
|
|
|
{
|
|
|
|
gs_texture_2d *tex2d = reinterpret_cast<gs_texture_2d *>(tex);
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return -1;
|
|
|
|
|
2019-03-03 08:39:18 -08:00
|
|
|
if (tex2d->acquired)
|
|
|
|
return 0;
|
|
|
|
|
2018-10-05 02:38:11 -07:00
|
|
|
ComQIPtr<IDXGIKeyedMutex> keyedMutex(tex2d->texture);
|
|
|
|
if (!keyedMutex)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
HRESULT hr = keyedMutex->AcquireSync(key, ms);
|
2019-03-03 08:39:18 -08:00
|
|
|
if (hr == S_OK) {
|
|
|
|
tex2d->acquired = true;
|
2018-10-05 02:38:11 -07:00
|
|
|
return 0;
|
2019-03-03 08:39:18 -08:00
|
|
|
} else if (hr == WAIT_TIMEOUT) {
|
2018-10-05 02:38:11 -07:00
|
|
|
return ETIMEDOUT;
|
2019-03-03 08:39:18 -08:00
|
|
|
}
|
2018-10-05 02:38:11 -07:00
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" EXPORT int device_texture_release_sync(gs_texture_t *tex,
|
2019-06-22 22:13:45 -07:00
|
|
|
uint64_t key)
|
2018-10-05 02:38:11 -07:00
|
|
|
{
|
|
|
|
gs_texture_2d *tex2d = reinterpret_cast<gs_texture_2d *>(tex);
|
|
|
|
if (tex->type != GS_TEXTURE_2D)
|
|
|
|
return -1;
|
|
|
|
|
2019-03-03 08:39:18 -08:00
|
|
|
if (!tex2d->acquired)
|
|
|
|
return 0;
|
|
|
|
|
2018-10-05 02:38:11 -07:00
|
|
|
ComQIPtr<IDXGIKeyedMutex> keyedMutex(tex2d->texture);
|
|
|
|
if (!keyedMutex)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
HRESULT hr = keyedMutex->ReleaseSync(key);
|
2019-03-03 08:39:18 -08:00
|
|
|
if (hr == S_OK) {
|
|
|
|
tex2d->acquired = false;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2018-10-05 02:38:11 -07:00
|
|
|
}
|
2018-10-05 03:15:13 -07:00
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
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)
|
2018-10-05 03:15:13 -07:00
|
|
|
{
|
|
|
|
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,
|
2019-06-22 22:13:45 -07:00
|
|
|
nullptr, flags, GS_TEXTURE_2D, false,
|
|
|
|
true);
|
2018-10-05 03:15:13 -07:00
|
|
|
tex_uv = new gs_texture_2d(device, tex_y->texture, flags);
|
|
|
|
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2018-10-05 03:15:13 -07:00
|
|
|
blog(LOG_ERROR, "gs_texture_create_nv12 (D3D11): %s (%08lX)",
|
2019-06-22 22:13:45 -07:00
|
|
|
error.str, error.hr);
|
2018-10-05 03:15:13 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} catch (const char *error) {
|
|
|
|
blog(LOG_ERROR, "gs_texture_create_nv12 (D3D11): %s", error);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-17 17:41:06 -08:00
|
|
|
tex_y->pairedNV12texture = tex_uv;
|
|
|
|
tex_uv->pairedNV12texture = tex_y;
|
|
|
|
|
2018-10-05 03:15:13 -07:00
|
|
|
*p_tex_y = tex_y;
|
|
|
|
*p_tex_uv = tex_uv;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-06-22 22:13:45 -07:00
|
|
|
extern "C" EXPORT gs_stagesurf_t *
|
|
|
|
device_stagesurface_create_nv12(gs_device_t *device, uint32_t width,
|
|
|
|
uint32_t height)
|
2018-10-05 03:15:13 -07:00
|
|
|
{
|
|
|
|
gs_stage_surface *surf = NULL;
|
|
|
|
try {
|
|
|
|
surf = new gs_stage_surface(device, width, height);
|
2019-08-28 21:10:51 -07:00
|
|
|
} catch (const HRError &error) {
|
2019-06-22 22:13:45 -07:00
|
|
|
blog(LOG_ERROR,
|
|
|
|
"device_stagesurface_create (D3D11): %s "
|
|
|
|
"(%08lX)",
|
|
|
|
error.str, error.hr);
|
2018-10-05 03:15:13 -07:00
|
|
|
LogD3D11ErrorDetails(error, device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return surf;
|
|
|
|
}
|
2019-11-27 16:35:27 -08:00
|
|
|
|
|
|
|
extern "C" EXPORT void
|
|
|
|
device_register_loss_callbacks(gs_device_t *device,
|
|
|
|
const gs_device_loss *callbacks)
|
|
|
|
{
|
|
|
|
device->loss_callbacks.emplace_back(*callbacks);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" EXPORT void device_unregister_loss_callbacks(gs_device_t *device,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
for (auto iter = device->loss_callbacks.begin();
|
|
|
|
iter != device->loss_callbacks.end(); ++iter) {
|
|
|
|
if (iter->data == data) {
|
|
|
|
device->loss_callbacks.erase(iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|