Imported Upstream version 0.13.2+dsfg1

This commit is contained in:
Sebastian Ramacher 2016-02-24 00:16:51 +01:00
commit fb3990e9e5
2036 changed files with 287360 additions and 0 deletions

View 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)

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

View 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();
}

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

View 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 &param = 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(&params[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 &param, 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 &param = shader->params[i];
if (strcmp(param.name.c_str(), name) == 0)
return &param;
}
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());
}

View 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> &params,
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> &params)
{
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";
}

View 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> &params);
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)
{
}
};

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

File diff suppressed because it is too large Load diff

View 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 &param, 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);
};

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

View 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();
}

View 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();
}