mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-06 05:37:48 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,669 @@
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "GeometryD3D11.h"
|
||||
#include "ShaderD3D11.h"
|
||||
#include "TextureD3D11.h"
|
||||
#include "FramebufferD3D11.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
|
||||
FASTFLAG(GraphicsDebugMarkersEnable)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
static const D3D11_CULL_MODE gCullModeD3D11[RasterizerState::Cull_Count] =
|
||||
{
|
||||
D3D11_CULL_NONE,
|
||||
D3D11_CULL_BACK,
|
||||
D3D11_CULL_FRONT
|
||||
};
|
||||
|
||||
struct BlendFuncD3D11
|
||||
{
|
||||
D3D11_BLEND src, dst;
|
||||
};
|
||||
|
||||
static const D3D11_BLEND gBlendFactors[BlendState::Factor_Count] =
|
||||
{
|
||||
D3D11_BLEND_ONE,
|
||||
D3D11_BLEND_ZERO,
|
||||
D3D11_BLEND_DEST_COLOR,
|
||||
D3D11_BLEND_SRC_ALPHA,
|
||||
D3D11_BLEND_INV_SRC_ALPHA,
|
||||
D3D11_BLEND_DEST_ALPHA,
|
||||
D3D11_BLEND_INV_DEST_ALPHA
|
||||
};
|
||||
|
||||
static const D3D11_COMPARISON_FUNC gDepthFuncD3D11[DepthState::Function_Count] =
|
||||
{
|
||||
D3D11_COMPARISON_ALWAYS,
|
||||
D3D11_COMPARISON_LESS,
|
||||
D3D11_COMPARISON_LESS_EQUAL
|
||||
};
|
||||
|
||||
static const D3D11_FILTER gSamplerFilterD3D11[SamplerState::Filter_Count] =
|
||||
{
|
||||
D3D11_FILTER_MIN_MAG_MIP_POINT,
|
||||
D3D11_FILTER_MIN_MAG_MIP_LINEAR,
|
||||
D3D11_FILTER_ANISOTROPIC,
|
||||
};
|
||||
|
||||
static const D3D11_TEXTURE_ADDRESS_MODE gSamplerAddressD3D11[SamplerState::Address_Count] =
|
||||
{
|
||||
D3D11_TEXTURE_ADDRESS_WRAP,
|
||||
D3D11_TEXTURE_ADDRESS_CLAMP
|
||||
};
|
||||
|
||||
DeviceContextD3D11::DeviceContextD3D11(Device* device, ID3D11DeviceContext* deviceContext11)
|
||||
: device(device)
|
||||
, device11(static_cast<DeviceD3D11*>(device)->getDevice11())
|
||||
, globalDataSize(0)
|
||||
, defaultAnisotropy(1)
|
||||
, cachedProgram(NULL)
|
||||
, cachedVertexLayout(NULL)
|
||||
, cachedGeometry(NULL)
|
||||
, cachedFramebuffer(NULL)
|
||||
, cachedRasterizerState(RasterizerState::Cull_None)
|
||||
, cachedBlendState(BlendState::Mode_None)
|
||||
, cachedDepthState(DepthState::Function_Always, false)
|
||||
, globalsConstantBuffer(NULL)
|
||||
, d3d9(NULL)
|
||||
{
|
||||
immediateContext11 = deviceContext11;
|
||||
|
||||
// markers, we are going oldschool here. It works for RenderDoc too
|
||||
pfn_D3DPERF_BeginEvent = 0;
|
||||
pfn_D3DPERF_EndEvent = 0;
|
||||
pfn_D3DPERF_SetMarker = 0;
|
||||
|
||||
DWORD (WINAPI *pfn_D3DPERF_GetStatus)() = 0;
|
||||
|
||||
if(PIX_ENABLED)
|
||||
{
|
||||
d3d9 = LoadLibraryW(L"d3d9.dll");
|
||||
if (d3d9)
|
||||
{
|
||||
(void*&)pfn_D3DPERF_BeginEvent = GetProcAddress(d3d9, "D3DPERF_BeginEvent");
|
||||
(void*&)pfn_D3DPERF_EndEvent = GetProcAddress(d3d9, "D3DPERF_EndEvent");
|
||||
(void*&)pfn_D3DPERF_SetMarker = GetProcAddress(d3d9, "D3DPERF_SetMarker");
|
||||
(void*&)pfn_D3DPERF_GetStatus = GetProcAddress(d3d9, "D3DPERF_GetStatus");
|
||||
}
|
||||
}
|
||||
|
||||
if( !pfn_D3DPERF_GetStatus || !pfn_D3DPERF_GetStatus() )
|
||||
{
|
||||
FFlag::GraphicsDebugMarkersEnable = false; // no use
|
||||
}
|
||||
}
|
||||
|
||||
DeviceContextD3D11::~DeviceContextD3D11()
|
||||
{
|
||||
if (d3d9)
|
||||
{
|
||||
FreeLibrary(d3d9);
|
||||
d3d9 = NULL;
|
||||
}
|
||||
|
||||
ReleaseCheck(immediateContext11);
|
||||
ReleaseCheck(globalsConstantBuffer);
|
||||
|
||||
for (RasterizerStateHash::iterator it = rasterizerStateHash.begin(); it != rasterizerStateHash.end(); ++it)
|
||||
ReleaseCheck(it->second);
|
||||
for (BlendStateHash::iterator it = blendStateHash.begin(); it != blendStateHash.end(); ++it)
|
||||
ReleaseCheck(it->second);
|
||||
for (DepthStateHash::iterator it = depthStateHash.begin(); it != depthStateHash.end(); ++it)
|
||||
ReleaseCheck(it->second);
|
||||
for (SamplerStateHash::iterator it = samplerStateHash.begin(); it != samplerStateHash.end(); ++it)
|
||||
ReleaseCheck(it->second);
|
||||
|
||||
rasterizerStateHash.clear();
|
||||
samplerStateHash.clear();
|
||||
depthStateHash.clear();
|
||||
blendStateHash.clear();
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::defineGlobalConstants(size_t dataSize)
|
||||
{
|
||||
RBXASSERT(globalsConstantBuffer == NULL);
|
||||
if (globalsConstantBuffer)
|
||||
return;
|
||||
|
||||
D3D11_BUFFER_DESC bd = {};
|
||||
bd.Usage = D3D11_USAGE_DEFAULT;
|
||||
bd.ByteWidth = dataSize;
|
||||
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
bd.CPUAccessFlags = 0;
|
||||
bd.StructureByteStride = 0;
|
||||
bd.MiscFlags = 0;
|
||||
|
||||
globalDataSize = dataSize;
|
||||
|
||||
HRESULT hr = device11->CreateBuffer( &bd, NULL, &globalsConstantBuffer );
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::updateGlobalConstants(const void* data, size_t dataSize)
|
||||
{
|
||||
RBXASSERT(dataSize == globalDataSize);
|
||||
|
||||
immediateContext11->UpdateSubresource(globalsConstantBuffer, 0, NULL, data, 0, 0);
|
||||
|
||||
immediateContext11->VSSetConstantBuffers( 0, 1, &globalsConstantBuffer);
|
||||
immediateContext11->PSSetConstantBuffers( 0, 1, &globalsConstantBuffer);
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::bindFramebuffer(Framebuffer* buffer)
|
||||
{
|
||||
FramebufferD3D11* buffer11 = static_cast<FramebufferD3D11*>(buffer);
|
||||
|
||||
const std::vector<shared_ptr<Renderbuffer> >& color = buffer11->getColor();
|
||||
const shared_ptr<Renderbuffer>& depth = buffer11->getDepth();
|
||||
|
||||
ID3D11RenderTargetView* rtArray[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
|
||||
for(size_t i = 0; i < color.size(); ++i)
|
||||
{
|
||||
RenderbufferD3D11* rb = static_cast<RenderbufferD3D11*>(color[i].get());
|
||||
rtArray[i] = static_cast<ID3D11RenderTargetView*>(rb->getObject());
|
||||
|
||||
// unbind texture if bound as SRV
|
||||
const shared_ptr<TextureD3D11>& ownerTex = rb->getOwner();
|
||||
|
||||
if (ownerTex)
|
||||
{
|
||||
for (size_t i = 0; i < ARRAYSIZE(cachedTextureUnits); ++i)
|
||||
{
|
||||
TextureUnit& u = cachedTextureUnits[i];
|
||||
if (u.texture == ownerTex.get())
|
||||
{
|
||||
ID3D11ShaderResourceView* nullSRV = NULL;
|
||||
immediateContext11->PSSetShaderResources(i, 1, &nullSRV);
|
||||
u.texture = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RenderbufferD3D11* dsBuffer = static_cast<RenderbufferD3D11*>(depth.get());
|
||||
ID3D11DepthStencilView* dsv = dsBuffer ? static_cast<ID3D11DepthStencilView*>(dsBuffer->getObject()) : NULL;
|
||||
|
||||
immediateContext11->OMSetRenderTargets( color.size(), rtArray, dsv);
|
||||
|
||||
cachedFramebuffer = buffer;
|
||||
|
||||
D3D11_VIEWPORT vp = {};
|
||||
vp.Width = (FLOAT)buffer->getWidth();
|
||||
vp.Height = (FLOAT)buffer->getHeight();
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
immediateContext11->RSSetViewports( 1, &vp );
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::setWorldTransforms4x3(const float* data, size_t matrixCount)
|
||||
{
|
||||
RBXASSERT(cachedProgram);
|
||||
|
||||
cachedProgram->setWorldTransforms4x3(data, matrixCount);
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::setConstant(int handle, const float* data, size_t vectorCount)
|
||||
{
|
||||
RBXASSERT(cachedProgram);
|
||||
|
||||
cachedProgram->setConstant(handle, data, vectorCount);
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::setRasterizerState(const RasterizerState& state)
|
||||
{
|
||||
bool depthBiasSupported = static_cast<DeviceD3D11*>(device)->getShaderProfile() == DeviceD3D11::shaderProfile_DX11;
|
||||
|
||||
RasterizerState realState = state;
|
||||
if (!depthBiasSupported)
|
||||
realState = RasterizerState(state.getCullMode(), 0);
|
||||
|
||||
if (realState != cachedRasterizerState)
|
||||
{
|
||||
ID3D11RasterizerState* state11 = rasterizerStateHash[realState];
|
||||
|
||||
if (!state11)
|
||||
{
|
||||
D3D11_RASTERIZER_DESC rastStateDesc = {};
|
||||
|
||||
float slopeBias = static_cast<float>(realState.getDepthBias()) / 32.f; // do we need explicit control over slope or just a better formula since these numbers are magic anyway?
|
||||
|
||||
rastStateDesc.FillMode = D3D11_FILL_SOLID;
|
||||
rastStateDesc.CullMode = gCullModeD3D11[realState.getCullMode()];
|
||||
rastStateDesc.FrontCounterClockwise = true;
|
||||
rastStateDesc.DepthBias = realState.getDepthBias();;
|
||||
rastStateDesc.DepthBiasClamp = 0;
|
||||
rastStateDesc.SlopeScaledDepthBias = slopeBias;
|
||||
rastStateDesc.DepthClipEnable = true;
|
||||
rastStateDesc.ScissorEnable = false;
|
||||
rastStateDesc.MultisampleEnable = false;
|
||||
rastStateDesc.AntialiasedLineEnable = false;
|
||||
|
||||
HRESULT hr = device11->CreateRasterizerState( &rastStateDesc, &state11);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
checkDuplicates(rasterizerStateHash, state11);
|
||||
rasterizerStateHash[realState] = state11;
|
||||
}
|
||||
|
||||
immediateContext11->RSSetState(state11);
|
||||
cachedRasterizerState = realState;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::setBlendState(const BlendState& state)
|
||||
{
|
||||
if (cachedBlendState != state)
|
||||
{
|
||||
ID3D11BlendState* state11 = blendStateHash[state];
|
||||
|
||||
if (!state11)
|
||||
{
|
||||
D3D11_BLEND_DESC blendStateDesc = {};
|
||||
|
||||
blendStateDesc.AlphaToCoverageEnable = false;
|
||||
blendStateDesc.IndependentBlendEnable = false;
|
||||
|
||||
if (!state.blendingNeeded())
|
||||
{
|
||||
blendStateDesc.RenderTarget[0].BlendEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
blendStateDesc.RenderTarget[0].BlendEnable = true;
|
||||
blendStateDesc.RenderTarget[0].SrcBlend = gBlendFactors[state.getColorSrc()];
|
||||
blendStateDesc.RenderTarget[0].SrcBlendAlpha = gBlendFactors[state.getAlphaSrc()];
|
||||
blendStateDesc.RenderTarget[0].DestBlend = gBlendFactors[state.getColorDst()];
|
||||
blendStateDesc.RenderTarget[0].DestBlendAlpha = gBlendFactors[state.getAlphaDst()];
|
||||
blendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
blendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
}
|
||||
|
||||
unsigned int colorMask = 0;
|
||||
|
||||
if (state.getColorMask() & BlendState::Color_R)
|
||||
colorMask |= D3D11_COLOR_WRITE_ENABLE_RED;
|
||||
|
||||
if (state.getColorMask() & BlendState::Color_G)
|
||||
colorMask |= D3D11_COLOR_WRITE_ENABLE_GREEN;
|
||||
|
||||
if (state.getColorMask() & BlendState::Color_B)
|
||||
colorMask |= D3D11_COLOR_WRITE_ENABLE_BLUE;
|
||||
|
||||
if (state.getColorMask() & BlendState::Color_A)
|
||||
colorMask |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
|
||||
|
||||
blendStateDesc.RenderTarget[0].RenderTargetWriteMask = colorMask;
|
||||
|
||||
HRESULT hr = device11->CreateBlendState(&blendStateDesc, &state11);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
checkDuplicates(blendStateHash, state11);
|
||||
blendStateHash[state] = state11;
|
||||
}
|
||||
|
||||
float blendFactor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
UINT sampleMask = 0xffffffff;
|
||||
|
||||
immediateContext11->OMSetBlendState(state11, blendFactor, sampleMask);
|
||||
cachedBlendState = state;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::setDepthState(const DepthState& state)
|
||||
{
|
||||
if (cachedDepthState != state)
|
||||
{
|
||||
ID3D11DepthStencilState* state11 = depthStateHash[state];
|
||||
|
||||
if (!state11)
|
||||
{
|
||||
D3D11_DEPTH_STENCIL_DESC dsDesc = {};
|
||||
|
||||
if (state.getFunction() == DepthState::Function_Always && state.getWrite() == false)
|
||||
{
|
||||
dsDesc.DepthEnable = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
dsDesc.DepthEnable = true;
|
||||
dsDesc.DepthFunc = gDepthFuncD3D11[state.getFunction()];
|
||||
dsDesc.DepthWriteMask = state.getWrite() ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
}
|
||||
|
||||
dsDesc.StencilReadMask = 0xFF;
|
||||
dsDesc.StencilWriteMask = 0xFF;
|
||||
|
||||
switch (state.getStencilMode())
|
||||
{
|
||||
case DepthState::Stencil_None:
|
||||
dsDesc.StencilEnable = false;
|
||||
break;
|
||||
|
||||
case DepthState::Stencil_IsNotZero:
|
||||
dsDesc.StencilEnable = true;
|
||||
|
||||
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_NOT_EQUAL;
|
||||
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
|
||||
|
||||
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_NOT_EQUAL;
|
||||
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
|
||||
break;
|
||||
|
||||
case DepthState::Stencil_UpdateZFail:
|
||||
dsDesc.StencilEnable = true;
|
||||
|
||||
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
|
||||
|
||||
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
|
||||
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
|
||||
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
|
||||
break;
|
||||
}
|
||||
|
||||
HRESULT hr = device11->CreateDepthStencilState(&dsDesc, &state11);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
checkDuplicates(depthStateHash, state11);
|
||||
depthStateHash[state] = state11;
|
||||
}
|
||||
|
||||
immediateContext11->OMSetDepthStencilState(state11, 0);
|
||||
cachedDepthState = state;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::clearStates()
|
||||
{
|
||||
// Clear framebuffer cache
|
||||
cachedFramebuffer = NULL;
|
||||
|
||||
// Clear program cache
|
||||
cachedProgram = NULL;
|
||||
|
||||
// Clear vertex layout cache
|
||||
cachedVertexLayout = NULL;
|
||||
|
||||
// Clear geometry cache
|
||||
cachedGeometry = NULL;
|
||||
|
||||
// Clear texture cache
|
||||
for (size_t i = 0; i < ARRAYSIZE(cachedTextureUnits); ++i)
|
||||
{
|
||||
TextureUnit& u = cachedTextureUnits[i];
|
||||
|
||||
u.texture = NULL;
|
||||
|
||||
// Clear state to an invalid value to guarantee a cache miss on the next setup
|
||||
u.samplerState = SamplerState::Filter_Count;
|
||||
}
|
||||
|
||||
// unset all textures (SRVs) from shader
|
||||
ID3D11ShaderResourceView* nullSRVs[ARRAYSIZE(cachedTextureUnits)] = {};
|
||||
|
||||
immediateContext11->PSSetShaderResources(0, ARRAYSIZE(cachedTextureUnits), nullSRVs);
|
||||
|
||||
// Clear states to invalid values to guarantee a cache miss on the next setup
|
||||
cachedRasterizerState = RasterizerState(RasterizerState::Cull_Count);
|
||||
cachedBlendState = BlendState(BlendState::Mode_Count);
|
||||
cachedDepthState = DepthState(DepthState::Function_Count, false);
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::setDefaultAnisotropy(unsigned int value)
|
||||
{
|
||||
defaultAnisotropy = value;
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::bindTexture(unsigned int stage, Texture* texture, const SamplerState& state)
|
||||
{
|
||||
SamplerState realState =
|
||||
(state.getFilter() == SamplerState::Filter_Anisotropic && state.getAnisotropy() == 0)
|
||||
? SamplerState(state.getFilter(), state.getAddress(), defaultAnisotropy)
|
||||
: state;
|
||||
|
||||
RBXASSERT(stage < device->getCaps().maxTextureUnits);
|
||||
RBXASSERT(stage < ARRAYSIZE(cachedTextureUnits));
|
||||
|
||||
TextureUnit& u = cachedTextureUnits[stage];
|
||||
|
||||
TextureD3D11* texture11 = static_cast<TextureD3D11*>(texture);
|
||||
if (u.texture != texture11)
|
||||
{
|
||||
ID3D11ShaderResourceView* srv = texture11->getSRV();
|
||||
immediateContext11->PSSetShaderResources(stage, 1, &srv);
|
||||
|
||||
u.texture = texture11;
|
||||
}
|
||||
|
||||
if (u.samplerState != realState)
|
||||
{
|
||||
|
||||
ID3D11SamplerState* samplerState = samplerStateHash[realState];
|
||||
|
||||
if (!samplerState)
|
||||
{
|
||||
D3D11_SAMPLER_DESC samplerDesc = {};
|
||||
|
||||
samplerDesc.AddressU = gSamplerAddressD3D11[realState.getAddress()];
|
||||
samplerDesc.AddressV = gSamplerAddressD3D11[realState.getAddress()];
|
||||
samplerDesc.AddressW = gSamplerAddressD3D11[realState.getAddress()];
|
||||
samplerDesc.Filter = gSamplerFilterD3D11[realState.getFilter()];
|
||||
samplerDesc.MaxAnisotropy = realState.getAnisotropy();
|
||||
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
samplerDesc.MaxLOD = FLT_MAX;
|
||||
|
||||
HRESULT hr = device11->CreateSamplerState(&samplerDesc, &samplerState);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
checkDuplicates(samplerStateHash, samplerState);
|
||||
samplerStateHash[realState] = samplerState;
|
||||
}
|
||||
|
||||
immediateContext11->PSSetSamplers(stage, 1, &samplerState);
|
||||
u.samplerState = realState;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::drawImpl(Geometry* geometry, Geometry::Primitive primitive, unsigned int offset, unsigned int count, unsigned int indexRangeBegin, unsigned int indexRangeEnd)
|
||||
{
|
||||
static_cast<GeometryD3D11*>(geometry)->draw(primitive, offset, count, indexRangeBegin, indexRangeEnd, &cachedVertexLayout, &cachedGeometry, &cachedProgram);
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::bindProgram(ShaderProgram* program)
|
||||
{
|
||||
if (cachedProgram != program)
|
||||
{
|
||||
cachedProgram = static_cast<ShaderProgramD3D11*>(program);
|
||||
cachedProgram->bind();
|
||||
cachedVertexLayout = NULL; // VertexLayout is per vertex shader
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11DeviceContext* DeviceContextD3D11::getContextDX11()
|
||||
{
|
||||
return immediateContext11;
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::clearFramebuffer(unsigned int mask, const float color[4], float depth, unsigned int stencil)
|
||||
{
|
||||
RBXASSERT(cachedFramebuffer);
|
||||
|
||||
FramebufferD3D11* buffer11 = static_cast<FramebufferD3D11*>(cachedFramebuffer);
|
||||
|
||||
if (mask & Buffer_Color)
|
||||
{
|
||||
const std::vector<shared_ptr<Renderbuffer> >& colorBuf = buffer11->getColor();
|
||||
for(size_t i = 0; i < colorBuf.size(); ++i)
|
||||
{
|
||||
RenderbufferD3D11* rb = static_cast<RenderbufferD3D11*>(colorBuf[i].get());
|
||||
ID3D11RenderTargetView* rtv = static_cast<ID3D11RenderTargetView*>(rb->getObject());
|
||||
immediateContext11->ClearRenderTargetView(rtv, color);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & (Buffer_Depth | Buffer_Stencil))
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
if (mask & Buffer_Depth)
|
||||
flags |= D3D11_CLEAR_DEPTH;
|
||||
|
||||
if (mask & Buffer_Stencil)
|
||||
flags |= D3D11_CLEAR_STENCIL;
|
||||
|
||||
RenderbufferD3D11* dsBuffer = static_cast<RenderbufferD3D11*>(buffer11->getDepth().get());
|
||||
ID3D11DepthStencilView* dsv = static_cast<ID3D11DepthStencilView*>(dsBuffer->getObject());
|
||||
|
||||
immediateContext11->ClearDepthStencilView(dsv, flags, depth, stencil);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::copyFramebuffer(Framebuffer* buffer, Texture* texture)
|
||||
{
|
||||
FramebufferD3D11* fb = static_cast<FramebufferD3D11*>(buffer);
|
||||
RBXASSERT(fb->getColor().size() > 0);
|
||||
RenderbufferD3D11* color0 = static_cast<RenderbufferD3D11*>(fb->getColor()[0].get());
|
||||
|
||||
RBXASSERT(texture->getType() == Texture::Type_2D);
|
||||
RBXASSERT(texture->getMipLevels() == 1);
|
||||
RBXASSERT(color0->getWidth() == texture->getWidth() && color0->getHeight() == texture->getHeight());
|
||||
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
context11->CopyResource(static_cast<TextureD3D11*>(texture)->getObject(), color0->getResource());
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::resolveFramebuffer(Framebuffer* msaaBuffer, Framebuffer* buffer, unsigned int mask)
|
||||
{
|
||||
RBXASSERT(msaaBuffer->getSamples() > 1);
|
||||
RBXASSERT(buffer->getSamples() == 1);
|
||||
RBXASSERT(msaaBuffer->getWidth() == buffer->getWidth() && msaaBuffer->getHeight() == buffer->getHeight());
|
||||
|
||||
FramebufferD3D11* msaaBuffer11 = static_cast<FramebufferD3D11*>(msaaBuffer);
|
||||
FramebufferD3D11* buffer11 = static_cast<FramebufferD3D11*>(buffer);
|
||||
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
if (mask & Buffer_Color)
|
||||
{
|
||||
RBXASSERT(msaaBuffer11->getColor().size() > 0);
|
||||
RBXASSERT(msaaBuffer11->getColor().size() == buffer11->getColor().size());
|
||||
|
||||
for (size_t i = 0; i < msaaBuffer11->getColor().size(); ++i)
|
||||
{
|
||||
RenderbufferD3D11* msaaColor = static_cast<RenderbufferD3D11*>(msaaBuffer11->getColor()[i].get());
|
||||
RenderbufferD3D11* color = static_cast<RenderbufferD3D11*>(buffer11->getColor()[i].get());
|
||||
|
||||
RBXASSERT(msaaColor->getFormat() == color->getFormat());
|
||||
|
||||
context11->ResolveSubresource(color->getResource(), 0, msaaColor->getResource(), 0, static_cast<DXGI_FORMAT>(TextureD3D11::getInternalFormat(msaaColor->getFormat())));
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & (Buffer_Depth | Buffer_Stencil))
|
||||
{
|
||||
RBXASSERT(msaaBuffer11->getDepth() && buffer11->getDepth());
|
||||
|
||||
RenderbufferD3D11* msaaDepth = static_cast<RenderbufferD3D11*>(msaaBuffer11->getDepth().get());
|
||||
RenderbufferD3D11* depth = static_cast<RenderbufferD3D11*>(buffer11->getDepth().get());
|
||||
|
||||
RBXASSERT(msaaDepth->getFormat() == depth->getFormat());
|
||||
|
||||
context11->ResolveSubresource(depth->getResource(), 0, msaaDepth->getResource(), 0, static_cast<DXGI_FORMAT>(TextureD3D11::getInternalFormat(msaaDepth->getFormat())));
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::discardFramebuffer(Framebuffer* buffer, unsigned int mask)
|
||||
{
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::invalidateCachedGeometry()
|
||||
{
|
||||
cachedGeometry = NULL;
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::invalidateCachedProgram()
|
||||
{
|
||||
cachedProgram = NULL;
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::invalidateCachedVertexLayout()
|
||||
{
|
||||
cachedVertexLayout = NULL;
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::invalidateCachedTexture(Texture* texture)
|
||||
{
|
||||
for (unsigned int stage = 0; stage < ARRAYSIZE(cachedTextureUnits); ++stage)
|
||||
{
|
||||
TextureUnit& u = cachedTextureUnits[stage];
|
||||
|
||||
if (u.texture == texture)
|
||||
u.texture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void ascii2unicode(wchar_t* dest, const char* src, int max)
|
||||
{
|
||||
while( (*dest++ = *src++) && max--) {}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::pushDebugMarkerGroup(const char* text)
|
||||
{
|
||||
if (pfn_D3DPERF_BeginEvent)
|
||||
{
|
||||
wchar_t buffer[512];
|
||||
ascii2unicode(buffer, text, sizeof(buffer)/sizeof(buffer[0]) );
|
||||
pfn_D3DPERF_BeginEvent(0, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::popDebugMarkerGroup()
|
||||
{
|
||||
if (pfn_D3DPERF_EndEvent)
|
||||
{
|
||||
pfn_D3DPERF_EndEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::setDebugMarker(const char* text)
|
||||
{
|
||||
if (pfn_D3DPERF_SetMarker)
|
||||
{
|
||||
wchar_t buffer[512];
|
||||
ascii2unicode(buffer, text, sizeof(buffer)/sizeof(buffer[0]));
|
||||
pfn_D3DPERF_SetMarker(0, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeviceContextD3D11::beginQuery(ID3D11Query* query)
|
||||
{
|
||||
immediateContext11->Begin(query);
|
||||
}
|
||||
|
||||
void DeviceContextD3D11::endQuery(ID3D11Query* query)
|
||||
{
|
||||
immediateContext11->End(query);
|
||||
}
|
||||
|
||||
bool DeviceContextD3D11::getQueryData(ID3D11Query* query, void* dataOut, size_t dataSize)
|
||||
{
|
||||
HRESULT hr = immediateContext11->GetData(query, dataOut, dataSize, D3D11_ASYNC_GETDATA_DONOTFLUSH);
|
||||
return hr == S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "GeometryD3D11.h"
|
||||
#include "ShaderD3D11.h"
|
||||
#include "TextureD3D11.h"
|
||||
#include "FramebufferD3D11.h"
|
||||
|
||||
#include "rbx/rbxTime.h"
|
||||
#include "rbx/Profiler.h"
|
||||
|
||||
#include "StringConv.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
|
||||
LOGGROUP(Graphics)
|
||||
LOGGROUP(VR)
|
||||
|
||||
FASTFLAGVARIABLE(DebugD3D11DebugMode, false)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
static unsigned int getMaxSamplesSupported(ID3D11Device* device11)
|
||||
{
|
||||
unsigned int result = 1;
|
||||
|
||||
for (unsigned int mode = 2; mode <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; mode *= 2)
|
||||
{
|
||||
unsigned maxQualityLevel;
|
||||
HRESULT hr = device11->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, mode, &maxQualityLevel);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
if (maxQualityLevel <= 0)
|
||||
break;
|
||||
|
||||
result = mode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DXGI_ADAPTER_DESC getAdapterDesc(IDXGIDevice* device)
|
||||
{
|
||||
IDXGIAdapter* adapter = NULL;
|
||||
device->GetAdapter(&adapter);
|
||||
|
||||
DXGI_ADAPTER_DESC desc = {};
|
||||
adapter->GetDesc(&desc);
|
||||
|
||||
adapter->Release();
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
template <typename T, typename P> T* queryInterface(P* object)
|
||||
{
|
||||
void* result = 0;
|
||||
if (SUCCEEDED(object->QueryInterface(__uuidof(T), &result)))
|
||||
return static_cast<T*>(result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DeviceD3D11::DeviceD3D11(void* windowHandle)
|
||||
: windowHandle(windowHandle)
|
||||
, device11(NULL)
|
||||
, swapChain11(NULL)
|
||||
, immediateContext(NULL)
|
||||
, frameTimeQueryIssued(false)
|
||||
, gpuTime(0)
|
||||
, beginQuery(NULL)
|
||||
, endQuery(NULL)
|
||||
, disjointQuery(NULL)
|
||||
, vrEnabled(true)
|
||||
{
|
||||
createDevice();
|
||||
|
||||
caps = DeviceCaps();
|
||||
|
||||
caps.supportsFramebuffer = true;
|
||||
caps.supportsShaders = true;
|
||||
caps.supportsFFP = false;
|
||||
caps.supportsStencil = true;
|
||||
caps.supportsIndex32 = true;
|
||||
|
||||
caps.supportsTextureDXT = true;
|
||||
caps.supportsTexturePVR = false;
|
||||
caps.supportsTextureHalfFloat = true; //DXGI_FORMAT_R16G16B16A16_FLOAT is always supported on DX11 HW (including featureLvl 10 - 9.3)
|
||||
caps.supportsTexture3D = true;
|
||||
caps.supportsTextureNPOT = shaderProfile == shaderProfile_DX11_level_9_3 ? false : true;
|
||||
caps.supportsTextureETC1 = false;
|
||||
|
||||
caps.supportsTexturePartialMipChain = true;
|
||||
|
||||
caps.maxDrawBuffers = shaderProfile == shaderProfile_DX11_level_9_3 ? 4 : 8;
|
||||
caps.maxSamples = getMaxSamplesSupported(device11);
|
||||
caps.maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
caps.maxTextureUnits = 16;
|
||||
|
||||
caps.colorOrderBGR = false;
|
||||
caps.needsHalfPixelOffset = false;
|
||||
caps.requiresRenderTargetFlipping = false;
|
||||
|
||||
caps.retina = false;
|
||||
|
||||
std::pair<unsigned int, unsigned int> dimensions = getFramebufferSize();
|
||||
createMainFramebuffer(dimensions.first, dimensions.second);
|
||||
|
||||
// queries
|
||||
HRESULT hr;
|
||||
|
||||
D3D11_QUERY_DESC queryDesc;
|
||||
queryDesc.MiscFlags = 0;
|
||||
|
||||
queryDesc.Query = D3D11_QUERY_TIMESTAMP;
|
||||
hr = device11->CreateQuery(&queryDesc, &beginQuery);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
hr = device11->CreateQuery(&queryDesc, &endQuery);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
|
||||
hr = device11->CreateQuery(&queryDesc, &disjointQuery);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
if (IDXGIDevice1* deviceDXGI1 = queryInterface<IDXGIDevice1>(device11))
|
||||
{
|
||||
deviceDXGI1->SetMaximumFrameLatency(1);
|
||||
deviceDXGI1->Release();
|
||||
}
|
||||
|
||||
if (IDXGIDevice* deviceDXGI = queryInterface<IDXGIDevice>(device11))
|
||||
{
|
||||
DXGI_ADAPTER_DESC desc = getAdapterDesc(deviceDXGI);
|
||||
|
||||
FASTLOGS(FLog::Graphics, "D3D11 Adapter: %s", utf8_encode(desc.Description));
|
||||
FASTLOG2(FLog::Graphics, "D3D11 Adapter: Vendor %04x Device %04x", desc.VendorId, desc.DeviceId);
|
||||
|
||||
// Do not use GPU profiling on Intel cards to avoid a crash in Intel driver when releasing resources in gpuShutdown
|
||||
// Also, this vendor id is SO COOL!
|
||||
if (desc.VendorId != 0x8086)
|
||||
Profiler::gpuInit(getImmediateContext11());
|
||||
|
||||
deviceDXGI->Release();
|
||||
}
|
||||
|
||||
if (vr)
|
||||
{
|
||||
try
|
||||
{
|
||||
vr->setup(this);
|
||||
}
|
||||
catch (RBX::base_exception& e)
|
||||
{
|
||||
FASTLOGS(FLog::VR, "VR ERROR during setup: %s", e.what());
|
||||
vr.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DeviceD3D11::createMainFramebuffer(unsigned width, unsigned height)
|
||||
{
|
||||
RBXASSERT(!mainFramebuffer);
|
||||
|
||||
// Get back buffer, create view
|
||||
ID3D11Texture2D* backBuffer = NULL;
|
||||
HRESULT hr = swapChain11->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&backBuffer );
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
shared_ptr<Renderbuffer> backBufferRB = shared_ptr<Renderbuffer>(new RenderbufferD3D11(this, Texture::Format_RGBA8, width, height, 1, backBuffer));
|
||||
std::vector<shared_ptr<Renderbuffer>> colorBuffers;
|
||||
colorBuffers.push_back(backBufferRB);
|
||||
|
||||
// Create depth stencil
|
||||
shared_ptr<Renderbuffer> depthStencil = shared_ptr<Renderbuffer>(new RenderbufferD3D11(this, Texture::Format_D24S8, width, height, 1));
|
||||
|
||||
// create frame buffer
|
||||
mainFramebuffer.reset(new FramebufferD3D11(this, colorBuffers, depthStencil));
|
||||
}
|
||||
|
||||
DeviceD3D11::~DeviceD3D11()
|
||||
{
|
||||
Profiler::gpuShutdown();
|
||||
|
||||
// we want to release all the DX references before releasing device to be able to test if nothing is hanging
|
||||
vr.reset();
|
||||
immediateContext.reset();
|
||||
mainFramebuffer.reset();
|
||||
|
||||
ReleaseCheck(beginQuery);
|
||||
ReleaseCheck(endQuery);
|
||||
ReleaseCheck(disjointQuery);
|
||||
|
||||
ReleaseCheck(swapChain11);
|
||||
ReleaseCheck(device11);
|
||||
}
|
||||
|
||||
void DeviceD3D11::defineGlobalConstants(size_t dataSize, const std::vector<ShaderGlobalConstant>& constants)
|
||||
{
|
||||
RBXASSERT(!constants.empty());
|
||||
|
||||
// Since constants are directly set to register values, we impose additional restrictions on constant data
|
||||
// The struct should be an integer number of float4 registers, and every constant has to be aligned to float4 boundary
|
||||
RBXASSERT(dataSize % 16 == 0);
|
||||
|
||||
immediateContext->defineGlobalConstants(dataSize);
|
||||
}
|
||||
|
||||
DeviceContext* DeviceD3D11::beginFrame()
|
||||
{
|
||||
std::pair<unsigned int, unsigned int> dimensions = getFramebufferSize();
|
||||
|
||||
// Don't render anything if there is no main framebuffer or device is lost
|
||||
if (!mainFramebuffer)
|
||||
return false;
|
||||
|
||||
// Don't render anything if window size changed; wait for validate
|
||||
if (dimensions.first != mainFramebuffer->getWidth() || dimensions.second != mainFramebuffer->getHeight())
|
||||
return NULL;
|
||||
|
||||
immediateContext->bindFramebuffer(mainFramebuffer.get());
|
||||
immediateContext->clearStates();
|
||||
|
||||
if (disjointQuery && beginQuery && endQuery)
|
||||
{
|
||||
if (!frameTimeQueryIssued)
|
||||
{
|
||||
immediateContext->beginQuery(disjointQuery);
|
||||
immediateContext->endQuery(beginQuery);
|
||||
}
|
||||
}
|
||||
|
||||
return immediateContext.get();
|
||||
}
|
||||
|
||||
bool DeviceD3D11::validate()
|
||||
{
|
||||
std::pair<unsigned int, unsigned int> dimensions = getFramebufferSize();
|
||||
|
||||
// Don't change anything if window is minimized (getFramebufferSize returns 1x1)
|
||||
if (dimensions.first <= 1 && dimensions.second <= 1)
|
||||
return false;
|
||||
|
||||
// Reset device if window size changed
|
||||
if (mainFramebuffer && (dimensions.first != mainFramebuffer->getWidth() || dimensions.second != mainFramebuffer->getHeight()))
|
||||
{
|
||||
immediateContext->getContextDX11()->OMSetRenderTargets(NULL, NULL, NULL);
|
||||
|
||||
mainFramebuffer.reset();
|
||||
resizeSwapchain();
|
||||
createMainFramebuffer(dimensions.first, dimensions.second);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceD3D11::endFrame()
|
||||
{
|
||||
if (disjointQuery && beginQuery && endQuery)
|
||||
{
|
||||
if (!frameTimeQueryIssued)
|
||||
{
|
||||
immediateContext->endQuery(endQuery);
|
||||
immediateContext->endQuery(disjointQuery);
|
||||
frameTimeQueryIssued = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT64 tsBeginFrame, tsEndFrame;
|
||||
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT tsDisjoint;
|
||||
|
||||
bool queryFinished = immediateContext->getQueryData(disjointQuery, &tsDisjoint, sizeof(tsDisjoint));
|
||||
queryFinished &= immediateContext->getQueryData(beginQuery, &tsBeginFrame, sizeof(UINT64));
|
||||
queryFinished &= immediateContext->getQueryData(endQuery, &tsEndFrame, sizeof(UINT64));
|
||||
|
||||
if (queryFinished)
|
||||
{
|
||||
if (!tsDisjoint.Disjoint)
|
||||
gpuTime = (float)(double(tsEndFrame - tsBeginFrame) / double(tsDisjoint.Frequency) * 1000.0);
|
||||
frameTimeQueryIssued = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vr && vrEnabled)
|
||||
{
|
||||
vr->submitFrame(immediateContext.get());
|
||||
}
|
||||
|
||||
present();
|
||||
}
|
||||
|
||||
DeviceStats DeviceD3D11::getStatistics() const
|
||||
{
|
||||
DeviceStats result = {};
|
||||
|
||||
result.gpuFrameTime = gpuTime;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
shared_ptr<Texture> DeviceD3D11::createTexture(Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Texture::Usage usage)
|
||||
{
|
||||
return shared_ptr<Texture>(new TextureD3D11(this, type, format, width, height, depth, mipLevels, usage));
|
||||
}
|
||||
|
||||
shared_ptr<VertexBuffer> DeviceD3D11::createVertexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage)
|
||||
{
|
||||
return shared_ptr<VertexBuffer>(new VertexBufferD3D11(this, elementSize, elementCount, usage));
|
||||
}
|
||||
|
||||
shared_ptr<IndexBuffer> DeviceD3D11::createIndexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage)
|
||||
{
|
||||
return shared_ptr<IndexBuffer>(new IndexBufferD3D11(this, elementSize, elementCount, usage));
|
||||
}
|
||||
|
||||
shared_ptr<VertexLayout> DeviceD3D11::createVertexLayout(const std::vector<VertexLayout::Element>& elements)
|
||||
{
|
||||
return shared_ptr<VertexLayout>(new VertexLayoutD3D11(this, elements));
|
||||
}
|
||||
|
||||
shared_ptr<Geometry> DeviceD3D11::createGeometryImpl(const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer> >& vertexBuffers, const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex)
|
||||
{
|
||||
return shared_ptr<Geometry>(new GeometryD3D11(this, layout, vertexBuffers, indexBuffer, baseVertexIndex));
|
||||
}
|
||||
|
||||
shared_ptr<Framebuffer> DeviceD3D11::createFramebufferImpl(const std::vector<shared_ptr<Renderbuffer> >& color, const shared_ptr<Renderbuffer>& depth)
|
||||
{
|
||||
return shared_ptr<Framebuffer>(new FramebufferD3D11(this, color, depth));
|
||||
}
|
||||
|
||||
Framebuffer* DeviceD3D11::getMainFramebuffer()
|
||||
{
|
||||
return mainFramebuffer.get();
|
||||
}
|
||||
|
||||
DeviceVR* DeviceD3D11::getVR()
|
||||
{
|
||||
return (vr && vrEnabled) ? vr.get() : NULL;
|
||||
}
|
||||
|
||||
void DeviceD3D11::setVR(bool enabled)
|
||||
{
|
||||
vrEnabled = enabled;
|
||||
}
|
||||
|
||||
shared_ptr<Renderbuffer> DeviceD3D11::createRenderbuffer(Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
|
||||
{
|
||||
return shared_ptr<Renderbuffer>(new RenderbufferD3D11(this, format, width, height, samples));
|
||||
}
|
||||
|
||||
std::string DeviceD3D11::createShaderSource(const std::string& path, const std::string& defines, boost::function<std::string (const std::string&)> fileCallback)
|
||||
{
|
||||
std::string dx11Defines = defines;
|
||||
dx11Defines += " DX11";
|
||||
|
||||
if (getShaderProfile() == DeviceD3D11::shaderProfile_DX11_level_9_3)
|
||||
dx11Defines += " WIN_MOBILE";
|
||||
|
||||
return ShaderProgramD3D11::createShaderSource(path, dx11Defines, this, fileCallback);
|
||||
}
|
||||
|
||||
std::vector<char> DeviceD3D11::createShaderBytecode(const std::string& source, const std::string& target, const std::string& entrypoint)
|
||||
{
|
||||
return ShaderProgramD3D11::createShaderBytecode(source, target, this, entrypoint);
|
||||
}
|
||||
|
||||
shared_ptr<VertexShader> DeviceD3D11::createVertexShader(const std::vector<char>& bytecode)
|
||||
{
|
||||
return shared_ptr<VertexShader>(new VertexShaderD3D11(this, bytecode));
|
||||
}
|
||||
|
||||
shared_ptr<FragmentShader> DeviceD3D11::createFragmentShader(const std::vector<char>& bytecode)
|
||||
{
|
||||
return shared_ptr<FragmentShader>(new FragmentShaderD3D11(this, bytecode));
|
||||
}
|
||||
|
||||
shared_ptr<ShaderProgram> DeviceD3D11::createShaderProgram(const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader)
|
||||
{
|
||||
return shared_ptr<ShaderProgram>(new ShaderProgramD3D11(this, vertexShader, fragmentShader));
|
||||
}
|
||||
|
||||
shared_ptr<ShaderProgram> DeviceD3D11::createShaderProgramFFP()
|
||||
{
|
||||
throw RBX::runtime_error("No FFP support");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
#pragma once
|
||||
|
||||
#include "GfxCore/Device.h"
|
||||
#include "GfxCore/States.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
struct ID3D11Device;
|
||||
struct ID3D11DeviceContext;
|
||||
struct IDXGISwapChain;
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11RasterizerState;
|
||||
struct ID3D11BlendState;
|
||||
struct ID3D11DepthStencilState;
|
||||
struct ID3D11SamplerState;
|
||||
struct ID3D11ShaderResourceView;
|
||||
struct ID3D11Resource;
|
||||
struct ID3D11Query;
|
||||
struct IDXGIAdapter;
|
||||
struct IDXGIDevice1;
|
||||
struct ID3D11DeviceChild;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
|
||||
class DeviceVRD3D11: public DeviceVR
|
||||
{
|
||||
public:
|
||||
virtual void setup(Device* device) = 0;
|
||||
virtual void submitFrame(DeviceContext* context) = 0;
|
||||
|
||||
static DeviceVRD3D11* createOculus(IDXGIAdapter** outAdapter);
|
||||
static DeviceVRD3D11* createOpenVR(IDXGIAdapter** outAdapter);
|
||||
};
|
||||
|
||||
class FramebufferD3D11;
|
||||
class ShaderProgramD3D11;
|
||||
class TextureD3D11;
|
||||
class VertexLayoutD3D11;
|
||||
class GeometryD3D11;
|
||||
|
||||
template<class Ty>
|
||||
inline void ReleaseCheck(Ty*& object)
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
ULONG refCnt = object->Release();
|
||||
#if !defined(RBX_PLATFORM_DURANGO) // on xbox, object->Release() always returns 1, just because the COM doc says Release() can return anything
|
||||
RBXASSERT(refCnt == 0);
|
||||
#endif
|
||||
object = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceContextD3D11: public DeviceContext
|
||||
{
|
||||
public:
|
||||
DeviceContextD3D11(Device* device, ID3D11DeviceContext* deviceContext11);
|
||||
~DeviceContextD3D11();
|
||||
|
||||
void defineGlobalConstants(size_t dataSize);
|
||||
unsigned getGlobalDataSize() { return globalDataSize; }
|
||||
|
||||
void clearStates();
|
||||
|
||||
void invalidateCachedProgram();
|
||||
void invalidateCachedVertexLayout();
|
||||
void invalidateCachedGeometry();
|
||||
void invalidateCachedTexture(Texture* texture);
|
||||
|
||||
virtual void updateGlobalConstants(const void* data, size_t dataSize);
|
||||
|
||||
virtual void setDefaultAnisotropy(unsigned int value);
|
||||
|
||||
virtual void bindFramebuffer(Framebuffer* buffer);
|
||||
virtual void clearFramebuffer(unsigned int mask, const float color[4], float depth, unsigned int stencil);
|
||||
|
||||
virtual void copyFramebuffer(Framebuffer* buffer, Texture* texture);
|
||||
virtual void resolveFramebuffer(Framebuffer* msaaBuffer, Framebuffer* buffer, unsigned int mask);
|
||||
virtual void discardFramebuffer(Framebuffer* buffer, unsigned int mask);
|
||||
|
||||
virtual void bindProgram(ShaderProgram* program);
|
||||
virtual void setWorldTransforms4x3(const float* data, size_t matrixCount);
|
||||
virtual void setConstant(int handle, const float* data, size_t vectorCount);
|
||||
|
||||
virtual void bindTexture(unsigned int stage, Texture* texture, const SamplerState& state);
|
||||
|
||||
virtual void setRasterizerState(const RasterizerState& state);
|
||||
virtual void setBlendState(const BlendState& state);
|
||||
virtual void setDepthState(const DepthState& state);
|
||||
|
||||
virtual void drawImpl(Geometry* geometry, Geometry::Primitive primitive, unsigned int offset, unsigned int count, unsigned int indexRangeBegin, unsigned int indexRangeEnd);
|
||||
|
||||
void beginQuery(ID3D11Query* query);
|
||||
void endQuery(ID3D11Query* query);
|
||||
bool getQueryData(ID3D11Query* query, void* dataOut, size_t dataSize);
|
||||
|
||||
virtual void pushDebugMarkerGroup(const char* text);
|
||||
virtual void popDebugMarkerGroup();
|
||||
virtual void setDebugMarker(const char* text);
|
||||
|
||||
ID3D11DeviceContext* getContextDX11();
|
||||
|
||||
protected:
|
||||
struct TextureUnit
|
||||
{
|
||||
TextureD3D11* texture;
|
||||
SamplerState samplerState;
|
||||
|
||||
TextureUnit()
|
||||
: texture(NULL)
|
||||
, samplerState(SamplerState::Filter_Point)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Device* device;
|
||||
ID3D11Device* device11;
|
||||
ID3D11DeviceContext* immediateContext11;
|
||||
|
||||
ID3D11Buffer* globalsConstantBuffer;
|
||||
size_t globalDataSize;
|
||||
|
||||
unsigned int defaultAnisotropy;
|
||||
|
||||
Framebuffer* cachedFramebuffer;
|
||||
ShaderProgramD3D11* cachedProgram;
|
||||
VertexLayoutD3D11* cachedVertexLayout;
|
||||
GeometryD3D11* cachedGeometry;
|
||||
|
||||
TextureUnit cachedTextureUnits[16];
|
||||
|
||||
RasterizerState cachedRasterizerState;
|
||||
BlendState cachedBlendState;
|
||||
DepthState cachedDepthState;
|
||||
|
||||
typedef boost::unordered_map<RasterizerState, ID3D11RasterizerState*, StateHasher<RasterizerState>> RasterizerStateHash;
|
||||
typedef boost::unordered_map<BlendState, ID3D11BlendState*, StateHasher<BlendState>> BlendStateHash;
|
||||
typedef boost::unordered_map<DepthState, ID3D11DepthStencilState*, StateHasher<DepthState>> DepthStateHash;
|
||||
typedef boost::unordered_map<SamplerState, ID3D11SamplerState*, StateHasher<SamplerState>> SamplerStateHash;
|
||||
|
||||
RasterizerStateHash rasterizerStateHash;
|
||||
BlendStateHash blendStateHash;
|
||||
DepthStateHash depthStateHash;
|
||||
SamplerStateHash samplerStateHash;
|
||||
|
||||
template <class tHash, class tState>
|
||||
void checkDuplicates(const tHash& hash, tState* state)
|
||||
{
|
||||
for (tHash::const_iterator it = hash.begin(); it != hash.end(); ++it)
|
||||
{
|
||||
RBXASSERT(state != it->second);
|
||||
}
|
||||
}
|
||||
|
||||
// functions
|
||||
HMODULE d3d9;
|
||||
int (WINAPI *pfn_D3DPERF_BeginEvent)( DWORD col, LPCWSTR wszName);
|
||||
int (WINAPI *pfn_D3DPERF_EndEvent)();
|
||||
void (WINAPI *pfn_D3DPERF_SetMarker)( DWORD col, LPCWSTR wszName );
|
||||
};
|
||||
|
||||
class DeviceD3D11: public Device
|
||||
{
|
||||
public:
|
||||
|
||||
DeviceD3D11(void* windowHandle);
|
||||
~DeviceD3D11();
|
||||
|
||||
enum ShaderProfile
|
||||
{
|
||||
shaderProfile_DX11,
|
||||
shaderProfile_DX11_level_9_3
|
||||
};
|
||||
|
||||
virtual bool validate();
|
||||
|
||||
virtual DeviceContext* beginFrame();
|
||||
virtual void endFrame();
|
||||
|
||||
virtual Framebuffer* getMainFramebuffer();
|
||||
|
||||
virtual DeviceVR* getVR();
|
||||
virtual void setVR(bool enabled);
|
||||
|
||||
virtual void defineGlobalConstants(size_t dataSize, const std::vector<ShaderGlobalConstant>& constants);
|
||||
|
||||
virtual std::string getAPIName() { return "DirectX 11"; }
|
||||
virtual std::string getFeatureLevel(){ return shaderProfile == shaderProfile_DX11 ? "D3D11" : "D3D11_9.3"; }
|
||||
virtual std::string getShadingLanguage(){ return shaderProfile == shaderProfile_DX11 ? "hlsl11" : "hlsl11_level_9_3"; }
|
||||
virtual std::string createShaderSource(const std::string& path, const std::string& defines, boost::function<std::string (const std::string&)> fileCallback);
|
||||
virtual std::vector<char> createShaderBytecode(const std::string& source, const std::string& target, const std::string& entrypoint);
|
||||
|
||||
virtual shared_ptr<VertexShader> createVertexShader(const std::vector<char>& bytecode);
|
||||
virtual shared_ptr<FragmentShader> createFragmentShader(const std::vector<char>& bytecode);
|
||||
virtual shared_ptr<ShaderProgram> createShaderProgram(const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader);
|
||||
virtual shared_ptr<ShaderProgram> createShaderProgramFFP();
|
||||
|
||||
virtual shared_ptr<VertexBuffer> createVertexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage);
|
||||
virtual shared_ptr<IndexBuffer> createIndexBuffer(size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage);
|
||||
virtual shared_ptr<VertexLayout> createVertexLayout(const std::vector<VertexLayout::Element>& elements);
|
||||
|
||||
virtual shared_ptr<Texture> createTexture(Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Texture::Usage usage);
|
||||
|
||||
virtual shared_ptr<Renderbuffer> createRenderbuffer(Texture::Format format, unsigned int width, unsigned int height, unsigned int samples);
|
||||
|
||||
virtual shared_ptr<Geometry> createGeometryImpl(const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer> >& vertexBuffers, const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex);
|
||||
|
||||
virtual shared_ptr<Framebuffer> createFramebufferImpl(const std::vector<shared_ptr<Renderbuffer> >& color, const shared_ptr<Renderbuffer>& depth);
|
||||
|
||||
virtual const DeviceCaps& getCaps() const { return caps; }
|
||||
|
||||
virtual DeviceStats getStatistics() const;
|
||||
|
||||
#ifdef RBX_PLATFORM_DURANGO
|
||||
virtual void suspend();
|
||||
virtual void resume();
|
||||
#endif
|
||||
|
||||
ID3D11Device* getDevice11() { return device11; }
|
||||
ShaderProfile getShaderProfile() const { return shaderProfile; }
|
||||
|
||||
ID3D11DeviceContext* getImmediateContext11() { return immediateContext->getContextDX11(); }
|
||||
DeviceContextD3D11* getImmediateContextD3D11() { return immediateContext.get(); }
|
||||
|
||||
void* getWindowHandle() const { return windowHandle; }
|
||||
|
||||
private:
|
||||
void* windowHandle;
|
||||
DeviceCaps caps;
|
||||
|
||||
ID3D11Device* device11;
|
||||
IDXGISwapChain* swapChain11;
|
||||
scoped_ptr<DeviceContextD3D11> immediateContext;
|
||||
|
||||
scoped_ptr<FramebufferD3D11> mainFramebuffer;
|
||||
|
||||
void createMainFramebuffer(unsigned width, unsigned height);
|
||||
|
||||
ShaderProfile shaderProfile;
|
||||
|
||||
float gpuTime;
|
||||
|
||||
ID3D11Query* beginQuery;
|
||||
ID3D11Query* endQuery;
|
||||
ID3D11Query* disjointQuery;
|
||||
bool frameTimeQueryIssued;
|
||||
|
||||
scoped_ptr<DeviceVRD3D11> vr;
|
||||
bool vrEnabled;
|
||||
|
||||
// these functions are platform-dependent
|
||||
void createDevice();
|
||||
void present();
|
||||
void resizeSwapchain();
|
||||
std::pair<unsigned int, unsigned int> getFramebufferSize();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#if defined(RBX_PLATFORM_DURANGO)
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
#include <wrl.h>
|
||||
|
||||
FASTFLAG(DebugD3D11DebugMode)
|
||||
|
||||
// This is a hacky bridge to get overscan-aware resolution from XboxClient
|
||||
// There's no simple way to refactor this :(
|
||||
std::pair<unsigned int, unsigned int> xboxPlatformGetRenderSize_Hack(void* h);
|
||||
|
||||
namespace RBX {
|
||||
namespace Graphics {
|
||||
|
||||
IDXGISwapChain* createSwapchain(ID3D11Device* dev, unsigned w, unsigned h)
|
||||
{
|
||||
HRESULT hr;
|
||||
IDXGISwapChain1* swapch = 0;
|
||||
|
||||
IDXGIDevice1* spdxgiDevice = 0;
|
||||
dev->QueryInterface( IID_IDXGIDevice1, reinterpret_cast<void**>(&spdxgiDevice) );
|
||||
|
||||
IDXGIAdapter* spdxgiAdapter = 0;
|
||||
spdxgiDevice->GetAdapter( &spdxgiAdapter );
|
||||
|
||||
IDXGIFactory2* spdxgiFactory = 0;
|
||||
spdxgiAdapter->GetParent( IID_IDXGIFactory2, reinterpret_cast<void**>(&spdxgiFactory) );
|
||||
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
|
||||
swapChainDesc.Width = w;
|
||||
swapChainDesc.Height = h;
|
||||
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
swapChainDesc.Stereo = false;
|
||||
swapChainDesc.SampleDesc.Count = 1; // don't use multi-sampling
|
||||
swapChainDesc.SampleDesc.Quality = 0;
|
||||
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swapChainDesc.BufferCount = 2; // use two buffers to enable flip effect
|
||||
swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
|
||||
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||
hr = spdxgiFactory->CreateSwapChainForCoreWindow(dev, (IUnknown*)Windows::UI::Core::CoreWindow::GetForCurrentThread(), &swapChainDesc, nullptr, &swapch);
|
||||
|
||||
spdxgiFactory->Release();
|
||||
spdxgiAdapter->Release();
|
||||
spdxgiDevice->Release();
|
||||
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("failed to create swapchain: %x", hr);
|
||||
|
||||
return swapch;
|
||||
}
|
||||
|
||||
void DeviceD3D11::suspend()
|
||||
{
|
||||
ID3D11DeviceContextX* contextx = static_cast<ID3D11DeviceContextX*>(immediateContext->getContextDX11());
|
||||
contextx->Suspend(0);
|
||||
}
|
||||
|
||||
void DeviceD3D11::resume()
|
||||
{
|
||||
ID3D11DeviceContextX* contextx = static_cast<ID3D11DeviceContextX*>(immediateContext->getContextDX11());
|
||||
contextx->Resume();
|
||||
}
|
||||
|
||||
void DeviceD3D11::createDevice()
|
||||
{
|
||||
ID3D11DeviceX* dev;
|
||||
ID3D11DeviceContextX* ctx;
|
||||
|
||||
UINT flags = 0;
|
||||
if( FFlag::DebugD3D11DebugMode )
|
||||
{
|
||||
flags |= D3D11_CREATE_DEVICE_INSTRUMENTED | D3D11_CREATE_DEVICE_VALIDATED | D3D11_CREATE_DEVICE_DEBUG;
|
||||
}
|
||||
|
||||
D3D11X_CREATE_DEVICE_PARAMETERS params = D3D11X_CREATE_DEVICE_PARAMETERS();
|
||||
params.Flags = flags;
|
||||
params.Version = D3D11_SDK_VERSION;
|
||||
params.DeferredDeletionThreadAffinityMask = 0x20; // default value
|
||||
|
||||
HRESULT hr = D3D11XCreateDeviceX(¶ms, &dev, &ctx);
|
||||
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Unable to create D3D device: %x", hr);
|
||||
|
||||
std::pair<unsigned int, unsigned int> fbsize = getFramebufferSize();
|
||||
|
||||
this->device11 = dev;
|
||||
this->immediateContext.reset(new DeviceContextD3D11(this, ctx));
|
||||
this->shaderProfile = shaderProfile_DX11;
|
||||
this->swapChain11 = createSwapchain(dev, fbsize.first, fbsize.second);
|
||||
}
|
||||
|
||||
void DeviceD3D11::present()
|
||||
{
|
||||
unsigned centerX = 1920/2, centerY = 1080/2; // for now, assume that the native resolution of the TV is fullhd and we're simply dealing with overscan
|
||||
std::pair<unsigned, unsigned> sz = getFramebufferSize();
|
||||
D3D11_RECT src = { 0, 0, sz.first, sz.second };
|
||||
POINT dest = { centerX - sz.first/2, centerY - sz.second/2 };
|
||||
|
||||
DXGIX_PRESENTARRAY_PARAMETERS pp = {};
|
||||
pp.SourceRect = src;
|
||||
pp.DestRectUpperLeft = dest;
|
||||
pp.ScaleFactorHorz = 1.0f;
|
||||
pp.ScaleFactorVert = 1.0f;
|
||||
pp.Flags = 0;
|
||||
|
||||
DXGIXPresentArray(1, 0, 0, 1, (IDXGISwapChain1**)&swapChain11, &pp);
|
||||
}
|
||||
|
||||
void DeviceD3D11::resizeSwapchain()
|
||||
{
|
||||
std::pair<unsigned int, unsigned int> dimensions = getFramebufferSize();
|
||||
ReleaseCheck(swapChain11);
|
||||
swapChain11 = createSwapchain(device11, dimensions.first, dimensions.second );
|
||||
RBXASSERT(swapChain11);
|
||||
}
|
||||
|
||||
std::pair<unsigned int, unsigned int> DeviceD3D11::getFramebufferSize()
|
||||
{
|
||||
return xboxPlatformGetRenderSize_Hack(windowHandle);
|
||||
}
|
||||
|
||||
}}
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
#if !defined(RBX_PLATFORM_DURANGO) && !defined(RBX_PLATFORM_UWP)
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "ShaderD3D11.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
|
||||
FASTFLAG(DebugD3D11DebugMode)
|
||||
|
||||
FASTFLAG(RenderVR)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
|
||||
typedef HRESULT (WINAPI *TypeD3D11CreateDeviceAndSwapChain)(IDXGIAdapter *, D3D_DRIVER_TYPE, HMODULE, unsigned, const D3D_FEATURE_LEVEL*, unsigned, unsigned, const DXGI_SWAP_CHAIN_DESC *, IDXGISwapChain **, ID3D11Device **, D3D_FEATURE_LEVEL *, ID3D11DeviceContext **);
|
||||
|
||||
static TypeD3D11CreateDeviceAndSwapChain getDeviceCreationFunction()
|
||||
{
|
||||
HMODULE module = LoadLibraryA("d3d11.dll");
|
||||
if (!module) return NULL;
|
||||
|
||||
return (TypeD3D11CreateDeviceAndSwapChain)GetProcAddress(module, "D3D11CreateDeviceAndSwapChain");
|
||||
}
|
||||
|
||||
static DeviceVRD3D11* createVR(IDXGIAdapter** outAdapter)
|
||||
{
|
||||
if (DeviceVRD3D11* result = DeviceVRD3D11::createOculus(outAdapter))
|
||||
return result;
|
||||
|
||||
if (DeviceVRD3D11* result = DeviceVRD3D11::createOpenVR(outAdapter))
|
||||
return result;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DeviceD3D11::createDevice()
|
||||
{
|
||||
IDXGIAdapter* adapter = NULL;
|
||||
|
||||
if (FFlag::RenderVR)
|
||||
vr.reset(createVR(&adapter));
|
||||
|
||||
TypeD3D11CreateDeviceAndSwapChain createDeviceAndSwapChain = getDeviceCreationFunction();
|
||||
if (!createDeviceAndSwapChain)
|
||||
throw std::runtime_error("Unable to load d3d11.dll");
|
||||
|
||||
this->windowHandle = windowHandle;
|
||||
|
||||
unsigned deviceCreationFlags = FFlag::DebugD3D11DebugMode ? D3D11_CREATE_DEVICE_DEBUG : 0;
|
||||
|
||||
D3D_FEATURE_LEVEL requestedFeatureLevel = D3D_FEATURE_LEVEL_11_0;
|
||||
|
||||
D3D_FEATURE_LEVEL featureLevelOut;
|
||||
|
||||
std::pair<unsigned int, unsigned int> dimensions = getFramebufferSize();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC sd = {};
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = dimensions.first;
|
||||
sd.BufferDesc.Height = dimensions.second;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 0;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = (HWND)windowHandle;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = true;
|
||||
sd.Flags = 0;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
|
||||
ID3D11DeviceContext* deviceContext = NULL;
|
||||
HRESULT hr = createDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_HARDWARE, NULL, deviceCreationFlags, &requestedFeatureLevel, 1,
|
||||
D3D11_SDK_VERSION, &sd, &swapChain11, &device11, &featureLevelOut, &deviceContext);
|
||||
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Unable to create D3D device: %x", hr);
|
||||
|
||||
shaderProfile = featureLevelOut == D3D_FEATURE_LEVEL_11_0 ? shaderProfile_DX11 : shaderProfile_DX11_level_9_3;
|
||||
|
||||
HMODULE shaderCompiler = ShaderProgramD3D11::loadShaderCompilerDLL();
|
||||
if (!shaderCompiler)
|
||||
throw std::runtime_error("Unable to load shader compiler dll");
|
||||
|
||||
immediateContext.reset(new DeviceContextD3D11(this, deviceContext));
|
||||
}
|
||||
|
||||
void DeviceD3D11::present()
|
||||
{
|
||||
swapChain11->Present(0,0);
|
||||
}
|
||||
|
||||
void DeviceD3D11::resizeSwapchain()
|
||||
{
|
||||
HRESULT hr = swapChain11->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
std::pair<unsigned int, unsigned int> DeviceD3D11::getFramebufferSize()
|
||||
{
|
||||
RECT rect = {};
|
||||
GetClientRect((HWND)windowHandle, &rect);
|
||||
|
||||
unsigned int width = std::max(rect.right - rect.left, 1l);
|
||||
unsigned int height = std::max(rect.bottom - rect.top, 1l);
|
||||
|
||||
return std::make_pair(width, height);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,275 @@
|
||||
#include "FramebufferD3D11.h"
|
||||
|
||||
#include "TextureD3D11.h"
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
static ID3D11View* createRenderTargetView(ID3D11Device* device11, Texture::Format format, Texture::Type type, ID3D11Resource* texture, unsigned cubeIndex, unsigned int mipIndex, unsigned int samples)
|
||||
{
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
if (Texture::isFormatDepth(format))
|
||||
{
|
||||
RBXASSERT(type == Texture::Type_2D);
|
||||
|
||||
ID3D11DepthStencilView* depthStencilView = NULL;
|
||||
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {};
|
||||
|
||||
if (samples > 1)
|
||||
{
|
||||
RBXASSERT(mipIndex == 0);
|
||||
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
descDSV.Texture2D.MipSlice = mipIndex;
|
||||
}
|
||||
|
||||
descDSV.Flags = 0;
|
||||
descDSV.Format = DXGI_FORMAT_UNKNOWN;
|
||||
|
||||
hr = device11->CreateDepthStencilView(texture, &descDSV, &depthStencilView);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
return depthStencilView;
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D11_RENDER_TARGET_VIEW_DESC descRTV = {};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Texture::Type_2D:
|
||||
{
|
||||
if (samples > 1)
|
||||
{
|
||||
RBXASSERT(mipIndex == 0);
|
||||
descRTV.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
descRTV.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
descRTV.Texture2D.MipSlice = mipIndex;
|
||||
}
|
||||
|
||||
descRTV.Format = DXGI_FORMAT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
case Texture::Type_Cube:
|
||||
{
|
||||
RBXASSERT(samples == 1);
|
||||
|
||||
descRTV.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
descRTV.Texture2DArray.ArraySize = 1;
|
||||
descRTV.Texture2DArray.FirstArraySlice = cubeIndex;
|
||||
descRTV.Texture2DArray.MipSlice = mipIndex;
|
||||
descRTV.Format = DXGI_FORMAT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
RBXASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
ID3D11RenderTargetView* renderTargetView = NULL;
|
||||
|
||||
hr = device11->CreateRenderTargetView(texture, &descRTV, &renderTargetView);
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Error creating render target view: %x", hr);
|
||||
|
||||
return renderTargetView;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11Texture2D* createRenderTexture(ID3D11Device* device11, unsigned width, unsigned height, unsigned int samples, Texture::Format format)
|
||||
{
|
||||
bool isDepth = Texture::isFormatDepth(format);
|
||||
|
||||
D3D11_TEXTURE2D_DESC descDepth = {};
|
||||
descDepth.Width = width;
|
||||
descDepth.Height = height;
|
||||
descDepth.MipLevels = 1;
|
||||
descDepth.ArraySize = 1;
|
||||
descDepth.Format = static_cast<DXGI_FORMAT>(TextureD3D11::getInternalFormat(format));
|
||||
descDepth.SampleDesc.Count = samples;
|
||||
descDepth.SampleDesc.Quality = 0;
|
||||
descDepth.Usage = D3D11_USAGE_DEFAULT;
|
||||
descDepth.BindFlags = isDepth ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET;
|
||||
descDepth.CPUAccessFlags = 0;
|
||||
descDepth.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* rtTexture = NULL;
|
||||
HRESULT hr = device11->CreateTexture2D( &descDepth, NULL, &rtTexture );
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Error creating render target texture: %x", hr);
|
||||
|
||||
return rtTexture;
|
||||
}
|
||||
|
||||
RenderbufferD3D11::RenderbufferD3D11(Device* device, const shared_ptr<TextureD3D11>& owner, unsigned cubeIndex, unsigned mipIndex)
|
||||
: Renderbuffer(device, owner->getFormat(), owner->getWidth(), owner->getHeight(), 1)
|
||||
, object(0)
|
||||
, owner(owner)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
object = createRenderTargetView(device11, owner->getFormat(), owner->getType(), owner->getObject(), cubeIndex, mipIndex, 1);
|
||||
|
||||
// Destructor does not Release() the object, no need to AddRef()
|
||||
texture = owner->getObject();
|
||||
}
|
||||
|
||||
RenderbufferD3D11::RenderbufferD3D11(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples, ID3D11Texture2D* texture)
|
||||
: Renderbuffer(device, format, width, height, samples)
|
||||
, object(0)
|
||||
, texture(texture)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
if (Texture::isFormatDepth(format))
|
||||
{
|
||||
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {};
|
||||
descDSV.Format = static_cast<DXGI_FORMAT>(TextureD3D11::getInternalFormat(format));
|
||||
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
||||
|
||||
ID3D11DepthStencilView* depthStencilView = NULL;
|
||||
HRESULT hr = device11->CreateDepthStencilView(texture, &descDSV, &depthStencilView);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
object = depthStencilView;
|
||||
}
|
||||
else
|
||||
{
|
||||
D3D11_RENDER_TARGET_VIEW_DESC descRTV = {};
|
||||
descRTV.Format = static_cast<DXGI_FORMAT>(TextureD3D11::getInternalFormat(format));
|
||||
descRTV.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
|
||||
ID3D11RenderTargetView* renderTargetView = NULL;
|
||||
HRESULT hr = device11->CreateRenderTargetView(texture, &descRTV, &renderTargetView);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
object = renderTargetView;
|
||||
}
|
||||
}
|
||||
|
||||
RenderbufferD3D11::RenderbufferD3D11(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples)
|
||||
: Renderbuffer(device, format, width, height, samples)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
texture = createRenderTexture(device11, width, height, samples, format);
|
||||
|
||||
object = createRenderTargetView(device11, format, Texture::Type_2D, texture, 0, 0, samples);
|
||||
}
|
||||
|
||||
RenderbufferD3D11::~RenderbufferD3D11()
|
||||
{
|
||||
ReleaseCheck(object);
|
||||
if (!owner)
|
||||
ReleaseCheck(texture);
|
||||
}
|
||||
|
||||
FramebufferD3D11::FramebufferD3D11(Device* device, const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth)
|
||||
: Framebuffer(device, 0, 0, 0)
|
||||
, color(color)
|
||||
, depth(depth)
|
||||
{
|
||||
RBXASSERT(!color.empty());
|
||||
|
||||
if (color.size() > device->getCaps().maxDrawBuffers)
|
||||
throw RBX::runtime_error("Unsupported framebuffer configuration: too many buffers (%d)", color.size());
|
||||
|
||||
for (size_t i = 0; i < color.size(); ++i)
|
||||
{
|
||||
RenderbufferD3D11* buffer = static_cast<RenderbufferD3D11*>(color[i].get());
|
||||
RBXASSERT(buffer);
|
||||
RBXASSERT(!Texture::isFormatDepth(buffer->getFormat()));
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
width = buffer->getWidth();
|
||||
height = buffer->getHeight();
|
||||
samples = buffer->getSamples();
|
||||
}
|
||||
else
|
||||
{
|
||||
RBXASSERT(width == buffer->getWidth());
|
||||
RBXASSERT(height == buffer->getHeight());
|
||||
RBXASSERT(samples == buffer->getSamples());
|
||||
}
|
||||
}
|
||||
|
||||
if (depth)
|
||||
{
|
||||
RenderbufferD3D11* buffer = static_cast<RenderbufferD3D11*>(depth.get());
|
||||
RBXASSERT(Texture::isFormatDepth(buffer->getFormat()));
|
||||
|
||||
RBXASSERT(width == buffer->getWidth());
|
||||
RBXASSERT(height == buffer->getHeight());
|
||||
RBXASSERT(samples == buffer->getSamples());
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferD3D11::download(void* data, unsigned int size)
|
||||
{
|
||||
RBXASSERT(size == width * height * 4);
|
||||
|
||||
DeviceD3D11* device11 = static_cast<DeviceD3D11*>(device);
|
||||
ID3D11DeviceContext* context11 = device11->getImmediateContext11();
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.MipLevels = 1;
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.ArraySize = 1;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* tempTex = NULL;
|
||||
HRESULT hr = device11->getDevice11()->CreateTexture2D(&desc, NULL, reinterpret_cast<ID3D11Texture2D**>(&tempTex));
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Download frame buffer cant create temp texture %x", hr);
|
||||
|
||||
// get resource bound to view
|
||||
ID3D11Resource* resource;
|
||||
RenderbufferD3D11* color0 = static_cast<RenderbufferD3D11*>(color[0].get());
|
||||
color0->getObject()->GetResource(&resource);
|
||||
RBXASSERT(color0->getFormat() == Texture::Format_RGBA8);
|
||||
|
||||
// copy resource to tex
|
||||
context11->CopyResource(tempTex, resource);
|
||||
|
||||
// copy texture to provided memory
|
||||
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
||||
hr = context11->Map(tempTex, 0, D3D11_MAP_READ, 0, &mappedResource);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
char* dataRow = static_cast<char*>(data) + y * width * 4;
|
||||
memcpy(dataRow, static_cast<char*>(mappedResource.pData) + y * mappedResource.RowPitch, width * 4);
|
||||
}
|
||||
|
||||
// release all the stuff
|
||||
context11->Unmap(tempTex, 0);
|
||||
resource->Release();
|
||||
ReleaseCheck(tempTex);
|
||||
}
|
||||
|
||||
FramebufferD3D11::~FramebufferD3D11()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "GfxCore/Framebuffer.h"
|
||||
#include "TextureD3D11.h"
|
||||
#include <vector>
|
||||
|
||||
struct ID3D11RenderTargetView;
|
||||
struct ID3D11DepthStencilView;
|
||||
struct ID3D11View;
|
||||
struct ID3D11Texture2D;
|
||||
struct ID3D11Device;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
|
||||
class RenderbufferD3D11: public Renderbuffer
|
||||
{
|
||||
public:
|
||||
RenderbufferD3D11(Device* device, const shared_ptr<TextureD3D11>& owner, unsigned cubeIndex, unsigned mipIndex);
|
||||
RenderbufferD3D11(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples, ID3D11Texture2D* texture);
|
||||
RenderbufferD3D11(Device* device, Texture::Format format, unsigned int width, unsigned int height, unsigned int samples);
|
||||
~RenderbufferD3D11();
|
||||
|
||||
ID3D11View* getObject() const { return object; }
|
||||
ID3D11Resource* getResource() const { return texture; }
|
||||
const shared_ptr<TextureD3D11>& getOwner() const { return owner; }
|
||||
|
||||
private:
|
||||
ID3D11View* object;
|
||||
ID3D11Resource* texture;
|
||||
shared_ptr<TextureD3D11> owner;
|
||||
};
|
||||
|
||||
class FramebufferD3D11: public Framebuffer
|
||||
{
|
||||
public:
|
||||
FramebufferD3D11(Device* device, const std::vector<shared_ptr<Renderbuffer>>& color, const shared_ptr<Renderbuffer>& depth);
|
||||
~FramebufferD3D11();
|
||||
|
||||
virtual void download(void* data, unsigned int size);
|
||||
|
||||
const std::vector<shared_ptr<Renderbuffer> >& getColor() const { return color; }
|
||||
const shared_ptr<Renderbuffer>& getDepth() const { return depth; }
|
||||
|
||||
private:
|
||||
std::vector<shared_ptr<Renderbuffer>> color;
|
||||
shared_ptr<Renderbuffer> depth;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
#include "GeometryD3D11.h"
|
||||
|
||||
#include "DeviceD3D11.h"
|
||||
#include "ShaderD3D11.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
|
||||
LOGGROUP(Graphics)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
struct BufferUsageD3D11
|
||||
{
|
||||
D3D11_USAGE usage;
|
||||
unsigned cpuAccess;
|
||||
};
|
||||
|
||||
static const BufferUsageD3D11 gBufferUsageD3D11[GeometryBuffer::Usage_Count] =
|
||||
{
|
||||
{ D3D11_USAGE_DEFAULT, 0 },
|
||||
{ D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE },
|
||||
};
|
||||
|
||||
static const DXGI_FORMAT gVertexLayoutFormatD3D11[VertexLayout::Format_Count] =
|
||||
{
|
||||
DXGI_FORMAT_R32_FLOAT,
|
||||
DXGI_FORMAT_R32G32_FLOAT,
|
||||
DXGI_FORMAT_R32G32B32_FLOAT,
|
||||
DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
DXGI_FORMAT_R16G16_SINT,
|
||||
DXGI_FORMAT_R16G16B16A16_SINT,
|
||||
DXGI_FORMAT_R8G8B8A8_UINT,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
};
|
||||
|
||||
static const LPCSTR gVertexLayoutSemanticD3D11[VertexLayout::Semantic_Count] =
|
||||
{
|
||||
"POSITION",
|
||||
"NORMAL",
|
||||
"COLOR",
|
||||
"TEXCOORD",
|
||||
};
|
||||
|
||||
static const D3D11_PRIMITIVE_TOPOLOGY gGeometryPrimitiveD3D11[Geometry::Primitive_Count] =
|
||||
{
|
||||
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
|
||||
D3D11_PRIMITIVE_TOPOLOGY_LINELIST,
|
||||
D3D11_PRIMITIVE_TOPOLOGY_POINTLIST,
|
||||
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP
|
||||
};
|
||||
|
||||
static const D3D11_MAP gLockModeD3D11[GeometryBuffer::Lock_Count] =
|
||||
{
|
||||
D3D11_MAP_WRITE,
|
||||
D3D11_MAP_WRITE_DISCARD
|
||||
};
|
||||
|
||||
VertexLayoutD3D11::VertexLayoutD3D11(Device* device, const std::vector<Element>& elements)
|
||||
: VertexLayout(device, elements)
|
||||
{
|
||||
|
||||
for (size_t i = 0; i < elements.size(); ++i)
|
||||
{
|
||||
const Element& e = elements[i];
|
||||
D3D11_INPUT_ELEMENT_DESC e11 = {};
|
||||
|
||||
e11.InputSlot = e.stream;
|
||||
e11.AlignedByteOffset = e.offset;
|
||||
e11.SemanticName = gVertexLayoutSemanticD3D11[e.semantic];
|
||||
e11.Format = gVertexLayoutFormatD3D11[e.format];
|
||||
e11.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
e11.InstanceDataStepRate = 0;
|
||||
e11.SemanticIndex = e.semanticIndex;
|
||||
|
||||
elements11.push_back(e11);
|
||||
}
|
||||
}
|
||||
|
||||
VertexLayoutD3D11::~VertexLayoutD3D11()
|
||||
{
|
||||
for (size_t i = 0; i < shaders.size(); ++i)
|
||||
{
|
||||
shared_ptr<VertexShaderD3D11> vertexShader = shaders[i].lock();
|
||||
if (vertexShader)
|
||||
vertexShader->removeLayout(this);
|
||||
}
|
||||
|
||||
static_cast<DeviceD3D11*>(device)->getImmediateContextD3D11()->invalidateCachedVertexLayout();
|
||||
}
|
||||
|
||||
void VertexLayoutD3D11::registerShader(const shared_ptr<VertexShaderD3D11>& shader)
|
||||
{
|
||||
shaders.push_back(weak_ptr<VertexShaderD3D11>(shader));
|
||||
}
|
||||
|
||||
template <typename Base> GeometryBufferD3D11<Base>::GeometryBufferD3D11(Device* device, size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage)
|
||||
: Base(device, elementSize, elementCount, usage)
|
||||
, locked(0)
|
||||
, object(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Base> void GeometryBufferD3D11<Base>::create(unsigned bindFlags)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
D3D11_BUFFER_DESC bd = {};
|
||||
bd.Usage = gBufferUsageD3D11[usage].usage;
|
||||
bd.ByteWidth = elementSize * elementCount;
|
||||
bd.BindFlags = bindFlags;
|
||||
bd.CPUAccessFlags = gBufferUsageD3D11[usage].cpuAccess;
|
||||
bd.MiscFlags = 0;
|
||||
bd.StructureByteStride = 0;
|
||||
|
||||
HRESULT hr = device11->CreateBuffer( &bd, NULL, &object );
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Couldn't create geometry buffer: %x", hr);
|
||||
}
|
||||
|
||||
template <typename Base> GeometryBufferD3D11<Base>::~GeometryBufferD3D11()
|
||||
{
|
||||
RBXASSERT(!locked);
|
||||
|
||||
ReleaseCheck(object);
|
||||
}
|
||||
|
||||
template <typename Base> void* GeometryBufferD3D11<Base>::lock(GeometryBuffer::LockMode mode)
|
||||
{
|
||||
RBXASSERT(!locked);
|
||||
|
||||
if (usage == Usage::Usage_Static)
|
||||
{
|
||||
locked = new char[elementSize * elementCount];
|
||||
}
|
||||
else
|
||||
{
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
D3D11_MAP mapMode = gLockModeD3D11[mode];
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE resource;
|
||||
HRESULT hr = context11->Map(object, 0, mapMode, 0, &resource);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
FASTLOG2(FLog::Graphics, "Failed to lock VB (size %d): %x", elementCount * elementSize, hr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
locked = resource.pData;
|
||||
}
|
||||
|
||||
RBXASSERT(locked);
|
||||
return locked;
|
||||
}
|
||||
|
||||
template <typename Base> void GeometryBufferD3D11<Base>::unlock()
|
||||
{
|
||||
RBXASSERT(locked);
|
||||
|
||||
if (usage == Usage::Usage_Static)
|
||||
{
|
||||
upload(0, locked, elementCount * elementSize);
|
||||
delete[] static_cast<char*>(locked);
|
||||
}
|
||||
else
|
||||
{
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
context11->Unmap(object, 0);
|
||||
}
|
||||
|
||||
locked = NULL;
|
||||
}
|
||||
|
||||
template <typename Base> void GeometryBufferD3D11<Base>::upload(unsigned int offset, const void* data, unsigned int size)
|
||||
{
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
D3D11_BOX box;
|
||||
box.left = offset;
|
||||
box.right = offset + size;
|
||||
box.top = 0;
|
||||
box.bottom = 1;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
|
||||
context11->UpdateSubresource(object, 0, &box, data, 0, 0);
|
||||
}
|
||||
|
||||
VertexBufferD3D11::VertexBufferD3D11(Device* device, size_t elementSize, size_t elementCount, Usage usage)
|
||||
: GeometryBufferD3D11<VertexBuffer>(device, elementSize, elementCount, usage)
|
||||
{
|
||||
create(D3D11_BIND_VERTEX_BUFFER);
|
||||
}
|
||||
|
||||
VertexBufferD3D11::~VertexBufferD3D11()
|
||||
{
|
||||
}
|
||||
|
||||
IndexBufferD3D11::IndexBufferD3D11(Device* device, size_t elementSize, size_t elementCount, Usage usage)
|
||||
: GeometryBufferD3D11<IndexBuffer>(device, elementSize, elementCount, usage)
|
||||
{
|
||||
if (elementSize != 2 && elementSize != 4)
|
||||
throw RBX::runtime_error("Invalid element size: %d", (int)elementSize);
|
||||
|
||||
create(D3D11_BIND_INDEX_BUFFER);
|
||||
}
|
||||
|
||||
IndexBufferD3D11::~IndexBufferD3D11()
|
||||
{
|
||||
}
|
||||
|
||||
GeometryD3D11::GeometryD3D11(Device* device, const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer> >& vertexBuffers, const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex)
|
||||
: Geometry(device, layout, vertexBuffers, indexBuffer, baseVertexIndex)
|
||||
{
|
||||
}
|
||||
|
||||
GeometryD3D11::~GeometryD3D11()
|
||||
{
|
||||
static_cast<DeviceD3D11*>(device)->getImmediateContextD3D11()->invalidateCachedGeometry();
|
||||
}
|
||||
|
||||
void GeometryD3D11::draw(Geometry::Primitive primitive, unsigned int offset, unsigned int count, unsigned int indexRangeBegin, unsigned int indexRangeEnd, VertexLayoutD3D11** layoutCache, GeometryD3D11** geometryCache, ShaderProgramD3D11** programCache)
|
||||
{
|
||||
RBXASSERT(*programCache);
|
||||
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
if (*layoutCache != layout.get())
|
||||
{
|
||||
VertexLayoutD3D11* vertexLayout = static_cast<VertexLayoutD3D11*>(layout.get());
|
||||
*layoutCache = vertexLayout;
|
||||
|
||||
ID3D11InputLayout* inputLayout11 = (*programCache)->getInputLayout11(vertexLayout);
|
||||
context11->IASetInputLayout(inputLayout11);
|
||||
}
|
||||
|
||||
if (*geometryCache != this)
|
||||
{
|
||||
*geometryCache = this;
|
||||
|
||||
for (size_t i = 0; i < vertexBuffers.size(); ++i)
|
||||
{
|
||||
VertexBufferD3D11* vb = static_cast<VertexBufferD3D11*>(vertexBuffers[i].get());
|
||||
ID3D11Buffer* vb11 = vb->getObject();
|
||||
unsigned int offsetVB = 0;
|
||||
unsigned int stride = vb->getElementSize();
|
||||
context11->IASetVertexBuffers(i, 1, &vb11, &stride, &offsetVB);
|
||||
}
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
DXGI_FORMAT format = indexBuffer->getElementSize() == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
|
||||
context11->IASetIndexBuffer(static_cast<IndexBufferD3D11*>(indexBuffer.get())->getObject(), format, 0);
|
||||
}
|
||||
}
|
||||
|
||||
(*programCache)->uploadConstantBuffers();
|
||||
|
||||
context11->IASetPrimitiveTopology(gGeometryPrimitiveD3D11[primitive]);
|
||||
|
||||
if (indexBuffer)
|
||||
context11->DrawIndexed(count, offset, baseVertexIndex);
|
||||
else
|
||||
context11->Draw(count, offset);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include "GfxCore/Geometry.h"
|
||||
|
||||
struct ID3D11InputLayout;
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11DeviceContext;
|
||||
struct D3D11_INPUT_ELEMENT_DESC;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
|
||||
class ShaderProgramD3D11;
|
||||
class VertexShaderD3D11;
|
||||
|
||||
class VertexLayoutD3D11: public VertexLayout
|
||||
{
|
||||
public:
|
||||
VertexLayoutD3D11(Device* device, const std::vector<Element>& elements);
|
||||
~VertexLayoutD3D11();
|
||||
|
||||
const D3D11_INPUT_ELEMENT_DESC* getElements11() const { return elements11.data(); }
|
||||
size_t getElementsCount() const { return elements11.size(); }
|
||||
|
||||
void registerShader(const shared_ptr<VertexShaderD3D11>& shader);
|
||||
|
||||
private:
|
||||
std::vector<D3D11_INPUT_ELEMENT_DESC> elements11;
|
||||
std::vector<weak_ptr<VertexShaderD3D11>> shaders; // shaders having this vertex declaration
|
||||
};
|
||||
|
||||
template <typename Base> class GeometryBufferD3D11: public Base
|
||||
{
|
||||
public:
|
||||
GeometryBufferD3D11(Device* device, size_t elementSize, size_t elementCount, GeometryBuffer::Usage usage);
|
||||
~GeometryBufferD3D11();
|
||||
|
||||
virtual void* lock(GeometryBuffer::LockMode mode);
|
||||
virtual void unlock();
|
||||
|
||||
virtual void upload(unsigned int offset, const void* data, unsigned int size);
|
||||
|
||||
ID3D11Buffer* getObject() const { return object; }
|
||||
|
||||
protected:
|
||||
void create(unsigned bindFlags);
|
||||
|
||||
private:
|
||||
ID3D11Buffer* object;
|
||||
|
||||
void* locked;
|
||||
};
|
||||
|
||||
|
||||
class VertexBufferD3D11: public GeometryBufferD3D11<VertexBuffer>
|
||||
{
|
||||
public:
|
||||
VertexBufferD3D11(Device* device, size_t elementSize, size_t elementCount, Usage usage);
|
||||
~VertexBufferD3D11();
|
||||
};
|
||||
|
||||
class IndexBufferD3D11: public GeometryBufferD3D11<IndexBuffer>
|
||||
{
|
||||
public:
|
||||
IndexBufferD3D11(Device* device, size_t elementSize, size_t elementCount, Usage usage);
|
||||
~IndexBufferD3D11();
|
||||
};
|
||||
|
||||
class GeometryD3D11: public Geometry
|
||||
{
|
||||
public:
|
||||
GeometryD3D11(Device* device, const shared_ptr<VertexLayout>& layout, const std::vector<shared_ptr<VertexBuffer> >& vertexBuffers, const shared_ptr<IndexBuffer>& indexBuffer, unsigned int baseVertexIndex);
|
||||
~GeometryD3D11();
|
||||
|
||||
void draw(Geometry::Primitive primitive, unsigned int offset, unsigned int count, unsigned int indexRangeBegin, unsigned int indexRangeEnd, VertexLayoutD3D11** layoutCache, GeometryD3D11** geometryCache, ShaderProgramD3D11** programCache);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(RBX_PLATFORM_DURANGO)
|
||||
# include <d3d11_x.h>
|
||||
# include <D3Dcompiler_x.h>
|
||||
# include <xdk.h>
|
||||
#else
|
||||
# include <D3D11.h>
|
||||
# include <D3Dcompiler.h>
|
||||
#endif
|
||||
@@ -0,0 +1,335 @@
|
||||
#if !defined(RBX_PLATFORM_DURANGO) && !defined(RBX_PLATFORM_UWP)
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "FramebufferD3D11.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
LOGGROUP(VR)
|
||||
|
||||
FASTFLAGVARIABLE(DebugRenderVRHUD, false)
|
||||
|
||||
#include "../Rendering/LibOVR/Include/OVR_CAPI_D3D.h"
|
||||
|
||||
#pragma comment(lib, "../Rendering/LibOVR/Lib/Windows/Win32/Release/VS2012/LibOVR.lib")
|
||||
|
||||
#define OVR_CHECK(call) \
|
||||
do { \
|
||||
ovrResult vrResult = call; \
|
||||
if (OVR_FAILURE(vrResult)) FASTLOG1(FLog::VR, "VR ERROR: " #call " returned %d", vrResult); \
|
||||
} while (0)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
typedef HRESULT (WINAPI *TypeCreateDXGIFactory)(REFIID riid, void **ppFactory);
|
||||
|
||||
static TypeCreateDXGIFactory getFactoryCreationFunction()
|
||||
{
|
||||
HMODULE module = LoadLibraryA("d3d11.dll");
|
||||
if (!module) return NULL;
|
||||
|
||||
return (TypeCreateDXGIFactory)GetProcAddress(module, "CreateDXGIFactory");
|
||||
}
|
||||
|
||||
static IDXGIAdapter* getAdapterForLuid(LUID luid)
|
||||
{
|
||||
// Allow to use null/default adapter for applications that may render a window without an HMD.
|
||||
if ((luid.HighPart | luid.LowPart) == 0)
|
||||
return NULL;
|
||||
|
||||
TypeCreateDXGIFactory createFactory = getFactoryCreationFunction();
|
||||
if (!createFactory)
|
||||
return NULL;
|
||||
|
||||
// Try to find adapter by LUID
|
||||
IDXGIFactory* factory = NULL;
|
||||
if (FAILED(createFactory(__uuidof(IDXGIFactory), (void**)&factory)))
|
||||
return NULL;
|
||||
|
||||
UINT index = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
IDXGIAdapter* adapter = NULL;
|
||||
|
||||
if (SUCCEEDED(factory->EnumAdapters(index, &adapter)) && adapter)
|
||||
{
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
|
||||
if (SUCCEEDED(adapter->GetDesc(&desc)) && desc.AdapterLuid.HighPart == luid.HighPart && desc.AdapterLuid.LowPart == luid.LowPart)
|
||||
{
|
||||
ReleaseCheck(factory);
|
||||
|
||||
return adapter;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
ReleaseCheck(factory);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static DeviceVR::Pose getPose(const ovrPosef& pose, unsigned int statusFlags)
|
||||
{
|
||||
DeviceVR::Pose result = {};
|
||||
|
||||
result.valid = (statusFlags & ovrStatus_OrientationTracked) != 0;
|
||||
|
||||
result.position[0] = pose.Position.x;
|
||||
result.position[1] = pose.Position.y;
|
||||
result.position[2] = pose.Position.z;
|
||||
|
||||
result.orientation[0] = pose.Orientation.x;
|
||||
result.orientation[1] = pose.Orientation.y;
|
||||
result.orientation[2] = pose.Orientation.z;
|
||||
result.orientation[3] = pose.Orientation.w;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct VRTexture
|
||||
{
|
||||
static const int kMaxCount = 4;
|
||||
|
||||
shared_ptr<Framebuffer> fb[kMaxCount];
|
||||
ovrSwapTextureSet* textureSet;
|
||||
|
||||
VRTexture(): textureSet(NULL)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct OculusVRD3D11: DeviceVRD3D11
|
||||
{
|
||||
ovrSession session;
|
||||
ovrHmdDesc desc;
|
||||
VRTexture textures[2];
|
||||
ovrEyeRenderDesc eyeDesc[2];
|
||||
|
||||
double sensorSampleTime;
|
||||
ovrTrackingState trackingState;
|
||||
|
||||
OculusVRD3D11(): session(NULL), sensorSampleTime(0)
|
||||
{
|
||||
}
|
||||
|
||||
~OculusVRD3D11()
|
||||
{
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
ovr_DestroySwapTextureSet(session, textures[eye].textureSet);
|
||||
|
||||
ovr_Destroy(session);
|
||||
ovr_Shutdown();
|
||||
}
|
||||
|
||||
void update() override
|
||||
{
|
||||
double frameTime = ovr_GetPredictedDisplayTime(session, 0);
|
||||
|
||||
// Keeping sensorSampleTime as close to ovr_GetTrackingState as possible - fed into the layer
|
||||
sensorSampleTime = ovr_GetTimeInSeconds();
|
||||
trackingState = ovr_GetTrackingState(session, frameTime, ovrTrue);
|
||||
}
|
||||
|
||||
void recenter() override
|
||||
{
|
||||
ovr_RecenterPose(session);
|
||||
}
|
||||
|
||||
Framebuffer* getEyeFramebuffer(int eye) override
|
||||
{
|
||||
RBXASSERT(eye == 0 || eye == 1);
|
||||
|
||||
return textures[eye].fb[textures[eye].textureSet->CurrentIndex].get();
|
||||
}
|
||||
|
||||
State getState() override
|
||||
{
|
||||
State result = {};
|
||||
|
||||
result.headPose = getPose(trackingState.HeadPose.ThePose, trackingState.StatusFlags);
|
||||
result.handPose[0] = getPose(trackingState.HandPoses[0].ThePose, trackingState.HandStatusFlags[0]);
|
||||
result.handPose[1] = getPose(trackingState.HandPoses[1].ThePose, trackingState.HandStatusFlags[1]);
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
{
|
||||
result.eyeOffset[eye][0] = eyeDesc[eye].HmdToEyeViewOffset.x;
|
||||
result.eyeOffset[eye][1] = eyeDesc[eye].HmdToEyeViewOffset.y;
|
||||
result.eyeOffset[eye][2] = eyeDesc[eye].HmdToEyeViewOffset.z;
|
||||
|
||||
result.eyeFov[eye][0] = eyeDesc[eye].Fov.UpTan;
|
||||
result.eyeFov[eye][1] = eyeDesc[eye].Fov.DownTan;
|
||||
result.eyeFov[eye][2] = eyeDesc[eye].Fov.LeftTan;
|
||||
result.eyeFov[eye][3] = eyeDesc[eye].Fov.RightTan;
|
||||
}
|
||||
|
||||
result.needsMirror = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void submitFrame(DeviceContext* context) override
|
||||
{
|
||||
ovrLayerEyeFov ld = {};
|
||||
ld.Header.Type = ovrLayerType_EyeFov;
|
||||
ld.Header.Flags = 0;
|
||||
|
||||
ovrVector3f hmdToEyeViewOffset[2] = { eyeDesc[0].HmdToEyeViewOffset, eyeDesc[1].HmdToEyeViewOffset };
|
||||
ovrPosef eyeRenderPoses[2];
|
||||
ovr_CalcEyePoses(trackingState.HeadPose.ThePose, hmdToEyeViewOffset, eyeRenderPoses);
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
{
|
||||
ld.ColorTexture[eye] = textures[eye].textureSet;
|
||||
ld.Viewport[eye].Pos.x = 0;
|
||||
ld.Viewport[eye].Pos.y = 0;
|
||||
ld.Viewport[eye].Size.w = textures[eye].fb[0]->getWidth();
|
||||
ld.Viewport[eye].Size.h = textures[eye].fb[0]->getHeight();
|
||||
ld.Fov[eye] = eyeDesc[eye].Fov;
|
||||
ld.RenderPose[eye] = eyeRenderPoses[eye];
|
||||
ld.SensorSampleTime = sensorSampleTime;
|
||||
}
|
||||
|
||||
ovrViewScaleDesc viewScaleDesc;
|
||||
viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
|
||||
viewScaleDesc.HmdToEyeViewOffset[0] = eyeDesc[0].HmdToEyeViewOffset;
|
||||
viewScaleDesc.HmdToEyeViewOffset[1] = eyeDesc[1].HmdToEyeViewOffset;
|
||||
|
||||
ovrLayerHeader* layers = &ld.Header;
|
||||
OVR_CHECK(ovr_SubmitFrame(session, 0, &viewScaleDesc, &layers, 1));
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
{
|
||||
textures[eye].textureSet->CurrentIndex += 1;
|
||||
textures[eye].textureSet->CurrentIndex %= textures[eye].textureSet->TextureCount;
|
||||
}
|
||||
|
||||
if (FFlag::DebugRenderVRHUD)
|
||||
{
|
||||
static bool keyWasDown = false;
|
||||
bool keyIsDown = (GetAsyncKeyState(VK_CONTROL) < 0 && GetAsyncKeyState(VK_F8) < 0);
|
||||
|
||||
if (keyIsDown && !keyWasDown)
|
||||
{
|
||||
int perfHudMode = ovr_GetInt(session, OVR_PERF_HUD_MODE, 0);
|
||||
|
||||
perfHudMode += 1;
|
||||
perfHudMode %= ovrPerfHud_Count;
|
||||
|
||||
ovr_SetInt(session, OVR_PERF_HUD_MODE, perfHudMode);
|
||||
}
|
||||
|
||||
keyWasDown = keyIsDown;
|
||||
}
|
||||
}
|
||||
|
||||
void setup(Device* device) override
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
// Work around a bug in LibOVR
|
||||
ShowWindow(static_cast<HWND>(static_cast<DeviceD3D11*>(device)->getWindowHandle()), SW_SHOWNORMAL);
|
||||
|
||||
ovrSizei idealSizeLeft = ovr_GetFovTextureSize(session, ovrEye_Left, desc.DefaultEyeFov[ovrEye_Left], 1.0f);
|
||||
ovrSizei idealSizeRight = ovr_GetFovTextureSize(session, ovrEye_Right, desc.DefaultEyeFov[ovrEye_Right], 1.0f);
|
||||
|
||||
unsigned int width = std::max(idealSizeLeft.w, idealSizeRight.w);
|
||||
unsigned int height = std::max(idealSizeLeft.h, idealSizeRight.h);
|
||||
|
||||
shared_ptr<Renderbuffer> depthStencil = shared_ptr<Renderbuffer>(new RenderbufferD3D11(device, Texture::Format_D24S8, width, height, 1));
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC dsDesc;
|
||||
dsDesc.Width = width;
|
||||
dsDesc.Height = height;
|
||||
dsDesc.MipLevels = 1;
|
||||
dsDesc.ArraySize = 1;
|
||||
dsDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
|
||||
dsDesc.SampleDesc.Count = 1;
|
||||
dsDesc.SampleDesc.Quality = 0;
|
||||
dsDesc.Usage = D3D11_USAGE_DEFAULT;
|
||||
dsDesc.CPUAccessFlags = 0;
|
||||
dsDesc.MiscFlags = 0;
|
||||
dsDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
|
||||
|
||||
ovrResult result = ovr_CreateSwapTextureSetD3D11(session, device11, &dsDesc, ovrSwapTextureSetD3D11_Typeless, &textures[eye].textureSet);
|
||||
if (OVR_FAILURE(result))
|
||||
throw RBX::runtime_error("ovr_CreateSwapTextureSetD3D11 failed with %d", result);
|
||||
|
||||
RBXASSERT(textures[eye].textureSet->TextureCount <= VRTexture::kMaxCount);
|
||||
|
||||
for (int i = 0; i < textures[eye].textureSet->TextureCount; ++i)
|
||||
{
|
||||
ovrD3D11Texture* tex = reinterpret_cast<ovrD3D11Texture*>(&textures[eye].textureSet->Textures[i]);
|
||||
|
||||
tex->D3D11.pTexture->AddRef();
|
||||
|
||||
shared_ptr<Renderbuffer> colorBuffer(new RenderbufferD3D11(device, Texture::Format_RGBA8, width, height, 1, tex->D3D11.pTexture));
|
||||
|
||||
textures[eye].fb[i] = device->createFramebuffer(colorBuffer, depthStencil);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void logCallback(uintptr_t userData, int level, const char* message)
|
||||
{
|
||||
FASTLOGS(FLog::VR, "VR: %s", message);
|
||||
}
|
||||
|
||||
DeviceVRD3D11* DeviceVRD3D11::createOculus(IDXGIAdapter** outAdapter)
|
||||
{
|
||||
ovrInitParams params = {};
|
||||
|
||||
params.LogCallback = logCallback;
|
||||
|
||||
ovrResult vrResult = ovr_Initialize(¶ms);
|
||||
|
||||
if (!OVR_SUCCESS(vrResult))
|
||||
{
|
||||
FASTLOG1(FLog::VR, "VR: ovr_Initialize returned %d", vrResult);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ovrSession session;
|
||||
ovrGraphicsLuid vrLuid;
|
||||
|
||||
vrResult = ovr_Create(&session, &vrLuid);
|
||||
|
||||
if (!OVR_SUCCESS(vrResult))
|
||||
{
|
||||
FASTLOG1(FLog::VR, "VR: ovr_Create returned %d", vrResult);
|
||||
|
||||
ovr_Shutdown();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OculusVRD3D11* vr = new OculusVRD3D11();
|
||||
|
||||
vr->session = session;
|
||||
vr->desc = ovr_GetHmdDesc(session);
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
vr->eyeDesc[eye] = ovr_GetRenderDesc(session, (ovrEyeType)eye, vr->desc.DefaultEyeFov[eye]);
|
||||
|
||||
if (outAdapter)
|
||||
*outAdapter = getAdapterForLuid(*reinterpret_cast<LUID*>(&vrLuid));
|
||||
|
||||
FASTLOGS(FLog::VR, "VR: Connected to %s", vr->desc.ProductName);
|
||||
FASTLOG4(FLog::VR, "VR: Vendor %x Product %x Firmware %d.%d", vr->desc.VendorId, vr->desc.ProductId, vr->desc.FirmwareMajor, vr->desc.FirmwareMinor);
|
||||
|
||||
return vr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,270 @@
|
||||
#if !defined(RBX_PLATFORM_DURANGO) && !defined(RBX_PLATFORM_UWP)
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "FramebufferD3D11.h"
|
||||
|
||||
#include "G3D/Quat.h"
|
||||
|
||||
#include "rbx/Profiler.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
LOGGROUP(VR)
|
||||
|
||||
FASTFLAGVARIABLE(OpenVR, true)
|
||||
|
||||
#include "../Rendering/OpenVR/headers/openvr.h"
|
||||
|
||||
using namespace vr;
|
||||
|
||||
#define OVR_CHECK(call) \
|
||||
do { \
|
||||
int vrResult = call; \
|
||||
if (vrResult) FASTLOG1(FLog::VR, "VR ERROR: " #call " returned %d", vrResult); \
|
||||
} while (0)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
using G3D::Quat;
|
||||
using G3D::Vector3;
|
||||
using G3D::Matrix3;
|
||||
|
||||
typedef HRESULT (WINAPI *TypeCreateDXGIFactory)(REFIID riid, void **ppFactory);
|
||||
|
||||
static TypeCreateDXGIFactory getFactoryCreationFunction()
|
||||
{
|
||||
HMODULE module = LoadLibraryA("d3d11.dll");
|
||||
if (!module) return NULL;
|
||||
|
||||
return (TypeCreateDXGIFactory)GetProcAddress(module, "CreateDXGIFactory");
|
||||
}
|
||||
|
||||
template <typename F> static F getOpenVRFunction(const char* name)
|
||||
{
|
||||
HMODULE module = LoadLibraryA("openvr_api.dll");
|
||||
if (!module) return NULL;
|
||||
|
||||
return F(GetProcAddress(module, name));
|
||||
}
|
||||
|
||||
static IDXGIAdapter* getAdapterForIndex(int index)
|
||||
{
|
||||
TypeCreateDXGIFactory createFactory = getFactoryCreationFunction();
|
||||
if (!createFactory)
|
||||
return NULL;
|
||||
|
||||
// Try to find adapter by LUID
|
||||
IDXGIFactory* factory = NULL;
|
||||
if (FAILED(createFactory(__uuidof(IDXGIFactory), (void**)&factory)))
|
||||
return NULL;
|
||||
|
||||
IDXGIAdapter* adapter = NULL;
|
||||
factory->EnumAdapters(index, &adapter);
|
||||
|
||||
ReleaseCheck(factory);
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
static std::string getStringProperty(IVRSystem* system, TrackedDeviceIndex_t device, TrackedDeviceProperty property)
|
||||
{
|
||||
char buf[128] = {};
|
||||
system->GetStringTrackedDeviceProperty(device, property, buf, sizeof(buf), NULL);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static DeviceVR::Pose getPose(const TrackedDevicePose_t& pose)
|
||||
{
|
||||
const HmdMatrix34_t& m = pose.mDeviceToAbsoluteTracking;
|
||||
|
||||
Quat orientation(Matrix3(m.m[0][0], m.m[0][1], m.m[0][2], m.m[1][0], m.m[1][1], m.m[1][2], m.m[2][0], m.m[2][1], m.m[2][2]));
|
||||
|
||||
DeviceVR::Pose result = {};
|
||||
|
||||
result.valid = pose.bPoseIsValid;
|
||||
|
||||
result.position[0] = m.m[0][3];
|
||||
result.position[1] = m.m[1][3];
|
||||
result.position[2] = m.m[2][3];
|
||||
|
||||
result.orientation[0] = orientation.x;
|
||||
result.orientation[1] = orientation.y;
|
||||
result.orientation[2] = orientation.z;
|
||||
result.orientation[3] = orientation.w;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DeviceVR::Pose getPoseForIndex(IVRCompositor* compositor, TrackedDeviceIndex_t index)
|
||||
{
|
||||
TrackedDevicePose_t pose;
|
||||
OVR_CHECK(compositor->GetLastPoseForTrackedDeviceIndex(index, &pose, NULL));
|
||||
|
||||
return getPose(pose);
|
||||
}
|
||||
|
||||
static DeviceVR::Pose getPoseForRole(IVRSystem* system, IVRCompositor* compositor, ETrackedControllerRole role)
|
||||
{
|
||||
TrackedDeviceIndex_t index = system->GetTrackedDeviceIndexForControllerRole(role);
|
||||
if (index == k_unTrackedDeviceIndexInvalid)
|
||||
return DeviceVR::Pose();
|
||||
|
||||
return getPoseForIndex(compositor, index);
|
||||
}
|
||||
|
||||
struct OpenVRD3D11: DeviceVRD3D11
|
||||
{
|
||||
IVRSystem* system;
|
||||
IVRCompositor* compositor;
|
||||
|
||||
shared_ptr<Framebuffer> fb[2];
|
||||
shared_ptr<Texture> textures[2];
|
||||
|
||||
OpenVRD3D11(): system(NULL), compositor(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~OpenVRD3D11()
|
||||
{
|
||||
auto VR_ShutdownInternal = getOpenVRFunction<void (*)()>("VR_ShutdownInternal");
|
||||
|
||||
if (VR_ShutdownInternal)
|
||||
VR_ShutdownInternal();
|
||||
}
|
||||
|
||||
void update() override
|
||||
{
|
||||
compositor->SetTrackingSpace(TrackingUniverseSeated);
|
||||
}
|
||||
|
||||
void recenter() override
|
||||
{
|
||||
system->ResetSeatedZeroPose();
|
||||
}
|
||||
|
||||
Framebuffer* getEyeFramebuffer(int eye) override
|
||||
{
|
||||
RBXASSERT(eye == 0 || eye == 1);
|
||||
|
||||
return fb[eye].get();
|
||||
}
|
||||
|
||||
State getState() override
|
||||
{
|
||||
State result = {};
|
||||
|
||||
result.headPose = getPoseForIndex(compositor, k_unTrackedDeviceIndex_Hmd);
|
||||
result.handPose[0] = getPoseForRole(system, compositor, TrackedControllerRole_LeftHand);
|
||||
result.handPose[1] = getPoseForRole(system, compositor, TrackedControllerRole_RightHand);
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
{
|
||||
HmdMatrix34_t eyeToHead = system->GetEyeToHeadTransform(EVREye(eye));
|
||||
|
||||
result.eyeOffset[eye][0] = eyeToHead.m[0][3];
|
||||
result.eyeOffset[eye][1] = eyeToHead.m[1][3];
|
||||
result.eyeOffset[eye][2] = eyeToHead.m[2][3];
|
||||
|
||||
float upTan, downTan, leftTan, rightTan;
|
||||
system->GetProjectionRaw(EVREye(eye), &leftTan, &rightTan, &upTan, &downTan);
|
||||
|
||||
result.eyeFov[eye][0] = -upTan;
|
||||
result.eyeFov[eye][1] = downTan;
|
||||
result.eyeFov[eye][2] = -leftTan;
|
||||
result.eyeFov[eye][3] = rightTan;
|
||||
}
|
||||
|
||||
result.needsMirror = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void submitFrame(DeviceContext* context) override
|
||||
{
|
||||
RBXPROFILER_SCOPE("VR", "submitFrame");
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
{
|
||||
Texture_t texture = { static_cast<TextureD3D11*>(textures[eye].get())->getObject(), API_DirectX, ColorSpace_Gamma };
|
||||
OVR_CHECK(compositor->Submit(EVREye(eye), &texture));
|
||||
}
|
||||
|
||||
OVR_CHECK(compositor->WaitGetPoses(NULL, 0, NULL, 0));
|
||||
}
|
||||
|
||||
void setup(Device* device) override
|
||||
{
|
||||
unsigned int width, height;
|
||||
system->GetRecommendedRenderTargetSize(&width, &height);
|
||||
|
||||
shared_ptr<Renderbuffer> depthStencil = device->createRenderbuffer(Texture::Format_D24S8, width, height, 1);
|
||||
|
||||
for (int eye = 0; eye < 2; ++eye)
|
||||
{
|
||||
textures[eye] = device->createTexture(Texture::Type_2D, Texture::Format_RGBA8, width, height, 1, 1, Texture::Usage_Renderbuffer);
|
||||
fb[eye] = device->createFramebuffer(textures[eye]->getRenderbuffer(0, 0), depthStencil);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DeviceVRD3D11* DeviceVRD3D11::createOpenVR(IDXGIAdapter** outAdapter)
|
||||
{
|
||||
if (!FFlag::OpenVR)
|
||||
return NULL;
|
||||
|
||||
auto VR_InitInternal = getOpenVRFunction<uint32_t (*)(EVRInitError *peError, EVRApplicationType eApplicationType)>("VR_InitInternal");
|
||||
auto VR_ShutdownInternal = getOpenVRFunction<void (*)()>("VR_ShutdownInternal");
|
||||
auto VR_GetGenericInterface = getOpenVRFunction<void* (*)(const char *pchInterfaceVersion, EVRInitError *peError)>("VR_GetGenericInterface");
|
||||
|
||||
if (!VR_InitInternal || !VR_ShutdownInternal || !VR_GetGenericInterface)
|
||||
return NULL;
|
||||
|
||||
EVRInitError error;
|
||||
VR_InitInternal(&error, VRApplication_Scene);
|
||||
|
||||
if (error)
|
||||
{
|
||||
FASTLOG1(FLog::VR, "VR: VR_InitInternal returned %d", error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IVRSystem* system = static_cast<IVRSystem*>(VR_GetGenericInterface(IVRSystem_Version, &error));
|
||||
|
||||
if (!system)
|
||||
{
|
||||
FASTLOG1(FLog::VR, "VR: Error creating system: %d", error);
|
||||
VR_ShutdownInternal();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IVRCompositor* compositor = static_cast<IVRCompositor*>(VR_GetGenericInterface(IVRCompositor_Version, &error));
|
||||
|
||||
if (!compositor)
|
||||
{
|
||||
FASTLOG1(FLog::VR, "VR: Error creating compositor: %d", error);
|
||||
VR_ShutdownInternal();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int adapterIndex = 0;
|
||||
system->GetDXGIOutputInfo(&adapterIndex);
|
||||
|
||||
OpenVRD3D11* vr = new OpenVRD3D11();
|
||||
|
||||
vr->system = system;
|
||||
vr->compositor = compositor;
|
||||
|
||||
if (outAdapter)
|
||||
*outAdapter = getAdapterForIndex(adapterIndex);
|
||||
|
||||
FASTLOGS(FLog::VR, "VR: Connected to %s", getStringProperty(system, k_unTrackedDeviceIndex_Hmd, Prop_ModelNumber_String));
|
||||
|
||||
return vr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,765 @@
|
||||
#define INITGUID
|
||||
#include "ShaderD3D11.h"
|
||||
|
||||
#include "GeometryD3D11.h"
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
LOGGROUP(Graphics)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
typedef HRESULT (WINAPI *TypeD3DCompile)(LPCVOID, SIZE_T, LPCSTR, const D3D_SHADER_MACRO *, ID3DInclude *, LPCSTR, LPCSTR, UINT, UINT, ID3DBlob **, ID3DBlob **);
|
||||
typedef HRESULT (WINAPI *TypeD3DPreprocess)(LPCVOID, SIZE_T, LPCSTR, const D3D_SHADER_MACRO *, ID3DInclude *, ID3DBlob **, ID3DBlob **);
|
||||
typedef HRESULT (WINAPI *TypeD3DReflect)(LPCVOID, SIZE_T, REFIID, void**);
|
||||
|
||||
static TypeD3DCompile loadShaderCompiler()
|
||||
{
|
||||
#if !defined(RBX_PLATFORM_DURANGO)
|
||||
HMODULE d3dCompiler = ShaderProgramD3D11::loadShaderCompilerDLL();
|
||||
|
||||
return d3dCompiler ? (TypeD3DCompile)GetProcAddress(d3dCompiler, "D3DCompile") : NULL;
|
||||
#else
|
||||
return &D3DCompile;
|
||||
#endif
|
||||
}
|
||||
|
||||
static TypeD3DPreprocess loadShaderPreprocessor()
|
||||
{
|
||||
#if !defined(RBX_PLATFORM_DURANGO)
|
||||
HMODULE d3dCompiler = ShaderProgramD3D11::loadShaderCompilerDLL();
|
||||
|
||||
return d3dCompiler ? (TypeD3DPreprocess)GetProcAddress(d3dCompiler, "D3DPreprocess") : NULL;
|
||||
#else
|
||||
return &D3DPreprocess;
|
||||
#endif
|
||||
}
|
||||
|
||||
static TypeD3DReflect loadShaderReflector()
|
||||
{
|
||||
#if !defined(RBX_PLATFORM_DURANGO)
|
||||
HMODULE d3dCompiler = ShaderProgramD3D11::loadShaderCompilerDLL();
|
||||
|
||||
return d3dCompiler ? (TypeD3DReflect)GetProcAddress(d3dCompiler, "D3DReflect") : NULL;
|
||||
#else
|
||||
return &D3DReflect;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void extractCbuffers(Device* device, const std::vector<char>& bytecode, std::vector<shared_ptr<CBufferD3D11>>& cbuffers, unsigned globalSize, unsigned int* outSamplerMask)
|
||||
{
|
||||
TypeD3DReflect D3DReflect = loadShaderReflector();
|
||||
RBXASSERT(D3DReflect);
|
||||
|
||||
cbuffers.clear();
|
||||
|
||||
ID3D11ShaderReflection* shaderReflection11 = NULL;
|
||||
HRESULT hr = D3DReflect(bytecode.data(), bytecode.size(), IID_ID3D11ShaderReflection, (void**) &shaderReflection11);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
D3D11_SHADER_DESC shaderDesc;
|
||||
shaderReflection11->GetDesc( &shaderDesc );
|
||||
|
||||
unsigned int samplerMask = 0;
|
||||
for (unsigned i = 0; i < shaderDesc.BoundResources; ++i)
|
||||
{
|
||||
D3D11_SHADER_INPUT_BIND_DESC desc;
|
||||
HRESULT hr =shaderReflection11->GetResourceBindingDesc (i, &desc);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
if(desc.Type == D3D_SIT_TEXTURE)
|
||||
{
|
||||
samplerMask |= 1 << desc.BindPoint;
|
||||
}
|
||||
else if(desc.Type == D3D_SIT_CBUFFER)
|
||||
{
|
||||
ID3D11ShaderReflectionConstantBuffer* cb = shaderReflection11->GetConstantBufferByName(desc.Name);
|
||||
|
||||
D3D11_SHADER_BUFFER_DESC cbDesc;
|
||||
cb->GetDesc( &cbDesc );
|
||||
|
||||
if (cbDesc.Type == D3D11_CT_CBUFFER)
|
||||
{
|
||||
|
||||
if (desc.BindPoint == 0)
|
||||
{
|
||||
bool isGlobals = strcmp(cbDesc.Name, "Globals") == 0;
|
||||
|
||||
if (!isGlobals)
|
||||
throw std::runtime_error("D3D11 Shader compilation: Globals are not bound to register 0 (or not bound at all)");
|
||||
|
||||
if (isGlobals && cbDesc.Size != globalSize)
|
||||
throw std::runtime_error("D3D11 Shader compilation: Globals CBuffer size is not the same as defined CBuffer size");
|
||||
|
||||
continue; // globals are same for all the shaders globally in deviceContext, so we want to skip it here
|
||||
}
|
||||
|
||||
std::vector<UniformD3D11> uniforms;
|
||||
|
||||
for ( unsigned varId = 0; varId < cbDesc.Variables; ++varId )
|
||||
{
|
||||
ID3D11ShaderReflectionVariable* var = cb->GetVariableByIndex( varId );
|
||||
|
||||
D3D11_SHADER_VARIABLE_DESC varDesc;
|
||||
var->GetDesc(&varDesc);
|
||||
|
||||
ID3D11ShaderReflectionType* type = var->GetType();
|
||||
D3D11_SHADER_TYPE_DESC typeDesc;
|
||||
type->GetDesc( &typeDesc );
|
||||
|
||||
UniformD3D11 uniform = UniformD3D11();
|
||||
uniform.name = varDesc.Name;
|
||||
uniform.offset = varDesc.StartOffset;
|
||||
uniform.size = varDesc.Size;
|
||||
uniforms.push_back(uniform);
|
||||
}
|
||||
|
||||
cbuffers.push_back(shared_ptr<CBufferD3D11>(new CBufferD3D11(device, desc.BindPoint, cbDesc.Name, cbDesc.Size, uniforms)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (outSamplerMask)
|
||||
*outSamplerMask = samplerMask;
|
||||
|
||||
ReleaseCheck(shaderReflection11);
|
||||
}
|
||||
|
||||
static int findCBuffer(const std::vector<shared_ptr<CBufferD3D11>>& cBuffers, const std::string& name)
|
||||
{
|
||||
for(unsigned i = 0; i < cBuffers.size(); ++i)
|
||||
{
|
||||
if (cBuffers[i]->getName() == name)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ID3D11VertexShader* createVertexShader(Device* device, const std::vector<char>& bytecode,
|
||||
std::vector<shared_ptr<CBufferD3D11>>& cbuffers, int& uniformsCBuffer, unsigned& maxWorldTransforms, int& worldMatCBuffer, int& uniformWorldMatrix, int& uniformWorldMatrixArray)
|
||||
{
|
||||
DeviceContextD3D11* context = static_cast<DeviceD3D11*>(device)->getImmediateContextD3D11();
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
extractCbuffers(device, bytecode, cbuffers, context->getGlobalDataSize(), NULL);
|
||||
|
||||
uniformsCBuffer = findCBuffer(cbuffers, "$Globals");
|
||||
worldMatCBuffer = findCBuffer(cbuffers, "WorldMatrixCB");
|
||||
|
||||
if (worldMatCBuffer >= 0)
|
||||
{
|
||||
uniformWorldMatrix = cbuffers[worldMatCBuffer]->findUniform("WorldMatrix");
|
||||
if (uniformWorldMatrix >= 0)
|
||||
{
|
||||
maxWorldTransforms = 1;
|
||||
}
|
||||
|
||||
uniformWorldMatrixArray = cbuffers[worldMatCBuffer]->findUniform("WorldMatrixArray");
|
||||
if (uniformWorldMatrixArray >= 0)
|
||||
{
|
||||
const UniformD3D11& uniform = cbuffers[worldMatCBuffer]->getUniform(uniformWorldMatrixArray);
|
||||
maxWorldTransforms = uniform.size / (4 * 4 * 3); // 4bytes per float * 3 vectors
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11VertexShader* vertexShader = NULL;
|
||||
HRESULT hr = device11->CreateVertexShader( bytecode.data(), bytecode.size(), NULL, &vertexShader);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
static ID3D11PixelShader* createPixelShader(Device* device, const std::vector<char>& bytecode,
|
||||
std::vector<shared_ptr<CBufferD3D11>>& cbuffers, int& uniformsCBuffer, unsigned int& samplerMask)
|
||||
{
|
||||
DeviceContextD3D11* context = static_cast<DeviceD3D11*>(device)->getImmediateContextD3D11();
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
extractCbuffers(device, bytecode, cbuffers, context->getGlobalDataSize(), &samplerMask);
|
||||
uniformsCBuffer = findCBuffer(cbuffers, "$Globals");
|
||||
|
||||
ID3D11PixelShader* pixelShader = NULL;
|
||||
HRESULT hr = device11->CreatePixelShader(bytecode.data(), bytecode.size(), NULL, &pixelShader);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
return pixelShader;
|
||||
}
|
||||
|
||||
const UniformD3D11& CBufferD3D11::getUniform(int id) const
|
||||
{
|
||||
RBXASSERT(id >= 0 && id < (int)uniforms.size());
|
||||
return uniforms[id];
|
||||
}
|
||||
|
||||
CBufferD3D11::CBufferD3D11(Device* device, int registerId, const std::string& name, unsigned sizeIn, const std::vector<UniformD3D11>& uniformsIn):
|
||||
Resource(device),
|
||||
registerId(registerId),
|
||||
name(name),
|
||||
size(sizeIn),
|
||||
data(NULL),
|
||||
dirty(true),
|
||||
uniforms(uniformsIn),
|
||||
object(NULL)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
data = new char[size];
|
||||
memset(data, 0, size);
|
||||
|
||||
D3D11_BUFFER_DESC cbDesc;
|
||||
cbDesc.Usage = D3D11_USAGE_DEFAULT;
|
||||
cbDesc.ByteWidth = size;
|
||||
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
cbDesc.CPUAccessFlags = 0;
|
||||
cbDesc.MiscFlags = 0;
|
||||
cbDesc.StructureByteStride = 0;
|
||||
|
||||
HRESULT hr = device11->CreateBuffer(&cbDesc, NULL, &object);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
void CBufferD3D11::updateUniform(int uniformId, const float* uniformData, unsigned vectorCount)
|
||||
{
|
||||
size_t uniformSize = vectorCount * sizeof(float) * 4; // our vectors are always float4
|
||||
RBXASSERT(uniformId >= 0 && uniformId < (int)uniforms.size());
|
||||
RBXASSERT(uniforms[uniformId].size >= uniformSize);
|
||||
|
||||
if (dirty || memcmp(&data[uniforms[uniformId].offset], uniformData, uniformSize) != 0)
|
||||
{
|
||||
dirty = true;
|
||||
memcpy(&data[uniforms[uniformId].offset], uniformData, uniformSize);
|
||||
}
|
||||
}
|
||||
|
||||
void CBufferD3D11::updateBuffer()
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
context11->UpdateSubresource(object, 0, NULL, data, 0, 0);
|
||||
|
||||
dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
int CBufferD3D11::findUniform(const std::string& uniformName)
|
||||
{
|
||||
for(unsigned i = 0; i < uniforms.size(); ++i)
|
||||
{
|
||||
if (uniforms[i].name == uniformName)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
CBufferD3D11::~CBufferD3D11()
|
||||
{
|
||||
ReleaseCheck(object);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
BaseShaderD3D11::BaseShaderD3D11(const std::vector<char>& bytecode)
|
||||
: bytecode(bytecode)
|
||||
, uniformsBufferId(-1)
|
||||
{
|
||||
}
|
||||
|
||||
int BaseShaderD3D11::findUniform(const std::string& name)
|
||||
{
|
||||
if (uniformsBufferId < 0) return -1;
|
||||
|
||||
return cBuffers[uniformsBufferId]->findUniform(name);
|
||||
}
|
||||
|
||||
void BaseShaderD3D11::setConstant(int handle, const float* data, size_t vectorCount)
|
||||
{
|
||||
if (uniformsBufferId < 0)
|
||||
return;
|
||||
|
||||
cBuffers[uniformsBufferId]->updateUniform(handle, data, vectorCount);
|
||||
}
|
||||
|
||||
void BaseShaderD3D11::updateConstantBuffers()
|
||||
{
|
||||
for (size_t i = 0; i < cBuffers.size(); ++i)
|
||||
cBuffers[i]->updateBuffer();
|
||||
}
|
||||
|
||||
VertexShaderD3D11::VertexShaderD3D11(Device* device, const std::vector<char>& bytecode)
|
||||
: VertexShader(device)
|
||||
, BaseShaderD3D11(bytecode)
|
||||
, object(NULL)
|
||||
, worldMatrixCbuffer(-1)
|
||||
, worldMatrixArray(-1)
|
||||
, worldMatrix(-1)
|
||||
, maxWorldTransforms(0)
|
||||
{
|
||||
object = createVertexShader(device, bytecode, cBuffers, uniformsBufferId, maxWorldTransforms, worldMatrixCbuffer, worldMatrix, worldMatrixArray);
|
||||
}
|
||||
|
||||
void VertexShaderD3D11::reloadBytecode(const std::vector<char>& bytecode)
|
||||
{
|
||||
ID3D11VertexShader* newObject = createVertexShader(device, bytecode, cBuffers, uniformsBufferId, maxWorldTransforms, worldMatrixCbuffer, worldMatrix, worldMatrixArray);
|
||||
ReleaseCheck(object);
|
||||
|
||||
object = newObject;
|
||||
this->bytecode = bytecode;
|
||||
}
|
||||
|
||||
ID3D11InputLayout* VertexShaderD3D11::getInputLayout11(VertexLayoutD3D11* vertexLayout)
|
||||
{
|
||||
ID3D11InputLayout* inputLayout11 = inputLayoutMap[vertexLayout];
|
||||
|
||||
if (!inputLayout11)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
HRESULT hr = device11->CreateInputLayout(vertexLayout->getElements11(), vertexLayout->getElementsCount(), bytecode.data(), bytecode.size(), &inputLayout11);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
vertexLayout->registerShader(shared_from_this());
|
||||
inputLayoutMap[vertexLayout] = inputLayout11;
|
||||
}
|
||||
|
||||
return inputLayout11;
|
||||
}
|
||||
|
||||
void VertexShaderD3D11::removeLayout(VertexLayoutD3D11* vertexLayout)
|
||||
{
|
||||
InputLayoutMap::iterator it = inputLayoutMap.find(vertexLayout);
|
||||
|
||||
if (it != inputLayoutMap.end())
|
||||
{
|
||||
ReleaseCheck(it->second);
|
||||
inputLayoutMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void VertexShaderD3D11::setWorldTransforms4x3(const float* data, size_t matrixCount)
|
||||
{
|
||||
if (worldMatrixCbuffer < 0) return;
|
||||
|
||||
if (worldMatrix >= 0)
|
||||
{
|
||||
static const float lastRow[4] = {0,0,0,1};
|
||||
float matrix[16];
|
||||
|
||||
memcpy(matrix, data, 3 * 4 * 4);
|
||||
memcpy(&matrix[12], lastRow, 16);
|
||||
|
||||
cBuffers[worldMatrixCbuffer]->updateUniform(0, matrix, 4);
|
||||
}
|
||||
|
||||
if (worldMatrixArray >= 0)
|
||||
cBuffers[worldMatrixCbuffer]->updateUniform(0, data, matrixCount * 3);
|
||||
}
|
||||
|
||||
FragmentShaderD3D11::FragmentShaderD3D11(Device* device, const std::vector<char>& bytecode)
|
||||
: FragmentShader(device)
|
||||
, BaseShaderD3D11(bytecode)
|
||||
, object(NULL)
|
||||
, samplerMask(0)
|
||||
{
|
||||
object = createPixelShader(device, bytecode, cBuffers, uniformsBufferId, samplerMask);
|
||||
}
|
||||
|
||||
void FragmentShaderD3D11::reloadBytecode(const std::vector<char>& bytecode)
|
||||
{
|
||||
ID3D11PixelShader* newObject = createPixelShader(device, bytecode, cBuffers, uniformsBufferId, samplerMask);
|
||||
ReleaseCheck(object);
|
||||
|
||||
object = newObject;
|
||||
this->bytecode = bytecode;
|
||||
}
|
||||
|
||||
FragmentShaderD3D11::~FragmentShaderD3D11()
|
||||
{
|
||||
ReleaseCheck(object);
|
||||
}
|
||||
|
||||
VertexShaderD3D11::~VertexShaderD3D11()
|
||||
{
|
||||
ReleaseCheck(object);
|
||||
for (InputLayoutMap::iterator it = inputLayoutMap.begin(); it != inputLayoutMap.end(); ++it)
|
||||
ReleaseCheck(it->second);
|
||||
}
|
||||
|
||||
static void verifyShaderSignatures(const VertexShaderD3D11* vs, const FragmentShaderD3D11* fs)
|
||||
{
|
||||
TypeD3DReflect D3DReflect = loadShaderReflector();
|
||||
RBXASSERT(D3DReflect);
|
||||
|
||||
ID3D11ShaderReflection* reflectionVS11 = NULL;
|
||||
ID3D11ShaderReflection* reflectionFS11 = NULL;
|
||||
D3DReflect(vs->getByteCode().data(), vs->getByteCode().size(), IID_ID3D11ShaderReflection, (void**) &reflectionVS11);
|
||||
D3DReflect(fs->getByteCode().data(), fs->getByteCode().size(), IID_ID3D11ShaderReflection, (void**) &reflectionFS11);
|
||||
|
||||
// Get shader info
|
||||
D3D11_SHADER_DESC shaderDescVS;
|
||||
D3D11_SHADER_DESC shaderDescFS;
|
||||
reflectionVS11->GetDesc(&shaderDescVS);
|
||||
reflectionFS11->GetDesc(&shaderDescFS);
|
||||
|
||||
RBXASSERT(shaderDescVS.OutputParameters >= shaderDescFS.InputParameters);
|
||||
|
||||
// we have to find matching signature from FS in VS
|
||||
for (unsigned fsId = 0; fsId < shaderDescFS.InputParameters; ++fsId)
|
||||
{
|
||||
|
||||
D3D11_SIGNATURE_PARAMETER_DESC fsDesc;
|
||||
reflectionFS11->GetInputParameterDesc(fsId, &fsDesc);
|
||||
bool found = false;
|
||||
|
||||
for ( unsigned i=0; i< shaderDescVS.OutputParameters; i++ )
|
||||
{
|
||||
D3D11_SIGNATURE_PARAMETER_DESC vsDesc;
|
||||
reflectionVS11->GetOutputParameterDesc(i, &vsDesc);
|
||||
|
||||
if ((vsDesc.ComponentType == fsDesc.ComponentType) &&
|
||||
(vsDesc.Register == fsDesc.Register) &&
|
||||
(vsDesc.SemanticIndex == fsDesc.SemanticIndex) &&
|
||||
(strcmp(vsDesc.SemanticName, fsDesc.SemanticName) == 0) &&
|
||||
(vsDesc.SystemValueType == fsDesc.SystemValueType))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
RBXASSERT(found);
|
||||
}
|
||||
|
||||
ReleaseCheck(reflectionVS11);
|
||||
ReleaseCheck(reflectionFS11);
|
||||
}
|
||||
|
||||
ShaderProgramD3D11::ShaderProgramD3D11(Device* device, const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader)
|
||||
: ShaderProgram(device, vertexShader, fragmentShader)
|
||||
{
|
||||
#ifdef __RBX_NOT_RELEASE
|
||||
verifyShaderSignatures(static_cast<VertexShaderD3D11*>(vertexShader.get()), static_cast<FragmentShaderD3D11*>(fragmentShader.get()));
|
||||
#endif
|
||||
}
|
||||
|
||||
ShaderProgramD3D11::~ShaderProgramD3D11()
|
||||
{
|
||||
static_cast<DeviceD3D11*>(device)->getImmediateContextD3D11()->invalidateCachedProgram();
|
||||
}
|
||||
|
||||
struct IncludeCallback: ID3DInclude
|
||||
{
|
||||
boost::function<std::string (const std::string&)> fileCallback;
|
||||
std::map<const void*, std::string> paths;
|
||||
|
||||
IncludeCallback(boost::function<std::string (const std::string&)> fileCallback)
|
||||
: fileCallback(fileCallback)
|
||||
{
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes)
|
||||
{
|
||||
std::string path;
|
||||
|
||||
if (pParentData)
|
||||
{
|
||||
RBXASSERT(paths.count(pParentData));
|
||||
|
||||
path = paths[pParentData];
|
||||
|
||||
std::string::size_type slash = path.find_last_of("\\/");
|
||||
path.erase(path.begin() + (slash == std::string::npos ? 0 : slash + 1), path.end());
|
||||
}
|
||||
|
||||
path += pFileName;
|
||||
|
||||
try
|
||||
{
|
||||
std::string source = fileCallback(path);
|
||||
|
||||
char* result = new char[source.length()];
|
||||
memcpy(result, source.c_str(), source.length());
|
||||
|
||||
paths[result] = path;
|
||||
|
||||
*ppData = result;
|
||||
*pBytes = source.length();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Close(LPCVOID pData)
|
||||
{
|
||||
RBXASSERT(paths.count(pData));
|
||||
paths.erase(pData);
|
||||
delete[] static_cast<const char*>(pData);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> static std::vector<T> consumeData(HRESULT hr, ID3DBlob* buffer, ID3DBlob* messages)
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (messages)
|
||||
{
|
||||
std::string log(static_cast<char*>(messages->GetBufferPointer()), messages->GetBufferSize());
|
||||
|
||||
messages->Release();
|
||||
|
||||
FASTLOG(FLog::Graphics, "Shader compilation resulted in warnings:");
|
||||
|
||||
ShaderProgram::dumpToFLog(log.c_str(), FLog::Graphics);
|
||||
}
|
||||
|
||||
RBXASSERT(buffer->GetBufferSize() % sizeof(T) == 0);
|
||||
std::vector<T> result(static_cast<T*>(buffer->GetBufferPointer()), static_cast<T*>(buffer->GetBufferPointer()) + buffer->GetBufferSize() / sizeof(T));
|
||||
|
||||
buffer->Release();
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (messages)
|
||||
{
|
||||
std::string log(static_cast<char*>(messages->GetBufferPointer()), messages->GetBufferSize());
|
||||
|
||||
messages->Release();
|
||||
|
||||
throw std::runtime_error(log.c_str());
|
||||
}
|
||||
else
|
||||
throw RBX::runtime_error("Unknown error %x", hr);
|
||||
}
|
||||
|
||||
std::string ShaderProgramD3D11::createShaderSource(const std::string& path, const std::string& defines, const DeviceD3D11* device11, boost::function<std::string (const std::string&)> fileCallback)
|
||||
{
|
||||
TypeD3DPreprocess D3DPreprocess = loadShaderPreprocessor();
|
||||
RBXASSERT(D3DPreprocess);
|
||||
|
||||
// split define string into strings
|
||||
std::vector<std::string> defineStrings;
|
||||
|
||||
std::istringstream defineStream(defines);
|
||||
std::string defineTemp;
|
||||
|
||||
while (defineStream >> defineTemp)
|
||||
defineStrings.push_back(defineTemp);
|
||||
|
||||
// create d3dx defines
|
||||
std::vector<D3D_SHADER_MACRO > macros;
|
||||
|
||||
for (size_t i = 0; i < defineStrings.size(); ++i)
|
||||
{
|
||||
std::string& def = defineStrings[i];
|
||||
std::string::size_type pos = def.find('=');
|
||||
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
D3D_SHADER_MACRO macro = {def.c_str(), "1"};
|
||||
macros.push_back(macro);
|
||||
}
|
||||
else
|
||||
{
|
||||
// split string into name and value
|
||||
def[pos] = 0;
|
||||
|
||||
D3D_SHADER_MACRO macro = {def.c_str(), def.c_str() + pos + 1};
|
||||
macros.push_back(macro);
|
||||
}
|
||||
}
|
||||
|
||||
D3D_SHADER_MACRO macroDX11 = {"DX11", "1"};
|
||||
macros.push_back(macroDX11);
|
||||
if (device11->getShaderProfile() == DeviceD3D11::shaderProfile_DX11_level_9_3)
|
||||
{
|
||||
D3D_SHADER_MACRO macroWinMobile= {"WIN_MOBILE", "1"};
|
||||
macros.push_back(macroWinMobile);
|
||||
}
|
||||
D3D_SHADER_MACRO macroEnd = {};
|
||||
macros.push_back(macroEnd);
|
||||
|
||||
std::string sourceFolder = "";
|
||||
|
||||
// let preprocessor know about the original filename
|
||||
std::string source = "#include \"" + path + "\"\n";
|
||||
|
||||
IncludeCallback includeCallBack = IncludeCallback(fileCallback);
|
||||
|
||||
ID3DBlob* text;
|
||||
ID3DBlob* messages;
|
||||
HRESULT hr = D3DPreprocess(source.c_str(), source.size(), path.c_str(), ¯os[0], &includeCallBack, &text, &messages);
|
||||
|
||||
std::vector<char> resultBuffer = consumeData<char>(hr, text, messages);
|
||||
std::string result = &resultBuffer[0];
|
||||
|
||||
// preprocessor output includes a #line 1 "<full-path>\memory"; remove it!
|
||||
if (result.size() > 10 && result.compare(0, 9, "#line 1 \"") == 0 && result[10] == ':')
|
||||
{
|
||||
std::string::size_type pos = result.find_first_of('\n');
|
||||
assert(pos != std::string::npos);
|
||||
|
||||
result.erase(result.begin(), result.begin() + pos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void translateShaderProfile(const std::string& originalTarget, DeviceD3D11::ShaderProfile shaderProfile, std::string& targetOut)
|
||||
{
|
||||
switch (shaderProfile)
|
||||
{
|
||||
|
||||
case DeviceD3D11::shaderProfile_DX11:
|
||||
{
|
||||
std::string shaderType = originalTarget.substr(0, 2);
|
||||
targetOut = shaderType + "_5_0";
|
||||
return;
|
||||
}
|
||||
case DeviceD3D11::shaderProfile_DX11_level_9_3:
|
||||
{
|
||||
std::string shaderType = originalTarget.substr(0, 2);
|
||||
targetOut = shaderType + "_4_0_level_9_3";
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool needsBackwardCompatibility(const std::string& target)
|
||||
{
|
||||
char reqShaderProfile = target[3];
|
||||
|
||||
// our shaders are written in DX9 target and lower. Backwards compatibility is needed for newer targets and doesn't
|
||||
// hurt when shader is written in DX10 or DX11 target, then it doesn't do anything
|
||||
return reqShaderProfile >= '4';
|
||||
}
|
||||
|
||||
std::vector<char> ShaderProgramD3D11::createShaderBytecode(const std::string& source, const std::string& target, const DeviceD3D11* device11, const std::string& entrypoint)
|
||||
{
|
||||
TypeD3DCompile D3DCompile = loadShaderCompiler();
|
||||
RBXASSERT(D3DCompile);
|
||||
|
||||
unsigned int flags = D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
|
||||
|
||||
std::string realTarget;
|
||||
translateShaderProfile(target, device11->getShaderProfile(), realTarget);
|
||||
|
||||
if (needsBackwardCompatibility(realTarget))
|
||||
flags |= D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;
|
||||
|
||||
ID3DBlob* bytecode = NULL;
|
||||
ID3DBlob* messages = NULL;
|
||||
HRESULT hr = D3DCompile(source.c_str(), source.length(), entrypoint.c_str(), NULL, NULL, entrypoint.c_str(), realTarget.c_str(), flags, 0, &bytecode, &messages);
|
||||
|
||||
return consumeData<char>(hr, bytecode, messages);
|
||||
}
|
||||
|
||||
#if !defined(RBX_PLATFORM_DURANGO)
|
||||
HMODULE ShaderProgramD3D11::loadShaderCompilerDLL()
|
||||
{
|
||||
static HMODULE compiler;
|
||||
|
||||
if (!compiler)
|
||||
compiler = LoadLibraryA("D3DCompiler_47.dll");
|
||||
|
||||
return compiler;
|
||||
}
|
||||
#endif
|
||||
|
||||
ID3D11InputLayout* ShaderProgramD3D11::getInputLayout11(VertexLayoutD3D11* vertexLayout)
|
||||
{
|
||||
return static_cast<VertexShaderD3D11*>(vertexShader.get())->getInputLayout11(vertexLayout);
|
||||
}
|
||||
|
||||
unsigned int ShaderProgramD3D11::getMaxWorldTransforms() const
|
||||
{
|
||||
return static_cast<VertexShaderD3D11*>(vertexShader.get())->getMaxWorldTransforms();
|
||||
}
|
||||
|
||||
void ShaderProgramD3D11::setWorldTransforms4x3(const float* data, size_t matrixCount)
|
||||
{
|
||||
static_cast<VertexShaderD3D11*>(vertexShader.get())->setWorldTransforms4x3(data, matrixCount);
|
||||
}
|
||||
|
||||
int ShaderProgramD3D11::getConstantHandle(const char* name) const
|
||||
{
|
||||
int vs = static_cast<VertexShaderD3D11*>(vertexShader.get())->findUniform(name);
|
||||
int fs = static_cast<FragmentShaderD3D11*>(fragmentShader.get())->findUniform(name);
|
||||
|
||||
RBXASSERT(vs >= -1 && fs >= -1);
|
||||
|
||||
if (vs < 0 && fs < 0)
|
||||
return -1;
|
||||
else
|
||||
return (vs + 1) | ((fs + 1) << 16);
|
||||
}
|
||||
|
||||
void ShaderProgramD3D11::setConstant(int handle, const float* data, size_t vectorCount)
|
||||
{
|
||||
if (handle < 0)
|
||||
return;
|
||||
|
||||
int vs = (handle & 0xffff) - 1;
|
||||
int fs = (handle >> 16) - 1;
|
||||
|
||||
if (vs >= 0)
|
||||
{
|
||||
static_cast<VertexShaderD3D11*>(vertexShader.get())->setConstant(vs, data, vectorCount);
|
||||
}
|
||||
|
||||
if (fs >= 0)
|
||||
{
|
||||
static_cast<FragmentShaderD3D11*>(fragmentShader.get())->setConstant(fs, data, vectorCount);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderProgramD3D11::uploadConstantBuffers()
|
||||
{
|
||||
static_cast<VertexShaderD3D11*>(vertexShader.get())->updateConstantBuffers();
|
||||
static_cast<FragmentShaderD3D11*>(fragmentShader.get())->updateConstantBuffers();
|
||||
}
|
||||
|
||||
unsigned int ShaderProgramD3D11::getSamplerMask() const
|
||||
{
|
||||
return static_cast<FragmentShaderD3D11*>(fragmentShader.get())->getSamplerMask();
|
||||
}
|
||||
|
||||
void ShaderProgramD3D11::bind()
|
||||
{
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
VertexShaderD3D11* vs = static_cast<VertexShaderD3D11*>(vertexShader.get());
|
||||
FragmentShaderD3D11* fs = static_cast<FragmentShaderD3D11*>(fragmentShader.get());
|
||||
|
||||
for (auto& cb: vs->getCBuffers())
|
||||
{
|
||||
ID3D11Buffer* buffer = cb->getObject();
|
||||
context11->VSSetConstantBuffers(cb->getRegisterId(), 1, &buffer);
|
||||
}
|
||||
|
||||
for (auto& cb: fs->getCBuffers())
|
||||
{
|
||||
ID3D11Buffer* buffer = cb->getObject();
|
||||
context11->PSSetConstantBuffers(cb->getRegisterId(), 1, &buffer);
|
||||
}
|
||||
|
||||
context11->VSSetShader(vs->getObject(), NULL, 0);
|
||||
context11->PSSetShader(fs->getObject(), NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
|
||||
#include "GfxCore/Shader.h"
|
||||
|
||||
#include <vector>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
|
||||
|
||||
struct ID3D11VertexShader;
|
||||
struct ID3D11PixelShader;
|
||||
struct ID3D11Buffer;
|
||||
struct ID3D11Device;
|
||||
struct ID3D11InputLayout;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
class VertexLayoutD3D11;
|
||||
class DeviceD3D11;
|
||||
|
||||
struct UniformD3D11
|
||||
{
|
||||
std::string name;
|
||||
|
||||
unsigned offset;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
class CBufferD3D11 : public Resource
|
||||
{
|
||||
public:
|
||||
CBufferD3D11(Device* device, int registerId, const std::string& name, unsigned sizeIn, const std::vector<UniformD3D11>& uniformsIn);
|
||||
~CBufferD3D11();
|
||||
|
||||
const std::vector<UniformD3D11>& getUniforms () const { return uniforms; }
|
||||
const std::string& getName() const { return name; }
|
||||
int getRegisterId() { return registerId; }
|
||||
|
||||
ID3D11Buffer* getObject() { return object; }
|
||||
const UniformD3D11& getUniform(int id) const;
|
||||
|
||||
void updateUniform(int uniformId, const float* uniformData, unsigned vectorCount);
|
||||
void updateBuffer();
|
||||
|
||||
int findUniform(const std::string& uniformName);
|
||||
|
||||
private:
|
||||
int registerId;
|
||||
std::vector<UniformD3D11> uniforms;
|
||||
std::string name;
|
||||
ID3D11Buffer* object;
|
||||
bool dirty;
|
||||
|
||||
size_t size;
|
||||
char* data;
|
||||
};
|
||||
|
||||
class BaseShaderD3D11
|
||||
{
|
||||
public:
|
||||
BaseShaderD3D11(const std::vector<char>& bytecode);
|
||||
|
||||
const std::vector<char>& getByteCode() const { return bytecode; }
|
||||
|
||||
int findUniform(const std::string& name);
|
||||
void setConstant(int handle, const float* data, size_t vectorCount);
|
||||
|
||||
void updateConstantBuffers();
|
||||
|
||||
typedef std::vector<shared_ptr<CBufferD3D11>> CBufferList;
|
||||
const CBufferList& getCBuffers() const { return cBuffers; }
|
||||
|
||||
protected:
|
||||
typedef CBufferList CBufferList;
|
||||
|
||||
std::vector<shared_ptr<CBufferD3D11>> cBuffers;
|
||||
int uniformsBufferId;
|
||||
|
||||
std::vector<char> bytecode;
|
||||
};
|
||||
|
||||
class VertexShaderD3D11: public VertexShader, public BaseShaderD3D11, public boost::enable_shared_from_this<VertexShaderD3D11>
|
||||
{
|
||||
public:
|
||||
VertexShaderD3D11(Device* device, const std::vector<char>& bytecode);
|
||||
~VertexShaderD3D11();
|
||||
|
||||
virtual void reloadBytecode(const std::vector<char>& bytecode);
|
||||
ID3D11VertexShader* getObject() const { return object; }
|
||||
|
||||
ID3D11InputLayout* getInputLayout11(VertexLayoutD3D11* vertexLayout);
|
||||
void removeLayout(VertexLayoutD3D11* vertexLayout);
|
||||
|
||||
void setWorldTransforms4x3(const float* data, size_t matrixCount);
|
||||
unsigned int getMaxWorldTransforms() const { return maxWorldTransforms; }
|
||||
|
||||
private:
|
||||
ID3D11VertexShader* object;
|
||||
|
||||
int worldMatrixArray;
|
||||
int worldMatrix;
|
||||
int worldMatrixCbuffer;
|
||||
unsigned int maxWorldTransforms;
|
||||
|
||||
typedef boost::unordered_map<VertexLayoutD3D11*, ID3D11InputLayout*> InputLayoutMap;
|
||||
InputLayoutMap inputLayoutMap;
|
||||
|
||||
shared_ptr<VertexShaderD3D11> sharedThis;
|
||||
};
|
||||
|
||||
class FragmentShaderD3D11: public FragmentShader, public BaseShaderD3D11
|
||||
{
|
||||
public:
|
||||
FragmentShaderD3D11(Device* device, const std::vector<char>& bytecode);
|
||||
~FragmentShaderD3D11();
|
||||
|
||||
virtual void reloadBytecode(const std::vector<char>& bytecode);
|
||||
|
||||
ID3D11PixelShader* getObject() const { return object; }
|
||||
const std::vector<shared_ptr<CBufferD3D11>>& getCBuffers() const { return cBuffers; }
|
||||
unsigned int getSamplerMask() { return samplerMask; }
|
||||
|
||||
private:
|
||||
ID3D11PixelShader* object;
|
||||
unsigned int samplerMask;
|
||||
};
|
||||
|
||||
class ShaderProgramD3D11: public ShaderProgram
|
||||
{
|
||||
public:
|
||||
ShaderProgramD3D11(Device* device, const shared_ptr<VertexShader>& vertexShader, const shared_ptr<FragmentShader>& fragmentShader);
|
||||
~ShaderProgramD3D11();
|
||||
|
||||
virtual int getConstantHandle(const char* name) const;
|
||||
|
||||
virtual unsigned int getMaxWorldTransforms() const;
|
||||
virtual unsigned int getSamplerMask() const;
|
||||
|
||||
ID3D11InputLayout* getInputLayout11(VertexLayoutD3D11* vertexLayout);
|
||||
|
||||
void bind();
|
||||
void setWorldTransforms4x3(const float* data, size_t matrixCount);
|
||||
void setConstant(int handle, const float* data, size_t vectorCount);
|
||||
void uploadConstantBuffers();
|
||||
|
||||
static std::string createShaderSource(const std::string& path, const std::string& defines, const DeviceD3D11* device11, boost::function<std::string (const std::string&)> fileCallback);
|
||||
static std::vector<char> createShaderBytecode(const std::string& source, const std::string& target, const DeviceD3D11* device, const std::string& entrypoint);
|
||||
static HMODULE loadShaderCompilerDLL();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
#include "TextureD3D11.h"
|
||||
|
||||
#include "FramebufferD3D11.h"
|
||||
#include "DeviceD3D11.h"
|
||||
|
||||
#include "HeadersD3D11.h"
|
||||
|
||||
LOGGROUP(Graphics)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
static const DXGI_FORMAT gTextureFormatD3D11[Texture::Format_Count] =
|
||||
{
|
||||
DXGI_FORMAT_R8_UNORM,
|
||||
DXGI_FORMAT_R8G8_UNORM,
|
||||
DXGI_FORMAT_B5G5R5A1_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R16G16_UNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
DXGI_FORMAT_BC1_UNORM,
|
||||
DXGI_FORMAT_BC3_UNORM,
|
||||
DXGI_FORMAT_BC3_UNORM,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_D16_UNORM,
|
||||
DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||
};
|
||||
|
||||
struct TextureUsageD3D11
|
||||
{
|
||||
D3D11_USAGE usage;
|
||||
unsigned cpuAccess;
|
||||
unsigned bindFlags;
|
||||
unsigned misc;
|
||||
};
|
||||
|
||||
static const TextureUsageD3D11 gTextureUsageD3D11[Texture::Usage_Count] =
|
||||
{
|
||||
{ D3D11_USAGE_DEFAULT, 0, D3D11_BIND_SHADER_RESOURCE , 0},
|
||||
{ D3D11_USAGE_DEFAULT, 0, D3D11_BIND_SHADER_RESOURCE , 0}, // dynamic doesn't support updateSubResource and map cannot lock just part of resource
|
||||
{ D3D11_USAGE_DEFAULT, 0, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, D3D11_RESOURCE_MISC_GENERATE_MIPS}
|
||||
};
|
||||
|
||||
static ID3D11Resource* createTexture(ID3D11Device * device11, Texture::Type type, Texture::Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, const TextureUsageD3D11& textureUsage)
|
||||
{
|
||||
ID3D11Resource* result = NULL;
|
||||
|
||||
DXGI_FORMAT format11 = gTextureFormatD3D11[format];
|
||||
|
||||
HRESULT hr;
|
||||
switch (type)
|
||||
{
|
||||
case Texture::Type_2D:
|
||||
case Texture::Type_Cube:
|
||||
{
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.MipLevels = mipLevels;
|
||||
desc.Format = format11;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.ArraySize = type == Texture::Type_Cube ? 6 : 1;
|
||||
desc.Usage = textureUsage.usage;
|
||||
desc.BindFlags = textureUsage.bindFlags;
|
||||
desc.CPUAccessFlags = textureUsage.cpuAccess;
|
||||
desc.MiscFlags = textureUsage.misc | (type == Texture::Type_Cube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0);
|
||||
|
||||
hr = device11->CreateTexture2D(&desc, NULL, reinterpret_cast<ID3D11Texture2D**>(&result));
|
||||
break;
|
||||
}
|
||||
|
||||
case Texture::Type_3D:
|
||||
{
|
||||
D3D11_TEXTURE3D_DESC desc;
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
desc.Depth = depth;
|
||||
desc.MipLevels = mipLevels;
|
||||
desc.Format = format11;
|
||||
desc.Usage = textureUsage.usage;
|
||||
desc.BindFlags = textureUsage.bindFlags;
|
||||
desc.CPUAccessFlags = textureUsage.cpuAccess;
|
||||
desc.MiscFlags = textureUsage.misc;
|
||||
|
||||
hr = device11->CreateTexture3D(&desc, NULL, reinterpret_cast<ID3D11Texture3D**>(&result));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
RBXASSERT(false);
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Error creating texture: %x", hr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ID3D11ShaderResourceView* createSRV(ID3D11Device * device11, ID3D11Resource* resource, Texture::Type type, Texture::Format format, unsigned int mipLevels)
|
||||
{
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
switch (type)
|
||||
{
|
||||
case Texture::Type_2D:
|
||||
{
|
||||
srvDesc.Format = gTextureFormatD3D11[format];
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = mipLevels;
|
||||
srvDesc.Texture2D.MostDetailedMip = 0;
|
||||
break;
|
||||
}
|
||||
case Texture::Type_Cube:
|
||||
{
|
||||
srvDesc.Format = gTextureFormatD3D11[format];
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
||||
srvDesc.TextureCube.MipLevels = mipLevels;
|
||||
srvDesc.TextureCube.MostDetailedMip = 0;
|
||||
break;
|
||||
}
|
||||
case Texture::Type_3D:
|
||||
{
|
||||
srvDesc.Format = gTextureFormatD3D11[format];
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
||||
srvDesc.Texture3D.MipLevels = mipLevels;
|
||||
srvDesc.Texture3D.MostDetailedMip = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* SRV;
|
||||
HRESULT hr = device11->CreateShaderResourceView(resource, &srvDesc, &SRV);
|
||||
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Error creating shader resource view: %x", hr);
|
||||
|
||||
return SRV;
|
||||
}
|
||||
|
||||
TextureD3D11::TextureD3D11(Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Usage usage)
|
||||
: Texture(device, type, format, width, height, depth, mipLevels, usage)
|
||||
, object(NULL)
|
||||
, objectSRV(NULL)
|
||||
{
|
||||
ID3D11Device* device11 = static_cast<DeviceD3D11*>(device)->getDevice11();
|
||||
|
||||
object = createTexture(device11, type, format, width, height, depth, mipLevels, gTextureUsageD3D11[usage]);
|
||||
objectSRV = createSRV(device11, object, type, format, mipLevels);
|
||||
}
|
||||
|
||||
void TextureD3D11::upload(unsigned int index, unsigned int mip, const TextureRegion& region, const void* data, unsigned int size)
|
||||
{
|
||||
unsigned int mipWidth = getMipSide(width, mip);
|
||||
unsigned int mipHeight = getMipSide(height, mip);
|
||||
unsigned int mipDepth = getMipSide(depth, mip);
|
||||
|
||||
RBXASSERT(mip < mipLevels);
|
||||
RBXASSERT(region.x + region.width <= mipWidth);
|
||||
RBXASSERT(region.y + region.height <= mipHeight);
|
||||
RBXASSERT(region.z + region.depth <= mipDepth);
|
||||
|
||||
RBXASSERT(size == getImageSize(format, region.width, region.height) * region.depth);
|
||||
|
||||
bool partialUpload = (region.width != mipWidth || region.height != mipHeight || region.depth != mipDepth);
|
||||
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
unsigned int dataRowPitch = Texture::getImageSize(format, region.width, 1);
|
||||
unsigned int dataSlicePitch = (type == Type_3D) ? Texture::getImageSize(format, region.width, region.height) : 0;
|
||||
|
||||
D3D11_BOX box = {};
|
||||
if (partialUpload)
|
||||
{
|
||||
box.left = region.x;
|
||||
box.right = region.x + region.width;
|
||||
box.top = region.y;
|
||||
box.bottom = region.y + region.height;
|
||||
box.front = region.z;
|
||||
box.back = region.z + region.depth;
|
||||
}
|
||||
|
||||
UINT res = D3D11CalcSubresource(mip, index, mipLevels);
|
||||
context11->UpdateSubresource(object, res, partialUpload ? &box : NULL, data, dataRowPitch, dataSlicePitch);
|
||||
}
|
||||
|
||||
static void copyHelper(void* targetData, unsigned int targetRowPitch, unsigned int targetSlicePitch,
|
||||
const void* sourceData, unsigned int sourceRowPitch, unsigned int sourceSlicePitch,
|
||||
unsigned int width, unsigned int height, unsigned int depth, Texture::Format format)
|
||||
{
|
||||
unsigned int heightBlocks = Texture::isFormatCompressed(format) ? (height + 3) / 4 : height;
|
||||
unsigned int lineSize = Texture::getImageSize(format, width, 1);
|
||||
|
||||
RBXASSERT(lineSize <= sourceRowPitch && lineSize <= targetRowPitch);
|
||||
|
||||
if (targetRowPitch == sourceRowPitch && targetSlicePitch == sourceSlicePitch)
|
||||
{
|
||||
// Fast path: memory layout is the same
|
||||
unsigned int size = (sourceSlicePitch == 0) ? depth * heightBlocks * sourceRowPitch : depth * sourceSlicePitch;
|
||||
|
||||
memcpy(targetData, sourceData, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slow path: need to copy line by line
|
||||
for (unsigned int z = 0; z < depth; ++z)
|
||||
for (unsigned int yb = 0; yb < heightBlocks; ++yb)
|
||||
{
|
||||
void* target = static_cast<char*>(targetData) + z * targetSlicePitch + yb * targetRowPitch;
|
||||
const void* source = static_cast<const char*>(sourceData) + z * sourceSlicePitch + yb * sourceRowPitch;
|
||||
|
||||
memcpy(target, source, lineSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureD3D11::download(unsigned int index, unsigned int mip, void* data, unsigned int size)
|
||||
{
|
||||
unsigned int mipWidth = getMipSide(width, mip);
|
||||
unsigned int mipHeight = getMipSide(height, mip);
|
||||
unsigned int mipDepth = getMipSide(depth, mip);
|
||||
|
||||
RBXASSERT(mip < mipLevels);
|
||||
RBXASSERT(size == getImageSize(format, mipWidth, mipHeight) * mipDepth);
|
||||
if (type == Type::Type_3D)
|
||||
return false;
|
||||
|
||||
DeviceD3D11* device11 = static_cast<DeviceD3D11*>(device);
|
||||
ID3D11DeviceContext* context11 = device11->getImmediateContext11();
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = mipWidth;
|
||||
desc.Height = mipHeight;
|
||||
desc.MipLevels = 1;
|
||||
desc.Format = gTextureFormatD3D11[format];
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.ArraySize = 1;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
ID3D11Texture2D* tempTex = NULL;
|
||||
HRESULT hr = device11->getDevice11()->CreateTexture2D(&desc, NULL, reinterpret_cast<ID3D11Texture2D**>(&tempTex));
|
||||
if (FAILED(hr))
|
||||
throw RBX::runtime_error("Download texture cant create temp texture %x", hr);
|
||||
|
||||
UINT res = D3D11CalcSubresource(mip, index, mipLevels);
|
||||
context11->CopySubresourceRegion(tempTex, 0, 0, 0, 0, object, res, NULL);
|
||||
|
||||
// copy texture to provided memory
|
||||
D3D11_MAPPED_SUBRESOURCE mappedResource;
|
||||
hr = context11->Map(tempTex, 0, D3D11_MAP_READ, 0, &mappedResource);
|
||||
RBXASSERT(SUCCEEDED(hr));
|
||||
|
||||
unsigned int dataRowPitch = Texture::getImageSize(format, mipWidth, 1);
|
||||
unsigned int dataSlicePitch = (type == Type_3D) ? Texture::getImageSize(format, mipWidth, mipHeight) : 0;
|
||||
|
||||
copyHelper(data, dataRowPitch, dataSlicePitch, mappedResource.pData, mappedResource.RowPitch, 0, mipWidth, mipHeight, mipDepth, format);
|
||||
|
||||
// release all the things
|
||||
context11->Unmap(tempTex, 0);
|
||||
ReleaseCheck(tempTex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureD3D11::supportsLocking() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Texture::LockResult TextureD3D11::lock(unsigned int index, unsigned int mip, const TextureRegion& region)
|
||||
{
|
||||
return LockResult();
|
||||
}
|
||||
|
||||
void TextureD3D11::unlock(unsigned int index, unsigned int mip)
|
||||
{
|
||||
}
|
||||
|
||||
shared_ptr<Renderbuffer> TextureD3D11::getRenderbuffer(unsigned int index, unsigned int mip)
|
||||
{
|
||||
RBXASSERT(mip < mipLevels);
|
||||
|
||||
weak_ptr<Renderbuffer>& slot = renderbuffers[std::make_pair(index, mip)];
|
||||
shared_ptr<Renderbuffer> result = slot.lock();
|
||||
|
||||
if (!result)
|
||||
{
|
||||
if (getType() != Type_2D && getType() != Type_Cube)
|
||||
{
|
||||
RBXASSERT(!"Renderbuffer for this kind of texture is not yet implemented.");
|
||||
return shared_ptr<Renderbuffer>();
|
||||
}
|
||||
|
||||
result.reset(new RenderbufferD3D11(device, shared_from_this(), index, mip));
|
||||
|
||||
slot = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned TextureD3D11::getInternalFormat(Texture::Format format)
|
||||
{
|
||||
return gTextureFormatD3D11[format];
|
||||
}
|
||||
|
||||
void TextureD3D11::commitChanges()
|
||||
{
|
||||
}
|
||||
|
||||
void TextureD3D11::generateMipmaps()
|
||||
{
|
||||
RBXASSERT(usage == Texture::Usage_Renderbuffer);
|
||||
|
||||
ID3D11DeviceContext* context11 = static_cast<DeviceD3D11*>(device)->getImmediateContext11();
|
||||
|
||||
context11->GenerateMips(objectSRV);
|
||||
}
|
||||
|
||||
TextureD3D11::~TextureD3D11()
|
||||
{
|
||||
static_cast<DeviceD3D11*>(device)->getImmediateContextD3D11()->invalidateCachedTexture(this);
|
||||
|
||||
ReleaseCheck(objectSRV);
|
||||
ReleaseCheck(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "GfxCore/Texture.h"
|
||||
#include "GfxCore/States.h"
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <map>
|
||||
|
||||
struct ID3D11Resource;
|
||||
struct ID3D11ShaderResourceView;
|
||||
enum DXGI_FORMAT;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Graphics
|
||||
{
|
||||
|
||||
class Renderbuffer;
|
||||
|
||||
class TextureD3D11: public Texture, public boost::enable_shared_from_this<TextureD3D11>
|
||||
{
|
||||
public:
|
||||
TextureD3D11(Device* device, Type type, Format format, unsigned int width, unsigned int height, unsigned int depth, unsigned int mipLevels, Usage usage);
|
||||
~TextureD3D11();
|
||||
|
||||
virtual void upload(unsigned int index, unsigned int mip, const TextureRegion& region, const void* data, unsigned int size);
|
||||
virtual bool download(unsigned int index, unsigned int mip, void* data, unsigned int size);
|
||||
|
||||
virtual bool supportsLocking() const;
|
||||
virtual LockResult lock(unsigned int index, unsigned int mip, const TextureRegion& region);
|
||||
virtual void unlock(unsigned int index, unsigned int mip);
|
||||
|
||||
virtual shared_ptr<Renderbuffer> getRenderbuffer(unsigned int index, unsigned int mip);
|
||||
|
||||
virtual void commitChanges();
|
||||
virtual void generateMipmaps();
|
||||
|
||||
ID3D11ShaderResourceView* getSRV() const { return objectSRV; }
|
||||
ID3D11Resource* getObject() const { return object; }
|
||||
|
||||
static unsigned getInternalFormat(Texture::Format format);
|
||||
|
||||
private:
|
||||
ID3D11ShaderResourceView* objectSRV;
|
||||
ID3D11Resource* object;
|
||||
|
||||
typedef std::map<std::pair<unsigned int, unsigned int>, weak_ptr<Renderbuffer> > RenderbufferMap;
|
||||
RenderbufferMap renderbuffers;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user