Imported Upstream version 0.13.2+dsfg1
This commit is contained in:
commit
fb3990e9e5
2036 changed files with 287360 additions and 0 deletions
35
libobs-d3d11/CMakeLists.txt
Normal file
35
libobs-d3d11/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
project(libobs-d3d11)
|
||||
|
||||
include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/libobs")
|
||||
|
||||
add_definitions(-DLIBOBS_EXPORTS)
|
||||
|
||||
set(libobs-d3d11_SOURCES
|
||||
d3d11-indexbuffer.cpp
|
||||
d3d11-samplerstate.cpp
|
||||
d3d11-shader.cpp
|
||||
d3d11-shaderprocessor.cpp
|
||||
d3d11-stagesurf.cpp
|
||||
d3d11-subsystem.cpp
|
||||
d3d11-texture2d.cpp
|
||||
d3d11-vertexbuffer.cpp
|
||||
d3d11-duplicator.cpp
|
||||
d3d11-zstencilbuffer.cpp)
|
||||
|
||||
set(libobs-d3d11_HEADERS
|
||||
d3d11-shaderprocessor.hpp
|
||||
d3d11-subsystem.hpp)
|
||||
|
||||
add_library(libobs-d3d11 MODULE
|
||||
${libobs-d3d11_SOURCES}
|
||||
${libobs-d3d11_HEADERS})
|
||||
set_target_properties(libobs-d3d11
|
||||
PROPERTIES
|
||||
OUTPUT_NAME libobs-d3d11
|
||||
PREFIX "")
|
||||
target_link_libraries(libobs-d3d11
|
||||
libobs
|
||||
d3d11
|
||||
dxgi)
|
||||
|
||||
install_obs_core(libobs-d3d11)
|
||||
210
libobs-d3d11/d3d11-duplicator.cpp
Normal file
210
libobs-d3d11/d3d11-duplicator.cpp
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11-subsystem.hpp"
|
||||
|
||||
static inline bool get_monitor(gs_device_t *device, int monitor_idx,
|
||||
IDXGIOutput **dxgiOutput)
|
||||
{
|
||||
ComPtr<IDXGIAdapter> dxgiAdapter;
|
||||
ComPtr<IDXGIDevice> dxgiDevice;
|
||||
HRESULT hr;
|
||||
|
||||
hr = device->device->QueryInterface(__uuidof(IDXGIDevice),
|
||||
(void**)dxgiDevice.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to query IDXGIDevice", hr);
|
||||
|
||||
hr = dxgiDevice->GetAdapter(dxgiAdapter.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to get adapter", hr);
|
||||
|
||||
hr = dxgiAdapter->EnumOutputs(monitor_idx, dxgiOutput);
|
||||
if (FAILED(hr)) {
|
||||
if (hr == DXGI_ERROR_NOT_FOUND)
|
||||
return false;
|
||||
|
||||
throw HRError("Failed to get output", hr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
gs_duplicator::gs_duplicator(gs_device_t *device_, int monitor_idx)
|
||||
: texture(nullptr), device(device_)
|
||||
{
|
||||
ComPtr<IDXGIOutput1> output1;
|
||||
ComPtr<IDXGIOutput> output;
|
||||
HRESULT hr;
|
||||
|
||||
if (!get_monitor(device, monitor_idx, output.Assign()))
|
||||
throw "Invalid monitor index";
|
||||
|
||||
hr = output->QueryInterface(__uuidof(IDXGIOutput1),
|
||||
(void**)output1.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to query IDXGIOutput1", hr);
|
||||
|
||||
hr = output1->DuplicateOutput(device->device, duplicator.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to duplicate output", hr);
|
||||
}
|
||||
|
||||
gs_duplicator::~gs_duplicator()
|
||||
{
|
||||
delete texture;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
EXPORT bool device_get_duplicator_monitor_info(gs_device_t *device,
|
||||
int monitor_idx, struct gs_monitor_info *info)
|
||||
{
|
||||
DXGI_OUTPUT_DESC desc;
|
||||
HRESULT hr;
|
||||
|
||||
try {
|
||||
ComPtr<IDXGIOutput> output;
|
||||
|
||||
if (!get_monitor(device, monitor_idx, output.Assign()))
|
||||
return false;
|
||||
|
||||
hr = output->GetDesc(&desc);
|
||||
if (FAILED(hr))
|
||||
throw HRError("GetDesc failed", hr);
|
||||
|
||||
} catch (HRError error) {
|
||||
blog(LOG_ERROR, "device_get_duplicator_monitor_info: "
|
||||
"%s (%08lX)", error.str, error.hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (desc.Rotation) {
|
||||
case DXGI_MODE_ROTATION_UNSPECIFIED:
|
||||
case DXGI_MODE_ROTATION_IDENTITY:
|
||||
info->rotation_degrees = 0;
|
||||
break;
|
||||
|
||||
case DXGI_MODE_ROTATION_ROTATE90:
|
||||
info->rotation_degrees = 90;
|
||||
break;
|
||||
|
||||
case DXGI_MODE_ROTATION_ROTATE180:
|
||||
info->rotation_degrees = 180;
|
||||
break;
|
||||
|
||||
case DXGI_MODE_ROTATION_ROTATE270:
|
||||
info->rotation_degrees = 270;
|
||||
break;
|
||||
}
|
||||
|
||||
info->x = desc.DesktopCoordinates.left;
|
||||
info->y = desc.DesktopCoordinates.top;
|
||||
info->cx = desc.DesktopCoordinates.right - info->x;
|
||||
info->cy = desc.DesktopCoordinates.bottom - info->y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT gs_duplicator_t *device_duplicator_create(gs_device_t *device,
|
||||
int monitor_idx)
|
||||
{
|
||||
gs_duplicator *duplicator = nullptr;
|
||||
|
||||
try {
|
||||
duplicator = new gs_duplicator(device, monitor_idx);
|
||||
|
||||
} catch (const char *error) {
|
||||
blog(LOG_DEBUG, "device_duplicator_create: %s",
|
||||
error);
|
||||
return nullptr;
|
||||
|
||||
} catch (HRError error) {
|
||||
blog(LOG_DEBUG, "device_duplicator_create: %s (%08lX)",
|
||||
error.str, error.hr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return duplicator;
|
||||
}
|
||||
|
||||
EXPORT void gs_duplicator_destroy(gs_duplicator_t *duplicator)
|
||||
{
|
||||
delete duplicator;
|
||||
}
|
||||
|
||||
static inline void copy_texture(gs_duplicator_t *d, ID3D11Texture2D *tex)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
tex->GetDesc(&desc);
|
||||
|
||||
if (!d->texture ||
|
||||
d->texture->width != desc.Width ||
|
||||
d->texture->height != desc.Height) {
|
||||
|
||||
delete d->texture;
|
||||
d->texture = (gs_texture_2d*)gs_texture_create(
|
||||
desc.Width, desc.Height,
|
||||
ConvertDXGITextureFormat(desc.Format), 1,
|
||||
nullptr, 0);
|
||||
}
|
||||
|
||||
if (!!d->texture)
|
||||
d->device->context->CopyResource(d->texture->texture,
|
||||
tex);
|
||||
}
|
||||
|
||||
EXPORT bool gs_duplicator_update_frame(gs_duplicator_t *d)
|
||||
{
|
||||
DXGI_OUTDUPL_FRAME_INFO info;
|
||||
ComPtr<ID3D11Texture2D> tex;
|
||||
ComPtr<IDXGIResource> res;
|
||||
HRESULT hr;
|
||||
|
||||
hr = d->duplicator->AcquireNextFrame(0, &info, res.Assign());
|
||||
if (hr == DXGI_ERROR_ACCESS_LOST) {
|
||||
return false;
|
||||
|
||||
} else if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
|
||||
return true;
|
||||
|
||||
} else if (FAILED(hr)) {
|
||||
blog(LOG_ERROR, "gs_duplicator_update_frame: Failed to update "
|
||||
"frame (%08lX)", hr);
|
||||
return true;
|
||||
}
|
||||
|
||||
hr = res->QueryInterface(__uuidof(ID3D11Texture2D),
|
||||
(void**)tex.Assign());
|
||||
if (FAILED(hr)) {
|
||||
blog(LOG_ERROR, "gs_duplicator_update_frame: Failed to query "
|
||||
"ID3D11Texture2D (%08lX)", hr);
|
||||
d->duplicator->ReleaseFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
copy_texture(d, tex);
|
||||
d->duplicator->ReleaseFrame();
|
||||
return true;
|
||||
}
|
||||
|
||||
EXPORT gs_texture_t *gs_duplicator_get_texture(gs_duplicator_t *duplicator)
|
||||
{
|
||||
return duplicator->texture;
|
||||
}
|
||||
|
||||
}
|
||||
54
libobs-d3d11/d3d11-indexbuffer.cpp
Normal file
54
libobs-d3d11/d3d11-indexbuffer.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11-subsystem.hpp"
|
||||
|
||||
void gs_index_buffer::InitBuffer()
|
||||
{
|
||||
D3D11_BUFFER_DESC bd;
|
||||
D3D11_SUBRESOURCE_DATA srd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
memset(&srd, 0, sizeof(srd));
|
||||
|
||||
bd.Usage = dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
|
||||
bd.CPUAccessFlags = dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
bd.ByteWidth = UINT(indexSize * num);
|
||||
srd.pSysMem = indices.data;
|
||||
|
||||
hr = device->device->CreateBuffer(&bd, &srd, indexBuffer.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create buffer", hr);
|
||||
}
|
||||
|
||||
gs_index_buffer::gs_index_buffer(gs_device_t *device, enum gs_index_type type,
|
||||
void *indices, size_t num, uint32_t flags)
|
||||
: device (device),
|
||||
dynamic ((flags & GS_DYNAMIC) != 0),
|
||||
type (type),
|
||||
num (num),
|
||||
indices (indices)
|
||||
{
|
||||
switch (type) {
|
||||
case GS_UNSIGNED_SHORT: indexSize = 2; break;
|
||||
case GS_UNSIGNED_LONG: indexSize = 4; break;
|
||||
}
|
||||
|
||||
InitBuffer();
|
||||
}
|
||||
87
libobs-d3d11/d3d11-samplerstate.cpp
Normal file
87
libobs-d3d11/d3d11-samplerstate.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <graphics/vec4.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "d3d11-subsystem.hpp"
|
||||
|
||||
static inline D3D11_TEXTURE_ADDRESS_MODE ConvertGSAddressMode(
|
||||
gs_address_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case GS_ADDRESS_WRAP: return D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
case GS_ADDRESS_CLAMP: return D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
case GS_ADDRESS_MIRROR: return D3D11_TEXTURE_ADDRESS_MIRROR;
|
||||
case GS_ADDRESS_BORDER: return D3D11_TEXTURE_ADDRESS_BORDER;
|
||||
case GS_ADDRESS_MIRRORONCE: return D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
|
||||
}
|
||||
|
||||
return D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
}
|
||||
|
||||
static inline D3D11_FILTER ConvertGSFilter( gs_sample_filter filter)
|
||||
{
|
||||
switch (filter) {
|
||||
case GS_FILTER_POINT:
|
||||
return D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
case GS_FILTER_LINEAR:
|
||||
return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
case GS_FILTER_MIN_MAG_POINT_MIP_LINEAR:
|
||||
return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
|
||||
case GS_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT:
|
||||
return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
|
||||
case GS_FILTER_MIN_POINT_MAG_MIP_LINEAR:
|
||||
return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
|
||||
case GS_FILTER_MIN_LINEAR_MAG_MIP_POINT:
|
||||
return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
|
||||
case GS_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
|
||||
return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
|
||||
case GS_FILTER_MIN_MAG_LINEAR_MIP_POINT:
|
||||
return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
||||
case GS_FILTER_ANISOTROPIC:
|
||||
return D3D11_FILTER_ANISOTROPIC;
|
||||
}
|
||||
|
||||
return D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
}
|
||||
|
||||
gs_sampler_state::gs_sampler_state(gs_device_t *device,
|
||||
const gs_sampler_info *info)
|
||||
: device (device),
|
||||
info (*info)
|
||||
{
|
||||
D3D11_SAMPLER_DESC sd;
|
||||
HRESULT hr;
|
||||
vec4 v4;
|
||||
|
||||
memset(&sd, 0, sizeof(sd));
|
||||
sd.AddressU = ConvertGSAddressMode(info->address_u);
|
||||
sd.AddressV = ConvertGSAddressMode(info->address_v);
|
||||
sd.AddressW = ConvertGSAddressMode(info->address_w);
|
||||
sd.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
||||
sd.Filter = ConvertGSFilter(info->filter);
|
||||
sd.MaxAnisotropy = info->max_anisotropy;
|
||||
sd.MaxLOD = FLT_MAX;
|
||||
|
||||
vec4_from_rgba(&v4, info->border_color);
|
||||
memcpy(sd.BorderColor, v4.ptr, sizeof(v4));
|
||||
|
||||
hr = device->device->CreateSamplerState(&sd, state.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create sampler state", hr);
|
||||
}
|
||||
386
libobs-d3d11/d3d11-shader.cpp
Normal file
386
libobs-d3d11/d3d11-shader.cpp
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11-subsystem.hpp"
|
||||
#include "d3d11-shaderprocessor.hpp"
|
||||
#include <graphics/vec2.h>
|
||||
#include <graphics/vec3.h>
|
||||
#include <graphics/matrix3.h>
|
||||
#include <graphics/matrix4.h>
|
||||
|
||||
void gs_vertex_shader::GetBuffersExpected(
|
||||
const vector<D3D11_INPUT_ELEMENT_DESC> &inputs)
|
||||
{
|
||||
for (size_t i = 0; i < inputs.size(); i++) {
|
||||
const D3D11_INPUT_ELEMENT_DESC &input = inputs[i];
|
||||
if (strcmp(input.SemanticName, "NORMAL") == 0)
|
||||
hasNormals = true;
|
||||
else if (strcmp(input.SemanticName, "TANGENT") == 0)
|
||||
hasTangents = true;
|
||||
else if (strcmp(input.SemanticName, "COLOR") == 0)
|
||||
hasColors = true;
|
||||
else if (strcmp(input.SemanticName, "TEXCOORD") == 0)
|
||||
nTexUnits++;
|
||||
}
|
||||
}
|
||||
|
||||
gs_vertex_shader::gs_vertex_shader(gs_device_t *device, const char *file,
|
||||
const char *shaderString)
|
||||
: gs_shader (device, GS_SHADER_VERTEX),
|
||||
hasNormals (false),
|
||||
hasColors (false),
|
||||
hasTangents (false),
|
||||
nTexUnits (0)
|
||||
{
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> inputs;
|
||||
ShaderProcessor processor(device);
|
||||
ComPtr<ID3D10Blob> shaderBlob;
|
||||
string outputString;
|
||||
HRESULT hr;
|
||||
|
||||
processor.Process(shaderString, file);
|
||||
processor.BuildString(outputString);
|
||||
processor.BuildParams(params);
|
||||
processor.BuildInputLayout(inputs);
|
||||
GetBuffersExpected(inputs);
|
||||
BuildConstantBuffer();
|
||||
|
||||
Compile(outputString.c_str(), file, "vs_4_0", shaderBlob.Assign());
|
||||
|
||||
hr = device->device->CreateVertexShader(shaderBlob->GetBufferPointer(),
|
||||
shaderBlob->GetBufferSize(), NULL, shader.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create vertex shader", hr);
|
||||
|
||||
hr = device->device->CreateInputLayout(inputs.data(),
|
||||
(UINT)inputs.size(), shaderBlob->GetBufferPointer(),
|
||||
shaderBlob->GetBufferSize(), layout.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create input layout", hr);
|
||||
|
||||
viewProj = gs_shader_get_param_by_name(this, "ViewProj");
|
||||
world = gs_shader_get_param_by_name(this, "World");
|
||||
}
|
||||
|
||||
gs_pixel_shader::gs_pixel_shader(gs_device_t *device, const char *file,
|
||||
const char *shaderString)
|
||||
: gs_shader(device, GS_SHADER_PIXEL)
|
||||
{
|
||||
ShaderProcessor processor(device);
|
||||
ComPtr<ID3D10Blob> shaderBlob;
|
||||
string outputString;
|
||||
HRESULT hr;
|
||||
|
||||
processor.Process(shaderString, file);
|
||||
processor.BuildString(outputString);
|
||||
processor.BuildParams(params);
|
||||
processor.BuildSamplers(samplers);
|
||||
BuildConstantBuffer();
|
||||
|
||||
Compile(outputString.c_str(), file, "ps_4_0", shaderBlob.Assign());
|
||||
|
||||
hr = device->device->CreatePixelShader(shaderBlob->GetBufferPointer(),
|
||||
shaderBlob->GetBufferSize(), NULL, shader.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create vertex shader", hr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shader compilers will pack constants in to single registers when possible.
|
||||
* For example:
|
||||
*
|
||||
* uniform float3 test1;
|
||||
* uniform float test2;
|
||||
*
|
||||
* will inhabit a single constant register (c0.xyz for 'test1', and c0.w for
|
||||
* 'test2')
|
||||
*
|
||||
* However, if two constants cannot inhabit the same register, the second one
|
||||
* must begin at a new register, for example:
|
||||
*
|
||||
* uniform float2 test1;
|
||||
* uniform float3 test2;
|
||||
*
|
||||
* 'test1' will inhabit register constant c0.xy. However, because there's no
|
||||
* room for 'test2, it must use a new register constant entirely (c1.xyz).
|
||||
*
|
||||
* So if we want to calculate the position of the constants in the constant
|
||||
* buffer, we must take this in to account.
|
||||
*/
|
||||
|
||||
void gs_shader::BuildConstantBuffer()
|
||||
{
|
||||
for (size_t i = 0; i < params.size(); i++) {
|
||||
gs_shader_param ¶m = params[i];
|
||||
size_t size = 0;
|
||||
|
||||
switch (param.type) {
|
||||
case GS_SHADER_PARAM_BOOL:
|
||||
case GS_SHADER_PARAM_INT:
|
||||
case GS_SHADER_PARAM_FLOAT: size = sizeof(float); break;
|
||||
case GS_SHADER_PARAM_VEC2: size = sizeof(vec2); break;
|
||||
case GS_SHADER_PARAM_VEC3: size = sizeof(float)*3; break;
|
||||
case GS_SHADER_PARAM_VEC4: size = sizeof(vec4); break;
|
||||
case GS_SHADER_PARAM_MATRIX4X4:
|
||||
size = sizeof(float)*4*4;
|
||||
break;
|
||||
case GS_SHADER_PARAM_TEXTURE:
|
||||
case GS_SHADER_PARAM_STRING:
|
||||
case GS_SHADER_PARAM_UNKNOWN:
|
||||
continue;
|
||||
}
|
||||
|
||||
/* checks to see if this constant needs to start at a new
|
||||
* register */
|
||||
if (size && (constantSize & 15) != 0) {
|
||||
size_t alignMax = (constantSize + 15) & ~15;
|
||||
|
||||
if ((size + constantSize) > alignMax)
|
||||
constantSize = alignMax;
|
||||
}
|
||||
|
||||
param.pos = constantSize;
|
||||
constantSize += size;
|
||||
}
|
||||
|
||||
if (constantSize) {
|
||||
D3D11_BUFFER_DESC bd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
bd.ByteWidth = (constantSize+15)&0xFFFFFFF0; /* align */
|
||||
bd.Usage = D3D11_USAGE_DYNAMIC;
|
||||
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
||||
|
||||
hr = device->device->CreateBuffer(&bd, NULL,
|
||||
constants.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create constant buffer", hr);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < params.size(); i++)
|
||||
gs_shader_set_default(¶ms[i]);
|
||||
}
|
||||
|
||||
void gs_shader::Compile(const char *shaderString, const char *file,
|
||||
const char *target, ID3D10Blob **shader)
|
||||
{
|
||||
ComPtr<ID3D10Blob> errorsBlob;
|
||||
HRESULT hr;
|
||||
|
||||
if (!shaderString)
|
||||
throw "No shader string specified";
|
||||
|
||||
hr = device->d3dCompile(shaderString, strlen(shaderString), file, NULL,
|
||||
NULL, "main", target,
|
||||
D3D10_SHADER_OPTIMIZATION_LEVEL1, 0,
|
||||
shader, errorsBlob.Assign());
|
||||
if (FAILED(hr)) {
|
||||
if (errorsBlob != NULL && errorsBlob->GetBufferSize())
|
||||
throw ShaderError(errorsBlob, hr);
|
||||
else
|
||||
throw HRError("Failed to compile shader", hr);
|
||||
}
|
||||
}
|
||||
|
||||
inline void gs_shader::UpdateParam(vector<uint8_t> &constData,
|
||||
gs_shader_param ¶m, bool &upload)
|
||||
{
|
||||
if (param.type != GS_SHADER_PARAM_TEXTURE) {
|
||||
if (!param.curValue.size())
|
||||
throw "Not all shader parameters were set";
|
||||
|
||||
/* padding in case the constant needs to start at a new
|
||||
* register */
|
||||
if (param.pos > constData.size()) {
|
||||
uint8_t zero = 0;
|
||||
|
||||
constData.insert(constData.end(),
|
||||
param.pos - constData.size(), zero);
|
||||
}
|
||||
|
||||
constData.insert(constData.end(),
|
||||
param.curValue.begin(),
|
||||
param.curValue.end());
|
||||
|
||||
if (param.changed) {
|
||||
upload = true;
|
||||
param.changed = false;
|
||||
}
|
||||
} else if (param.curValue.size() == sizeof(gs_texture_t*)) {
|
||||
gs_texture_t *tex;
|
||||
memcpy(&tex, param.curValue.data(), sizeof(gs_texture_t*));
|
||||
device_load_texture(device, tex, param.textureID);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_shader::UploadParams()
|
||||
{
|
||||
vector<uint8_t> constData;
|
||||
bool upload = false;
|
||||
|
||||
constData.reserve(constantSize);
|
||||
|
||||
for (size_t i = 0; i < params.size(); i++)
|
||||
UpdateParam(constData, params[i], upload);
|
||||
|
||||
if (constData.size() != constantSize)
|
||||
throw "Invalid constant data size given to shader";
|
||||
|
||||
if (upload) {
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
HRESULT hr;
|
||||
|
||||
hr = device->context->Map(constants, 0, D3D11_MAP_WRITE_DISCARD,
|
||||
0, &map);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Could not lock constant buffer", hr);
|
||||
|
||||
memcpy(map.pData, constData.data(), constData.size());
|
||||
device->context->Unmap(constants, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_shader_destroy(gs_shader_t *shader)
|
||||
{
|
||||
delete shader;
|
||||
}
|
||||
|
||||
int gs_shader_get_num_params(const gs_shader_t *shader)
|
||||
{
|
||||
return (int)shader->params.size();
|
||||
}
|
||||
|
||||
gs_sparam_t *gs_shader_get_param_by_idx(gs_shader_t *shader, uint32_t param)
|
||||
{
|
||||
return &shader->params[param];
|
||||
}
|
||||
|
||||
gs_sparam_t *gs_shader_get_param_by_name(gs_shader_t *shader, const char *name)
|
||||
{
|
||||
for (size_t i = 0; i < shader->params.size(); i++) {
|
||||
gs_shader_param ¶m = shader->params[i];
|
||||
if (strcmp(param.name.c_str(), name) == 0)
|
||||
return ¶m;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gs_sparam_t *gs_shader_get_viewproj_matrix(const gs_shader_t *shader)
|
||||
{
|
||||
if (shader->type != GS_SHADER_VERTEX)
|
||||
return NULL;
|
||||
|
||||
return static_cast<const gs_vertex_shader*>(shader)->viewProj;
|
||||
}
|
||||
|
||||
gs_sparam_t *gs_shader_get_world_matrix(const gs_shader_t *shader)
|
||||
{
|
||||
if (shader->type != GS_SHADER_VERTEX)
|
||||
return NULL;
|
||||
|
||||
return static_cast<const gs_vertex_shader*>(shader)->world;
|
||||
}
|
||||
|
||||
void gs_shader_get_param_info(const gs_sparam_t *param,
|
||||
struct gs_shader_param_info *info)
|
||||
{
|
||||
if (!param)
|
||||
return;
|
||||
|
||||
info->name = param->name.c_str();
|
||||
info->type = param->type;
|
||||
}
|
||||
|
||||
static inline void shader_setval_inline(gs_shader_param *param,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
assert(param);
|
||||
if (!param)
|
||||
return;
|
||||
|
||||
bool size_changed = param->curValue.size() != size;
|
||||
if (size_changed)
|
||||
param->curValue.resize(size);
|
||||
|
||||
if (size_changed || memcmp(param->curValue.data(), data, size) != 0) {
|
||||
memcpy(param->curValue.data(), data, size);
|
||||
param->changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void gs_shader_set_bool(gs_sparam_t *param, bool val)
|
||||
{
|
||||
int b_val = (int)val;
|
||||
shader_setval_inline(param, &b_val, sizeof(int));
|
||||
}
|
||||
|
||||
void gs_shader_set_float(gs_sparam_t *param, float val)
|
||||
{
|
||||
shader_setval_inline(param, &val, sizeof(float));
|
||||
}
|
||||
|
||||
void gs_shader_set_int(gs_sparam_t *param, int val)
|
||||
{
|
||||
shader_setval_inline(param, &val, sizeof(int));
|
||||
}
|
||||
|
||||
void gs_shader_set_matrix3(gs_sparam_t *param, const struct matrix3 *val)
|
||||
{
|
||||
struct matrix4 mat;
|
||||
matrix4_from_matrix3(&mat, val);
|
||||
shader_setval_inline(param, &mat, sizeof(matrix4));
|
||||
}
|
||||
|
||||
void gs_shader_set_matrix4(gs_sparam_t *param, const struct matrix4 *val)
|
||||
{
|
||||
shader_setval_inline(param, val, sizeof(matrix4));
|
||||
}
|
||||
|
||||
void gs_shader_set_vec2(gs_sparam_t *param, const struct vec2 *val)
|
||||
{
|
||||
shader_setval_inline(param, val, sizeof(vec2));
|
||||
}
|
||||
|
||||
void gs_shader_set_vec3(gs_sparam_t *param, const struct vec3 *val)
|
||||
{
|
||||
shader_setval_inline(param, val, sizeof(float) * 3);
|
||||
}
|
||||
|
||||
void gs_shader_set_vec4(gs_sparam_t *param, const struct vec4 *val)
|
||||
{
|
||||
shader_setval_inline(param, val, sizeof(vec4));
|
||||
}
|
||||
|
||||
void gs_shader_set_texture(gs_sparam_t *param, gs_texture_t *val)
|
||||
{
|
||||
shader_setval_inline(param, &val, sizeof(gs_texture_t*));
|
||||
}
|
||||
|
||||
void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
|
||||
{
|
||||
shader_setval_inline(param, val, size);
|
||||
}
|
||||
|
||||
void gs_shader_set_default(gs_sparam_t *param)
|
||||
{
|
||||
if (param->defaultValue.size())
|
||||
shader_setval_inline(param, param->defaultValue.data(),
|
||||
param->defaultValue.size());
|
||||
}
|
||||
237
libobs-d3d11/d3d11-shaderprocessor.cpp
Normal file
237
libobs-d3d11/d3d11-shaderprocessor.cpp
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11-subsystem.hpp"
|
||||
#include "d3d11-shaderprocessor.hpp"
|
||||
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
static const char *semanticInputNames[] =
|
||||
{"POSITION", "NORMAL", "COLOR", "TANGENT", "TEXCOORD"};
|
||||
static const char *semanticOutputNames[] =
|
||||
{"SV_Position", "NORMAL", "COLOR", "TANGENT", "TEXCOORD"};
|
||||
|
||||
static const char *ConvertSemanticName(const char *name)
|
||||
{
|
||||
const size_t num = sizeof(semanticInputNames) / sizeof(const char*);
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
if (strcmp(name, semanticInputNames[i]) == 0)
|
||||
return semanticOutputNames[i];
|
||||
}
|
||||
|
||||
throw "Unknown Semantic Name";
|
||||
}
|
||||
|
||||
static void GetSemanticInfo(shader_var *var, const char *&name,
|
||||
uint32_t &index)
|
||||
{
|
||||
const char *mapping = var->mapping;
|
||||
const char *indexStr = mapping;
|
||||
|
||||
while (*indexStr && !isdigit(*indexStr))
|
||||
indexStr++;
|
||||
index = (*indexStr) ? strtol(indexStr, NULL, 10) : 0;
|
||||
|
||||
string nameStr;
|
||||
nameStr.assign(mapping, indexStr-mapping);
|
||||
name = ConvertSemanticName(nameStr.c_str());
|
||||
}
|
||||
|
||||
static void AddInputLayoutVar(shader_var *var,
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> &layout)
|
||||
{
|
||||
D3D11_INPUT_ELEMENT_DESC ied;
|
||||
const char *semanticName;
|
||||
uint32_t semanticIndex;
|
||||
|
||||
GetSemanticInfo(var, semanticName, semanticIndex);
|
||||
|
||||
memset(&ied, 0, sizeof(ied));
|
||||
ied.SemanticName = semanticName;
|
||||
ied.SemanticIndex = semanticIndex;
|
||||
ied.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
|
||||
if (strcmp(var->mapping, "COLOR") == 0) {
|
||||
ied.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
} else if (strcmp(var->mapping, "POSITION") == 0 ||
|
||||
strcmp(var->mapping, "NORMAL") == 0 ||
|
||||
strcmp(var->mapping, "TANGENT") == 0) {
|
||||
ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
|
||||
} else if (astrcmp_n(var->mapping, "TEXCOORD", 8) == 0) {
|
||||
/* type is always a 'float' type */
|
||||
switch (var->type[5]) {
|
||||
case 0: ied.Format = DXGI_FORMAT_R32_FLOAT; break;
|
||||
case '2': ied.Format = DXGI_FORMAT_R32G32_FLOAT; break;
|
||||
case '3':
|
||||
case '4': ied.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; break;
|
||||
}
|
||||
}
|
||||
|
||||
layout.push_back(ied);
|
||||
}
|
||||
|
||||
static inline bool SetSlot(vector<D3D11_INPUT_ELEMENT_DESC> &layout,
|
||||
const char *name, uint32_t index, uint32_t &slotIdx)
|
||||
{
|
||||
for (size_t i = 0; i < layout.size(); i++) {
|
||||
D3D11_INPUT_ELEMENT_DESC &input = layout[i];
|
||||
if (input.SemanticIndex == index &&
|
||||
strcmpi(input.SemanticName, name) == 0) {
|
||||
layout[i].InputSlot = slotIdx++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void BuildInputLayoutFromVars(shader_parser *parser, darray *vars,
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> &layout)
|
||||
{
|
||||
shader_var *array = (shader_var*)vars->array;
|
||||
|
||||
for (size_t i = 0; i < vars->num; i++) {
|
||||
shader_var *var = array+i;
|
||||
|
||||
if (var->mapping) {
|
||||
AddInputLayoutVar(var, layout);
|
||||
} else {
|
||||
shader_struct *st = shader_parser_getstruct(parser,
|
||||
var->type);
|
||||
if (st)
|
||||
BuildInputLayoutFromVars(parser, &st->vars.da,
|
||||
layout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the input slot value for each semantic, however we do it in
|
||||
* a specific order so that it will always match the vertex buffer's
|
||||
* sub-buffer order (points-> normals-> colors-> tangents-> uvcoords)
|
||||
*/
|
||||
uint32_t slot = 0;
|
||||
SetSlot(layout, "SV_Position", 0, slot);
|
||||
SetSlot(layout, "NORMAL", 0, slot);
|
||||
SetSlot(layout, "COLOR", 0, slot);
|
||||
SetSlot(layout, "TANGENT", 0, slot);
|
||||
|
||||
uint32_t index = 0;
|
||||
while (SetSlot(layout, "TEXCOORD", index++, slot));
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildInputLayout(
|
||||
vector<D3D11_INPUT_ELEMENT_DESC> &layout)
|
||||
{
|
||||
shader_func *func = shader_parser_getfunc(&parser, "main");
|
||||
if (!func)
|
||||
throw "Failed to find 'main' shader function";
|
||||
|
||||
BuildInputLayoutFromVars(&parser, &func->params.da, layout);
|
||||
}
|
||||
|
||||
gs_shader_param::gs_shader_param(shader_var &var, uint32_t &texCounter)
|
||||
: name (var.name),
|
||||
type (get_shader_param_type(var.type)),
|
||||
textureID (texCounter),
|
||||
arrayCount (var.array_count),
|
||||
changed (false)
|
||||
{
|
||||
defaultValue.resize(var.default_val.num);
|
||||
memcpy(defaultValue.data(), var.default_val.array, var.default_val.num);
|
||||
|
||||
if (type == GS_SHADER_PARAM_TEXTURE)
|
||||
texCounter++;
|
||||
else
|
||||
textureID = 0;
|
||||
}
|
||||
|
||||
static inline void AddParam(shader_var &var, vector<gs_shader_param> ¶ms,
|
||||
uint32_t &texCounter)
|
||||
{
|
||||
if (var.var_type != SHADER_VAR_UNIFORM ||
|
||||
strcmp(var.type, "sampler") == 0)
|
||||
return;
|
||||
|
||||
params.push_back(gs_shader_param(var, texCounter));
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildParams(vector<gs_shader_param> ¶ms)
|
||||
{
|
||||
uint32_t texCounter = 0;
|
||||
|
||||
for (size_t i = 0; i < parser.params.num; i++)
|
||||
AddParam(parser.params.array[i], params, texCounter);
|
||||
}
|
||||
|
||||
static inline void AddSampler(gs_device_t *device, shader_sampler &sampler,
|
||||
vector<ShaderSampler> &samplers)
|
||||
{
|
||||
gs_sampler_info si;
|
||||
shader_sampler_convert(&sampler, &si);
|
||||
samplers.push_back(ShaderSampler(sampler.name, device, &si));
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildSamplers(vector<ShaderSampler> &samplers)
|
||||
{
|
||||
for (size_t i = 0; i < parser.samplers.num; i++)
|
||||
AddSampler(device, parser.samplers.array[i], samplers);
|
||||
}
|
||||
|
||||
void ShaderProcessor::BuildString(string &outputString)
|
||||
{
|
||||
stringstream output;
|
||||
cf_token *token = cf_preprocessor_get_tokens(&parser.cfp.pp);
|
||||
while (token->type != CFTOKEN_NONE) {
|
||||
/* cheaply just replace specific tokens */
|
||||
if (strref_cmp(&token->str, "POSITION") == 0)
|
||||
output << "SV_Position";
|
||||
else if (strref_cmp(&token->str, "TARGET") == 0)
|
||||
output << "SV_Target";
|
||||
else if (strref_cmp(&token->str, "texture2d") == 0)
|
||||
output << "Texture2D";
|
||||
else if (strref_cmp(&token->str, "texture3d") == 0)
|
||||
output << "Texture3D";
|
||||
else if (strref_cmp(&token->str, "texture_cube") == 0)
|
||||
output << "TextureCube";
|
||||
else if (strref_cmp(&token->str, "texture_rect") == 0)
|
||||
throw "texture_rect is not supported in D3D";
|
||||
else if (strref_cmp(&token->str, "sampler_state") == 0)
|
||||
output << "SamplerState";
|
||||
else
|
||||
output.write(token->str.array, token->str.len);
|
||||
|
||||
token++;
|
||||
}
|
||||
|
||||
outputString = move(output.str());
|
||||
}
|
||||
|
||||
void ShaderProcessor::Process(const char *shader_string, const char *file)
|
||||
{
|
||||
bool success = shader_parse(&parser, shader_string, file);
|
||||
char *str = shader_parser_geterrors(&parser);
|
||||
if (str) {
|
||||
blog(LOG_WARNING, "Shader parser errors/warnings:\n%s\n", str);
|
||||
bfree(str);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
throw "Failed to parse shader";
|
||||
}
|
||||
40
libobs-d3d11/d3d11-shaderprocessor.hpp
Normal file
40
libobs-d3d11/d3d11-shaderprocessor.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <graphics/shader-parser.h>
|
||||
|
||||
struct ShaderParser : shader_parser {
|
||||
inline ShaderParser() {shader_parser_init(this);}
|
||||
inline ~ShaderParser() {shader_parser_free(this);}
|
||||
};
|
||||
|
||||
struct ShaderProcessor {
|
||||
gs_device_t *device;
|
||||
ShaderParser parser;
|
||||
|
||||
void BuildInputLayout(vector<D3D11_INPUT_ELEMENT_DESC> &inputs);
|
||||
void BuildParams(vector<gs_shader_param> ¶ms);
|
||||
void BuildSamplers(vector<ShaderSampler> &samplers);
|
||||
void BuildString(string &outputString);
|
||||
void Process(const char *shader_string, const char *file);
|
||||
|
||||
inline ShaderProcessor(gs_device_t *device) : device(device)
|
||||
{
|
||||
}
|
||||
};
|
||||
44
libobs-d3d11/d3d11-stagesurf.cpp
Normal file
44
libobs-d3d11/d3d11-stagesurf.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11-subsystem.hpp"
|
||||
|
||||
gs_stage_surface::gs_stage_surface(gs_device_t *device, uint32_t width,
|
||||
uint32_t height, gs_color_format colorFormat)
|
||||
: device (device),
|
||||
width (width),
|
||||
height (height),
|
||||
format (colorFormat),
|
||||
dxgiFormat (ConvertGSTextureFormat(colorFormat))
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&td, 0, sizeof(td));
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = 1;
|
||||
td.ArraySize = 1;
|
||||
td.Format = dxgiFormat;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
td.Usage = D3D11_USAGE_STAGING;
|
||||
|
||||
hr = device->device->CreateTexture2D(&td, NULL, texture.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create 2D texture", hr);
|
||||
}
|
||||
2026
libobs-d3d11/d3d11-subsystem.cpp
Normal file
2026
libobs-d3d11/d3d11-subsystem.cpp
Normal file
File diff suppressed because it is too large
Load diff
672
libobs-d3d11/d3d11-subsystem.hpp
Normal file
672
libobs-d3d11/d3d11-subsystem.hpp
Normal file
|
|
@ -0,0 +1,672 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <util/AlignedNew.hpp>
|
||||
#include <util/windows/win-version.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_2.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
#include <util/base.h>
|
||||
#include <graphics/matrix4.h>
|
||||
#include <graphics/graphics.h>
|
||||
#include <graphics/device-exports.h>
|
||||
#include <util/windows/ComPtr.hpp>
|
||||
#include <util/windows/HRError.hpp>
|
||||
|
||||
struct shader_var;
|
||||
struct shader_sampler;
|
||||
struct gs_vertex_shader;
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* Just to clarify, all structs, and all public. These are exporting only
|
||||
* via encapsulated C bindings, not C++ bindings, so the whole concept of
|
||||
* "public" and "private" does not matter at all for this subproject.
|
||||
*/
|
||||
|
||||
static inline uint32_t GetWinVer()
|
||||
{
|
||||
struct win_version_info ver;
|
||||
get_win_ver(&ver);
|
||||
|
||||
return (ver.major << 8) | ver.minor;
|
||||
}
|
||||
|
||||
static inline DXGI_FORMAT ConvertGSTextureFormat(gs_color_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_UNKNOWN: return DXGI_FORMAT_UNKNOWN;
|
||||
case GS_A8: return DXGI_FORMAT_A8_UNORM;
|
||||
case GS_R8: return DXGI_FORMAT_R8_UNORM;
|
||||
case GS_RGBA: return DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
case GS_BGRX: return DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||
case GS_BGRA: return DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
case GS_R10G10B10A2: return DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
case GS_RGBA16: return DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
case GS_R16: return DXGI_FORMAT_R16_UNORM;
|
||||
case GS_RGBA16F: return DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
case GS_RGBA32F: return DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||
case GS_RG16F: return DXGI_FORMAT_R16G16_FLOAT;
|
||||
case GS_RG32F: return DXGI_FORMAT_R32G32_FLOAT;
|
||||
case GS_R16F: return DXGI_FORMAT_R16_FLOAT;
|
||||
case GS_R32F: return DXGI_FORMAT_R32_FLOAT;
|
||||
case GS_DXT1: return DXGI_FORMAT_BC1_UNORM;
|
||||
case GS_DXT3: return DXGI_FORMAT_BC2_UNORM;
|
||||
case GS_DXT5: return DXGI_FORMAT_BC3_UNORM;
|
||||
}
|
||||
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format)
|
||||
{
|
||||
switch ((unsigned long)format) {
|
||||
case DXGI_FORMAT_A8_UNORM: return GS_A8;
|
||||
case DXGI_FORMAT_R8_UNORM: return GS_R8;
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM: return GS_RGBA;
|
||||
case DXGI_FORMAT_B8G8R8X8_UNORM: return GS_BGRX;
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM: return GS_BGRA;
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM: return GS_R10G10B10A2;
|
||||
case DXGI_FORMAT_R16G16B16A16_UNORM: return GS_RGBA16;
|
||||
case DXGI_FORMAT_R16_UNORM: return GS_R16;
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT: return GS_RGBA16F;
|
||||
case DXGI_FORMAT_R32G32B32A32_FLOAT: return GS_RGBA32F;
|
||||
case DXGI_FORMAT_R16G16_FLOAT: return GS_RG16F;
|
||||
case DXGI_FORMAT_R32G32_FLOAT: return GS_RG32F;
|
||||
case DXGI_FORMAT_R16_FLOAT: return GS_R16F;
|
||||
case DXGI_FORMAT_R32_FLOAT: return GS_R32F;
|
||||
case DXGI_FORMAT_BC1_UNORM: return GS_DXT1;
|
||||
case DXGI_FORMAT_BC2_UNORM: return GS_DXT3;
|
||||
case DXGI_FORMAT_BC3_UNORM: return GS_DXT5;
|
||||
}
|
||||
|
||||
return GS_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline DXGI_FORMAT ConvertGSZStencilFormat(gs_zstencil_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case GS_ZS_NONE: return DXGI_FORMAT_UNKNOWN;
|
||||
case GS_Z16: return DXGI_FORMAT_D16_UNORM;
|
||||
case GS_Z24_S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;
|
||||
case GS_Z32F: return DXGI_FORMAT_D32_FLOAT;
|
||||
case GS_Z32F_S8X24: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
|
||||
}
|
||||
|
||||
return DXGI_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline D3D11_COMPARISON_FUNC ConvertGSDepthTest(gs_depth_test test)
|
||||
{
|
||||
switch (test) {
|
||||
case GS_NEVER: return D3D11_COMPARISON_NEVER;
|
||||
case GS_LESS: return D3D11_COMPARISON_LESS;
|
||||
case GS_LEQUAL: return D3D11_COMPARISON_LESS_EQUAL;
|
||||
case GS_EQUAL: return D3D11_COMPARISON_EQUAL;
|
||||
case GS_GEQUAL: return D3D11_COMPARISON_GREATER_EQUAL;
|
||||
case GS_GREATER: return D3D11_COMPARISON_GREATER;
|
||||
case GS_NOTEQUAL: return D3D11_COMPARISON_NOT_EQUAL;
|
||||
case GS_ALWAYS: return D3D11_COMPARISON_ALWAYS;
|
||||
}
|
||||
|
||||
return D3D11_COMPARISON_NEVER;
|
||||
}
|
||||
|
||||
static inline D3D11_STENCIL_OP ConvertGSStencilOp(gs_stencil_op_type op)
|
||||
{
|
||||
switch (op) {
|
||||
case GS_KEEP: return D3D11_STENCIL_OP_KEEP;
|
||||
case GS_ZERO: return D3D11_STENCIL_OP_ZERO;
|
||||
case GS_REPLACE: return D3D11_STENCIL_OP_REPLACE;
|
||||
case GS_INCR: return D3D11_STENCIL_OP_INCR;
|
||||
case GS_DECR: return D3D11_STENCIL_OP_DECR;
|
||||
case GS_INVERT: return D3D11_STENCIL_OP_INVERT;
|
||||
}
|
||||
|
||||
return D3D11_STENCIL_OP_KEEP;
|
||||
}
|
||||
|
||||
static inline D3D11_BLEND ConvertGSBlendType(gs_blend_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case GS_BLEND_ZERO: return D3D11_BLEND_ZERO;
|
||||
case GS_BLEND_ONE: return D3D11_BLEND_ONE;
|
||||
case GS_BLEND_SRCCOLOR: return D3D11_BLEND_SRC_COLOR;
|
||||
case GS_BLEND_INVSRCCOLOR: return D3D11_BLEND_INV_SRC_COLOR;
|
||||
case GS_BLEND_SRCALPHA: return D3D11_BLEND_SRC_ALPHA;
|
||||
case GS_BLEND_INVSRCALPHA: return D3D11_BLEND_INV_SRC_ALPHA;
|
||||
case GS_BLEND_DSTCOLOR: return D3D11_BLEND_DEST_COLOR;
|
||||
case GS_BLEND_INVDSTCOLOR: return D3D11_BLEND_INV_DEST_COLOR;
|
||||
case GS_BLEND_DSTALPHA: return D3D11_BLEND_DEST_ALPHA;
|
||||
case GS_BLEND_INVDSTALPHA: return D3D11_BLEND_INV_DEST_ALPHA;
|
||||
case GS_BLEND_SRCALPHASAT: return D3D11_BLEND_SRC_ALPHA_SAT;
|
||||
}
|
||||
|
||||
return D3D11_BLEND_ONE;
|
||||
}
|
||||
|
||||
static inline D3D11_CULL_MODE ConvertGSCullMode(gs_cull_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case GS_BACK: return D3D11_CULL_BACK;
|
||||
case GS_FRONT: return D3D11_CULL_FRONT;
|
||||
case GS_NEITHER: return D3D11_CULL_NONE;
|
||||
}
|
||||
|
||||
return D3D11_CULL_BACK;
|
||||
}
|
||||
|
||||
static inline D3D11_PRIMITIVE_TOPOLOGY ConvertGSTopology(gs_draw_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case GS_POINTS: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
case GS_LINES: return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
|
||||
case GS_LINESTRIP: return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
||||
case GS_TRIS: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case GS_TRISTRIP: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
}
|
||||
|
||||
return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
|
||||
}
|
||||
|
||||
/* exception-safe RAII wrapper for vertex buffer data (NOTE: not copy-safe) */
|
||||
struct VBDataPtr {
|
||||
gs_vb_data *data;
|
||||
|
||||
inline void Clear() {gs_vbdata_destroy(data); data = nullptr;}
|
||||
|
||||
inline VBDataPtr(gs_vb_data *data) : data(data) {}
|
||||
inline ~VBDataPtr() {gs_vbdata_destroy(data);}
|
||||
};
|
||||
|
||||
struct gs_vertex_buffer {
|
||||
ComPtr<ID3D11Buffer> vertexBuffer;
|
||||
ComPtr<ID3D11Buffer> normalBuffer;
|
||||
ComPtr<ID3D11Buffer> colorBuffer;
|
||||
ComPtr<ID3D11Buffer> tangentBuffer;
|
||||
vector<ComPtr<ID3D11Buffer>> uvBuffers;
|
||||
|
||||
gs_device_t *device;
|
||||
bool dynamic;
|
||||
VBDataPtr vbd;
|
||||
size_t numVerts;
|
||||
vector<size_t> uvSizes;
|
||||
|
||||
void FlushBuffer(ID3D11Buffer *buffer, void *array,
|
||||
size_t elementSize);
|
||||
|
||||
void MakeBufferList(gs_vertex_shader *shader,
|
||||
vector<ID3D11Buffer*> &buffers,
|
||||
vector<uint32_t> &strides);
|
||||
|
||||
inline void InitBuffer(const size_t elementSize,
|
||||
const size_t numVerts, void *array,
|
||||
ID3D11Buffer **buffer);
|
||||
|
||||
gs_vertex_buffer(gs_device_t *device, struct gs_vb_data *data,
|
||||
uint32_t flags);
|
||||
};
|
||||
|
||||
/* exception-safe RAII wrapper for index buffer data (NOTE: not copy-safe) */
|
||||
struct DataPtr {
|
||||
void *data;
|
||||
|
||||
inline DataPtr(void *data) : data(data) {}
|
||||
inline ~DataPtr() {bfree(data);}
|
||||
};
|
||||
|
||||
struct gs_index_buffer {
|
||||
ComPtr<ID3D11Buffer> indexBuffer;
|
||||
gs_device_t *device;
|
||||
bool dynamic;
|
||||
gs_index_type type;
|
||||
size_t indexSize;
|
||||
size_t num;
|
||||
DataPtr indices;
|
||||
|
||||
void InitBuffer();
|
||||
|
||||
gs_index_buffer(gs_device_t *device, enum gs_index_type type,
|
||||
void *indices, size_t num, uint32_t flags);
|
||||
};
|
||||
|
||||
struct gs_texture {
|
||||
gs_texture_type type;
|
||||
gs_device *device;
|
||||
uint32_t levels;
|
||||
gs_color_format format;
|
||||
|
||||
ComPtr<ID3D11ShaderResourceView> shaderRes;
|
||||
|
||||
inline gs_texture() {}
|
||||
|
||||
inline gs_texture(gs_device *device, gs_texture_type type,
|
||||
uint32_t levels, gs_color_format format)
|
||||
: type (type),
|
||||
device (device),
|
||||
levels (levels),
|
||||
format (format)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~gs_texture() {}
|
||||
};
|
||||
|
||||
struct gs_texture_2d : gs_texture {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11RenderTargetView> renderTarget[6];
|
||||
ComPtr<IDXGISurface1> gdiSurface;
|
||||
|
||||
uint32_t width = 0, height = 0;
|
||||
DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN;
|
||||
bool isRenderTarget = false;
|
||||
bool isGDICompatible = false;
|
||||
bool isDynamic = false;
|
||||
bool isShared = false;
|
||||
bool genMipmaps = false;
|
||||
uint32_t sharedHandle = 0;
|
||||
|
||||
void InitSRD(vector<D3D11_SUBRESOURCE_DATA> &srd, const uint8_t **data);
|
||||
void InitTexture(const uint8_t **data);
|
||||
void InitResourceView();
|
||||
void InitRenderTargets();
|
||||
|
||||
inline gs_texture_2d()
|
||||
: gs_texture (NULL, GS_TEXTURE_2D, 0, GS_UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
gs_texture_2d(gs_device_t *device, uint32_t width, uint32_t height,
|
||||
gs_color_format colorFormat, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags,
|
||||
gs_texture_type type, bool gdiCompatible, bool shared);
|
||||
|
||||
gs_texture_2d(gs_device_t *device, uint32_t handle);
|
||||
};
|
||||
|
||||
struct gs_zstencil_buffer {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
ComPtr<ID3D11DepthStencilView> view;
|
||||
|
||||
gs_device *device;
|
||||
uint32_t width, height;
|
||||
gs_zstencil_format format;
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
|
||||
void InitBuffer();
|
||||
|
||||
inline gs_zstencil_buffer()
|
||||
: device (NULL),
|
||||
width (0),
|
||||
height (0),
|
||||
dxgiFormat (DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
gs_zstencil_buffer(gs_device_t *device, uint32_t width, uint32_t height,
|
||||
gs_zstencil_format format);
|
||||
};
|
||||
|
||||
struct gs_stage_surface {
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
|
||||
gs_device *device;
|
||||
uint32_t width, height;
|
||||
gs_color_format format;
|
||||
DXGI_FORMAT dxgiFormat;
|
||||
|
||||
gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height,
|
||||
gs_color_format colorFormat);
|
||||
};
|
||||
|
||||
struct gs_sampler_state {
|
||||
ComPtr<ID3D11SamplerState> state;
|
||||
gs_device_t *device;
|
||||
gs_sampler_info info;
|
||||
|
||||
gs_sampler_state(gs_device_t *device, const gs_sampler_info *info);
|
||||
};
|
||||
|
||||
struct gs_shader_param {
|
||||
string name;
|
||||
gs_shader_param_type type;
|
||||
|
||||
uint32_t textureID;
|
||||
|
||||
int arrayCount;
|
||||
|
||||
size_t pos;
|
||||
|
||||
vector<uint8_t> curValue;
|
||||
vector<uint8_t> defaultValue;
|
||||
bool changed;
|
||||
|
||||
gs_shader_param(shader_var &var, uint32_t &texCounter);
|
||||
};
|
||||
|
||||
struct ShaderError {
|
||||
ComPtr<ID3D10Blob> errors;
|
||||
HRESULT hr;
|
||||
|
||||
inline ShaderError(const ComPtr<ID3D10Blob> &errors, HRESULT hr)
|
||||
: errors (errors),
|
||||
hr (hr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct gs_shader {
|
||||
gs_device_t *device;
|
||||
gs_shader_type type;
|
||||
vector<gs_shader_param> params;
|
||||
ComPtr<ID3D11Buffer> constants;
|
||||
size_t constantSize;
|
||||
|
||||
inline void UpdateParam(vector<uint8_t> &constData,
|
||||
gs_shader_param ¶m, bool &upload);
|
||||
void UploadParams();
|
||||
|
||||
void BuildConstantBuffer();
|
||||
void Compile(const char *shaderStr, const char *file,
|
||||
const char *target, ID3D10Blob **shader);
|
||||
|
||||
inline gs_shader(gs_device_t *device, gs_shader_type type)
|
||||
: device (device),
|
||||
type (type),
|
||||
constantSize (0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~gs_shader() {}
|
||||
};
|
||||
|
||||
struct ShaderSampler {
|
||||
string name;
|
||||
gs_sampler_state sampler;
|
||||
|
||||
inline ShaderSampler(const char *name, gs_device_t *device,
|
||||
gs_sampler_info *info)
|
||||
: name (name),
|
||||
sampler (device, info)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct gs_vertex_shader : gs_shader {
|
||||
ComPtr<ID3D11VertexShader> shader;
|
||||
ComPtr<ID3D11InputLayout> layout;
|
||||
|
||||
gs_shader_param *world, *viewProj;
|
||||
|
||||
bool hasNormals;
|
||||
bool hasColors;
|
||||
bool hasTangents;
|
||||
uint32_t nTexUnits;
|
||||
|
||||
inline uint32_t NumBuffersExpected() const
|
||||
{
|
||||
uint32_t count = nTexUnits+1;
|
||||
if (hasNormals) count++;
|
||||
if (hasColors) count++;
|
||||
if (hasTangents) count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void GetBuffersExpected(const vector<D3D11_INPUT_ELEMENT_DESC> &inputs);
|
||||
|
||||
gs_vertex_shader(gs_device_t *device, const char *file,
|
||||
const char *shaderString);
|
||||
};
|
||||
|
||||
struct gs_duplicator {
|
||||
ComPtr<IDXGIOutputDuplication> duplicator;
|
||||
gs_texture_2d *texture;
|
||||
gs_device_t *device;
|
||||
|
||||
gs_duplicator(gs_device_t *device, int monitor_idx);
|
||||
~gs_duplicator();
|
||||
};
|
||||
|
||||
struct gs_pixel_shader : gs_shader {
|
||||
ComPtr<ID3D11PixelShader> shader;
|
||||
vector<ShaderSampler> samplers;
|
||||
|
||||
inline void GetSamplerStates(ID3D11SamplerState **states)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < samplers.size(); i++)
|
||||
states[i] = samplers[i].sampler.state;
|
||||
for (; i < GS_MAX_TEXTURES; i++)
|
||||
states[i] = NULL;
|
||||
}
|
||||
|
||||
gs_pixel_shader(gs_device_t *device, const char *file,
|
||||
const char *shaderString);
|
||||
};
|
||||
|
||||
struct gs_swap_chain {
|
||||
gs_device *device;
|
||||
uint32_t numBuffers;
|
||||
HWND hwnd;
|
||||
|
||||
gs_texture_2d target;
|
||||
gs_zstencil_buffer zs;
|
||||
ComPtr<IDXGISwapChain> swap;
|
||||
|
||||
void InitTarget(uint32_t cx, uint32_t cy);
|
||||
void InitZStencilBuffer(uint32_t cx, uint32_t cy);
|
||||
void Resize(uint32_t cx, uint32_t cy);
|
||||
void Init(const gs_init_data *data);
|
||||
|
||||
inline gs_swap_chain()
|
||||
: device (NULL),
|
||||
numBuffers (0),
|
||||
hwnd (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
gs_swap_chain(gs_device *device, const gs_init_data *data);
|
||||
};
|
||||
|
||||
struct BlendState {
|
||||
bool blendEnabled;
|
||||
gs_blend_type srcFactorC;
|
||||
gs_blend_type destFactorC;
|
||||
gs_blend_type srcFactorA;
|
||||
gs_blend_type destFactorA;
|
||||
|
||||
bool redEnabled;
|
||||
bool greenEnabled;
|
||||
bool blueEnabled;
|
||||
bool alphaEnabled;
|
||||
|
||||
inline BlendState()
|
||||
: blendEnabled (true),
|
||||
srcFactorC (GS_BLEND_SRCALPHA),
|
||||
destFactorC (GS_BLEND_INVSRCALPHA),
|
||||
srcFactorA (GS_BLEND_ONE),
|
||||
destFactorA (GS_BLEND_ONE),
|
||||
redEnabled (true),
|
||||
greenEnabled (true),
|
||||
blueEnabled (true),
|
||||
alphaEnabled (true)
|
||||
{
|
||||
}
|
||||
|
||||
inline BlendState(const BlendState &state)
|
||||
{
|
||||
memcpy(this, &state, sizeof(BlendState));
|
||||
}
|
||||
};
|
||||
|
||||
struct SavedBlendState : BlendState {
|
||||
ComPtr<ID3D11BlendState> state;
|
||||
|
||||
inline SavedBlendState(const BlendState &val) : BlendState(val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct StencilSide {
|
||||
gs_depth_test test;
|
||||
gs_stencil_op_type fail;
|
||||
gs_stencil_op_type zfail;
|
||||
gs_stencil_op_type zpass;
|
||||
|
||||
inline StencilSide()
|
||||
: test (GS_ALWAYS),
|
||||
fail (GS_KEEP),
|
||||
zfail (GS_KEEP),
|
||||
zpass (GS_KEEP)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct ZStencilState {
|
||||
bool depthEnabled;
|
||||
bool depthWriteEnabled;
|
||||
gs_depth_test depthFunc;
|
||||
|
||||
bool stencilEnabled;
|
||||
bool stencilWriteEnabled;
|
||||
StencilSide stencilFront;
|
||||
StencilSide stencilBack;
|
||||
|
||||
inline ZStencilState()
|
||||
: depthEnabled (true),
|
||||
depthWriteEnabled (true),
|
||||
depthFunc (GS_LESS),
|
||||
stencilEnabled (false),
|
||||
stencilWriteEnabled (true)
|
||||
{
|
||||
}
|
||||
|
||||
inline ZStencilState(const ZStencilState &state)
|
||||
{
|
||||
memcpy(this, &state, sizeof(ZStencilState));
|
||||
}
|
||||
};
|
||||
|
||||
struct SavedZStencilState : ZStencilState {
|
||||
ComPtr<ID3D11DepthStencilState> state;
|
||||
|
||||
inline SavedZStencilState(const ZStencilState &val)
|
||||
: ZStencilState (val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct RasterState {
|
||||
gs_cull_mode cullMode;
|
||||
bool scissorEnabled;
|
||||
|
||||
inline RasterState()
|
||||
: cullMode (GS_BACK),
|
||||
scissorEnabled (false)
|
||||
{
|
||||
}
|
||||
|
||||
inline RasterState(const RasterState &state)
|
||||
{
|
||||
memcpy(this, &state, sizeof(RasterState));
|
||||
}
|
||||
};
|
||||
|
||||
struct SavedRasterState : RasterState {
|
||||
ComPtr<ID3D11RasterizerState> state;
|
||||
|
||||
inline SavedRasterState(const RasterState &val)
|
||||
: RasterState (val)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct mat4float {
|
||||
float mat[16];
|
||||
};
|
||||
|
||||
struct gs_device {
|
||||
ComPtr<IDXGIFactory1> factory;
|
||||
ComPtr<ID3D11Device> device;
|
||||
ComPtr<ID3D11DeviceContext> context;
|
||||
|
||||
gs_texture_2d *curRenderTarget = nullptr;
|
||||
gs_zstencil_buffer *curZStencilBuffer = nullptr;
|
||||
int curRenderSide = 0;
|
||||
gs_texture *curTextures[GS_MAX_TEXTURES];
|
||||
gs_sampler_state *curSamplers[GS_MAX_TEXTURES];
|
||||
gs_vertex_buffer *curVertexBuffer = nullptr;
|
||||
gs_index_buffer *curIndexBuffer = nullptr;
|
||||
gs_vertex_shader *curVertexShader = nullptr;
|
||||
gs_pixel_shader *curPixelShader = nullptr;
|
||||
gs_swap_chain *curSwapChain = nullptr;
|
||||
|
||||
bool zstencilStateChanged = true;
|
||||
bool rasterStateChanged = true;
|
||||
bool blendStateChanged = true;
|
||||
ZStencilState zstencilState;
|
||||
RasterState rasterState;
|
||||
BlendState blendState;
|
||||
vector<SavedZStencilState> zstencilStates;
|
||||
vector<SavedRasterState> rasterStates;
|
||||
vector<SavedBlendState> blendStates;
|
||||
ID3D11DepthStencilState *curDepthStencilState = nullptr;
|
||||
ID3D11RasterizerState *curRasterState = nullptr;
|
||||
ID3D11BlendState *curBlendState = nullptr;
|
||||
D3D11_PRIMITIVE_TOPOLOGY curToplogy;
|
||||
|
||||
pD3DCompile d3dCompile = nullptr;
|
||||
|
||||
gs_rect viewport;
|
||||
|
||||
vector<mat4float> projStack;
|
||||
|
||||
matrix4 curProjMatrix;
|
||||
matrix4 curViewMatrix;
|
||||
matrix4 curViewProjMatrix;
|
||||
|
||||
void InitCompiler();
|
||||
void InitFactory(uint32_t adapterIdx, IDXGIAdapter1 **adapter);
|
||||
void InitDevice(uint32_t adapterIdx, IDXGIAdapter *adapter);
|
||||
|
||||
ID3D11DepthStencilState *AddZStencilState();
|
||||
ID3D11RasterizerState *AddRasterState();
|
||||
ID3D11BlendState *AddBlendState();
|
||||
void UpdateZStencilState();
|
||||
void UpdateRasterState();
|
||||
void UpdateBlendState();
|
||||
|
||||
inline void 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);
|
||||
|
||||
void UpdateViewProjMatrix();
|
||||
|
||||
gs_device(uint32_t adapterIdx);
|
||||
};
|
||||
196
libobs-d3d11/d3d11-texture2d.cpp
Normal file
196
libobs-d3d11/d3d11-texture2d.cpp
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <util/base.h>
|
||||
#include "d3d11-subsystem.hpp"
|
||||
|
||||
void gs_texture_2d::InitSRD(vector<D3D11_SUBRESOURCE_DATA> &srd,
|
||||
const uint8_t **data)
|
||||
{
|
||||
uint32_t rowSizeBytes = width * gs_get_format_bpp(format);
|
||||
uint32_t texSizeBytes = height * rowSizeBytes / 8;
|
||||
size_t textures = type == GS_TEXTURE_2D ? 1 : 6;
|
||||
uint32_t actual_levels = levels;
|
||||
|
||||
if (!actual_levels)
|
||||
actual_levels = gs_get_total_levels(width, height);
|
||||
|
||||
rowSizeBytes /= 8;
|
||||
|
||||
for (size_t i = 0; i < textures; i++) {
|
||||
uint32_t newRowSize = rowSizeBytes;
|
||||
uint32_t newTexSize = texSizeBytes;
|
||||
|
||||
for (uint32_t j = 0; j < actual_levels; j++) {
|
||||
D3D11_SUBRESOURCE_DATA newSRD;
|
||||
newSRD.pSysMem = *data;
|
||||
newSRD.SysMemPitch = newRowSize;
|
||||
newSRD.SysMemSlicePitch = newTexSize;
|
||||
srd.push_back(newSRD);
|
||||
|
||||
newRowSize /= 2;
|
||||
newTexSize /= 4;
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitTexture(const uint8_t **data)
|
||||
{
|
||||
vector<D3D11_SUBRESOURCE_DATA> srd;
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&td, 0, sizeof(td));
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = genMipmaps ? 0 : levels;
|
||||
td.ArraySize = type == GS_TEXTURE_CUBE ? 6 : 1;
|
||||
td.Format = dxgiFormat;
|
||||
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.CPUAccessFlags = isDynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
td.Usage = isDynamic ? D3D11_USAGE_DYNAMIC :
|
||||
D3D11_USAGE_DEFAULT;
|
||||
|
||||
if (type == GS_TEXTURE_CUBE)
|
||||
td.MiscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
|
||||
|
||||
if (isRenderTarget || isGDICompatible)
|
||||
td.BindFlags |= D3D11_BIND_RENDER_TARGET;
|
||||
|
||||
if (isGDICompatible)
|
||||
td.MiscFlags |= D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
|
||||
|
||||
if (data)
|
||||
InitSRD(srd, data);
|
||||
|
||||
hr = device->device->CreateTexture2D(&td, data ? srd.data() : NULL,
|
||||
texture.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create 2D texture", hr);
|
||||
|
||||
if (isGDICompatible) {
|
||||
hr = texture->QueryInterface(__uuidof(IDXGISurface1),
|
||||
(void**)gdiSurface.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create GDI surface", hr);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitResourceView()
|
||||
{
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC resourceDesc;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&resourceDesc, 0, sizeof(resourceDesc));
|
||||
resourceDesc.Format = dxgiFormat;
|
||||
|
||||
if (type == GS_TEXTURE_CUBE) {
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
||||
resourceDesc.TextureCube.MipLevels = genMipmaps ? -1 : 1;
|
||||
} else {
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceDesc.Texture2D.MipLevels = genMipmaps ? -1 : 1;
|
||||
}
|
||||
|
||||
hr = device->device->CreateShaderResourceView(texture, &resourceDesc,
|
||||
shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create resource view", hr);
|
||||
}
|
||||
|
||||
void gs_texture_2d::InitRenderTargets()
|
||||
{
|
||||
HRESULT hr;
|
||||
if (type == GS_TEXTURE_2D) {
|
||||
hr = device->device->CreateRenderTargetView(texture, NULL,
|
||||
renderTarget[0].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create render target view",
|
||||
hr);
|
||||
} else {
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv;
|
||||
rtv.Format = dxgiFormat;
|
||||
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
rtv.Texture2DArray.MipSlice = 0;
|
||||
rtv.Texture2DArray.ArraySize = 1;
|
||||
|
||||
for (UINT i = 0; i < 6; i++) {
|
||||
rtv.Texture2DArray.FirstArraySlice = i;
|
||||
hr = device->device->CreateRenderTargetView(texture,
|
||||
&rtv, renderTarget[i].Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create cube render "
|
||||
"target view", hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t width,
|
||||
uint32_t height, gs_color_format colorFormat, uint32_t levels,
|
||||
const uint8_t **data, uint32_t flags, gs_texture_type type,
|
||||
bool gdiCompatible, bool shared)
|
||||
: gs_texture (device, type, levels, colorFormat),
|
||||
width (width),
|
||||
height (height),
|
||||
dxgiFormat (ConvertGSTextureFormat(format)),
|
||||
isRenderTarget ((flags & GS_RENDER_TARGET) != 0),
|
||||
isGDICompatible (gdiCompatible),
|
||||
isDynamic ((flags & GS_DYNAMIC) != 0),
|
||||
isShared (shared),
|
||||
genMipmaps ((flags & GS_BUILD_MIPMAPS) != 0)
|
||||
{
|
||||
InitTexture(data);
|
||||
InitResourceView();
|
||||
|
||||
if (isRenderTarget)
|
||||
InitRenderTargets();
|
||||
}
|
||||
|
||||
gs_texture_2d::gs_texture_2d(gs_device_t *device, uint32_t handle)
|
||||
: isShared (true),
|
||||
sharedHandle (handle)
|
||||
{
|
||||
HRESULT hr;
|
||||
hr = device->device->OpenSharedResource((HANDLE)(uintptr_t)handle,
|
||||
__uuidof(ID3D11Texture2D), (void**)texture.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to open resource", hr);
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture->GetDesc(&desc);
|
||||
|
||||
this->type = GS_TEXTURE_2D;
|
||||
this->format = ConvertDXGITextureFormat(desc.Format);
|
||||
this->levels = 1;
|
||||
this->device = device;
|
||||
|
||||
this->width = desc.Width;
|
||||
this->height = desc.Height;
|
||||
this->dxgiFormat = desc.Format;
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC resourceDesc = {};
|
||||
resourceDesc.Format = desc.Format;
|
||||
resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
resourceDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
hr = device->device->CreateShaderResourceView(texture, &resourceDesc,
|
||||
shaderRes.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create shader resource view", hr);
|
||||
}
|
||||
141
libobs-d3d11/d3d11-vertexbuffer.cpp
Normal file
141
libobs-d3d11/d3d11-vertexbuffer.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <util/base.h>
|
||||
#include <graphics/vec3.h>
|
||||
#include "d3d11-subsystem.hpp"
|
||||
|
||||
static inline void PushBuffer(vector<ID3D11Buffer*> &buffers,
|
||||
vector<uint32_t> &strides, ID3D11Buffer *buffer,
|
||||
size_t elementSize, const char *name)
|
||||
{
|
||||
if (buffer) {
|
||||
buffers.push_back(buffer);
|
||||
strides.push_back((uint32_t)elementSize);
|
||||
} else {
|
||||
blog(LOG_ERROR, "This vertex shader requires a %s buffer",
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
void gs_vertex_buffer::FlushBuffer(ID3D11Buffer *buffer, void *array,
|
||||
size_t elementSize)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE msr;
|
||||
HRESULT hr;
|
||||
|
||||
if (FAILED(hr = device->context->Map(buffer, 0,
|
||||
D3D11_MAP_WRITE_DISCARD, 0, &msr)))
|
||||
throw HRError("Failed to map buffer", hr);
|
||||
|
||||
memcpy(msr.pData, array, elementSize * vbd.data->num);
|
||||
device->context->Unmap(buffer, 0);
|
||||
}
|
||||
|
||||
void gs_vertex_buffer::MakeBufferList(gs_vertex_shader *shader,
|
||||
vector<ID3D11Buffer*> &buffers, vector<uint32_t> &strides)
|
||||
{
|
||||
PushBuffer(buffers, strides, vertexBuffer, sizeof(vec3), "point");
|
||||
|
||||
if (shader->hasNormals)
|
||||
PushBuffer(buffers, strides, normalBuffer, sizeof(vec3),
|
||||
"normal");
|
||||
if (shader->hasColors)
|
||||
PushBuffer(buffers, strides, colorBuffer, sizeof(uint32_t),
|
||||
"color");
|
||||
if (shader->hasTangents)
|
||||
PushBuffer(buffers, strides, tangentBuffer, sizeof(vec3),
|
||||
"tangent");
|
||||
if (shader->nTexUnits <= uvBuffers.size()) {
|
||||
for (size_t i = 0; i < shader->nTexUnits; i++) {
|
||||
buffers.push_back(uvBuffers[i]);
|
||||
strides.push_back((uint32_t)uvSizes[i]);
|
||||
}
|
||||
} else {
|
||||
blog(LOG_ERROR, "This vertex shader requires at least %u "
|
||||
"texture buffers.",
|
||||
(uint32_t)shader->nTexUnits);
|
||||
}
|
||||
}
|
||||
|
||||
inline void gs_vertex_buffer::InitBuffer(const size_t elementSize,
|
||||
const size_t numVerts, void *array, ID3D11Buffer **buffer)
|
||||
{
|
||||
D3D11_BUFFER_DESC bd;
|
||||
D3D11_SUBRESOURCE_DATA srd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&bd, 0, sizeof(bd));
|
||||
memset(&srd, 0, sizeof(srd));
|
||||
|
||||
bd.Usage = dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
|
||||
bd.CPUAccessFlags = dynamic ? D3D11_CPU_ACCESS_WRITE : 0;
|
||||
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
bd.ByteWidth = UINT(elementSize * numVerts);
|
||||
srd.pSysMem = array;
|
||||
|
||||
hr = device->device->CreateBuffer(&bd, &srd, buffer);
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create buffer", hr);
|
||||
}
|
||||
|
||||
gs_vertex_buffer::gs_vertex_buffer(gs_device_t *device, struct gs_vb_data *data,
|
||||
uint32_t flags)
|
||||
: device (device),
|
||||
dynamic ((flags & GS_DYNAMIC) != 0),
|
||||
vbd (data),
|
||||
numVerts (data->num)
|
||||
{
|
||||
if (!data->num)
|
||||
throw "Cannot initialize vertex buffer with 0 vertices";
|
||||
if (!data->points)
|
||||
throw "No points specified for vertex buffer";
|
||||
|
||||
InitBuffer(sizeof(vec3), data->num, data->points,
|
||||
vertexBuffer.Assign());
|
||||
|
||||
if (data->normals)
|
||||
InitBuffer(sizeof(vec3), data->num, data->normals,
|
||||
normalBuffer.Assign());
|
||||
|
||||
if (data->tangents)
|
||||
InitBuffer(sizeof(vec3), data->num, data->tangents,
|
||||
tangentBuffer.Assign());
|
||||
|
||||
if (data->colors)
|
||||
InitBuffer(sizeof(uint32_t), data->num, data->colors,
|
||||
colorBuffer.Assign());
|
||||
|
||||
for (size_t i = 0; i < data->num_tex; i++) {
|
||||
struct gs_tvertarray *tverts = data->tvarray+i;
|
||||
|
||||
if (tverts->width != 2 && tverts->width != 4)
|
||||
throw "Invalid texture vertex size specified";
|
||||
if (!tverts->array)
|
||||
throw "No texture vertices specified";
|
||||
|
||||
ComPtr<ID3D11Buffer> buffer;
|
||||
InitBuffer(tverts->width * sizeof(float), data->num,
|
||||
tverts->array, buffer.Assign());
|
||||
|
||||
uvBuffers.push_back(buffer);
|
||||
uvSizes.push_back(tverts->width * sizeof(float));
|
||||
}
|
||||
|
||||
if (!dynamic)
|
||||
vbd.Clear();
|
||||
}
|
||||
60
libobs-d3d11/d3d11-zstencilbuffer.cpp
Normal file
60
libobs-d3d11/d3d11-zstencilbuffer.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/******************************************************************************
|
||||
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
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11-subsystem.hpp"
|
||||
|
||||
void gs_zstencil_buffer::InitBuffer()
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC dsvd;
|
||||
HRESULT hr;
|
||||
|
||||
memset(&td, 0, sizeof(td));
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = 1;
|
||||
td.ArraySize = 1;
|
||||
td.Format = dxgiFormat;
|
||||
td.BindFlags = D3D11_BIND_DEPTH_STENCIL;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.Usage = D3D11_USAGE_DEFAULT;
|
||||
|
||||
hr = device->device->CreateTexture2D(&td, NULL, texture.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create depth stencil texture", hr);
|
||||
|
||||
memset(&dsvd, 0, sizeof(dsvd));
|
||||
dsvd.Format = dxgiFormat;
|
||||
dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
|
||||
hr = device->device->CreateDepthStencilView(texture, &dsvd,
|
||||
view.Assign());
|
||||
if (FAILED(hr))
|
||||
throw HRError("Failed to create depth stencil view", hr);
|
||||
}
|
||||
|
||||
gs_zstencil_buffer::gs_zstencil_buffer(gs_device_t *device,
|
||||
uint32_t width, uint32_t height,
|
||||
gs_zstencil_format format)
|
||||
: device (device),
|
||||
width (width),
|
||||
height (height),
|
||||
format (format),
|
||||
dxgiFormat (ConvertGSZStencilFormat(format))
|
||||
{
|
||||
InitBuffer();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue