This commit is contained in:
watrabi
2025-09-18 17:55:52 -04:00
commit 977f1ff4b8
15030 changed files with 17324420 additions and 0 deletions
@@ -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;
}
}
}
+390
View File
@@ -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");
}
}
}
+264
View File
@@ -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(&params, &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;
};
}
}
+272
View File
@@ -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);
}
}
}
+83
View File
@@ -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:
};
}
}
+10
View File
@@ -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
+335
View File
@@ -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(&params);
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
+270
View File
@@ -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
+765
View File
@@ -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(), &macros[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);
}
}
}
+155
View File
@@ -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();
};
}
}
+336
View File
@@ -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);
}
}
}
+51
View File
@@ -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;
};
}
}