summaryrefslogtreecommitdiff
path: root/Runtime/GfxDevice/d3d11/D3D11VBO.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/GfxDevice/d3d11/D3D11VBO.cpp')
-rw-r--r--Runtime/GfxDevice/d3d11/D3D11VBO.cpp1193
1 files changed, 1193 insertions, 0 deletions
diff --git a/Runtime/GfxDevice/d3d11/D3D11VBO.cpp b/Runtime/GfxDevice/d3d11/D3D11VBO.cpp
new file mode 100644
index 0000000..e0beaf1
--- /dev/null
+++ b/Runtime/GfxDevice/d3d11/D3D11VBO.cpp
@@ -0,0 +1,1193 @@
+#include "UnityPrefix.h"
+#include "D3D11VBO.h"
+#include "D3D11Context.h"
+#include "Runtime/GfxDevice/GfxDevice.h"
+#include "Runtime/Graphics/TriStripper.h"
+#include "Runtime/GfxDevice/ChannelAssigns.h"
+#include "Runtime/Utilities/ArrayUtility.h"
+#include "D3D11Utils.h"
+
+
+
+// defined in GfxDeviceD3D11.cpp
+ID3D11InputLayout* GetD3D11VertexDeclaration (const ChannelInfoArray& channels);
+void UpdateChannelBindingsD3D11 (const ChannelAssigns& channels);
+
+ID3D11InputLayout* g_ActiveInputLayoutD3D11;
+D3D11_PRIMITIVE_TOPOLOGY g_ActiveTopologyD3D11 = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
+
+
+
+static const D3D11_PRIMITIVE_TOPOLOGY kTopologyD3D11[kPrimitiveTypeCount] =
+{
+ D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
+ D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
+ D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
+ D3D11_PRIMITIVE_TOPOLOGY_LINELIST,
+ D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP,
+ D3D11_PRIMITIVE_TOPOLOGY_POINTLIST,
+};
+
+static const D3D11_PRIMITIVE_TOPOLOGY kTopologyD3D11Tess[kPrimitiveTypeCount] =
+{
+ D3D11_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST,
+ D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED,
+ D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST,
+ D3D11_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST,
+ D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED,
+ D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST,
+};
+
+
+void SetInputLayoutD3D11 (ID3D11DeviceContext* ctx, ID3D11InputLayout* layout)
+{
+ if (g_ActiveInputLayoutD3D11 != layout)
+ {
+ g_ActiveInputLayoutD3D11 = layout;
+ D3D11_CALL (ctx->IASetInputLayout (layout));
+ }
+}
+
+
+static ID3D11InputLayout* GetD3D11VertexDeclaration (UInt32 shaderChannelsMap)
+{
+ ChannelInfoArray channels;
+ int offset = 0;
+ for (int i = 0; i < kShaderChannelCount; i++)
+ {
+ ChannelInfo& info = channels[i];
+ if (shaderChannelsMap & (1 << i))
+ {
+ info.stream = 0;
+ info.offset = offset;
+ info.format = VBO::GetDefaultChannelFormat( i );
+ info.dimension = VBO::GetDefaultChannelDimension( i );
+ offset += VBO::GetDefaultChannelByteSize( i );
+ }
+ else
+ info.Reset();
+ }
+ return GetD3D11VertexDeclaration (channels);
+}
+
+
+// -----------------------------------------------------------------------------
+
+ID3D11Buffer* D3D11VBO::ms_CustomIB = NULL;
+int D3D11VBO::ms_CustomIBSize = 0;
+UInt32 D3D11VBO::ms_CustomIBUsedBytes = 0;
+
+ID3D11Buffer* D3D11VBO::ms_AllWhiteBuffer = NULL;
+
+
+D3D11VBO::D3D11VBO()
+: m_IB(NULL)
+, m_StagingIB(NULL)
+, m_IBReadable(NULL)
+, m_IBSize(0)
+, m_useForSO(false)
+{
+ memset(m_VBStreams, 0, sizeof(m_VBStreams));
+ memset(m_StagingVB, 0, sizeof(m_StagingVB));
+}
+
+D3D11VBO::~D3D11VBO ()
+{
+ for (int s = 0; s < kMaxVertexStreams; ++s)
+ {
+ //std::string tmp = GetDebugNameD3D11(m_StagingVB[s]);
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_VBStreams[s]);
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_StagingVB[s]);
+ SAFE_RELEASE(m_VBStreams[s]);
+ SAFE_RELEASE(m_StagingVB[s]);
+ }
+ if (m_IB)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_IB);
+ SAFE_RELEASE(m_IB);
+ }
+ if (m_StagingIB)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_StagingIB);
+ SAFE_RELEASE(m_StagingIB);
+ }
+ delete[] m_IBReadable;
+}
+
+
+static ID3D11Buffer* CreateStagingBuffer (int size)
+{
+ ID3D11Device* dev = GetD3D11Device();
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = size;
+ desc.Usage = D3D11_USAGE_STAGING;
+ desc.BindFlags = 0;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+
+ ID3D11Buffer* buffer = NULL;
+ HRESULT hr = dev->CreateBuffer (&desc, NULL, &buffer);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(buffer,size,NULL);
+ AssertIf (FAILED(hr));
+ return buffer;
+}
+
+void D3D11VBO::CleanupSharedBuffers()
+{
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(ms_CustomIB);
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(ms_AllWhiteBuffer);
+ SAFE_RELEASE (ms_CustomIB);
+ SAFE_RELEASE (ms_AllWhiteBuffer);
+ ms_CustomIBSize = 0;
+ ms_CustomIBUsedBytes = 0;
+}
+
+
+void D3D11VBO::UpdateVertexStream (const VertexBufferData& sourceData, unsigned stream)
+{
+ DebugAssert (!m_IsStreamMapped[stream]);
+ const StreamInfo& srcStream = sourceData.streams[stream];
+ const int oldSize = CalculateVertexStreamSize(m_Streams[stream], m_VertexCount);
+
+#if UNITY_METRO
+ #pragma message("Fix ugly hack CreateStagingBuffer")
+ // So honestly I don't how what's happening here, but when running on ARM (Surface) with Feature Level 9.1 and if we create a vertex buffer with size 144
+ // Sometimes we crash in D3D11VBO dtor in this line SAFE_RELEASE(m_StagingVB[s]);
+ // Sometimes we get an access violation but sometimes it's Data misalignment exception like below
+ // First-chance exception at 0x75499B2A (setupapi.dll) in Drift Mania Championship 2.exe: 0x80000002: Datatype misalignment
+ // Repro case 495782
+ // Not reproducible on Win32 running Feature Level 9.1
+
+ // In any case it seems increasing min size up to 256, solves this issue for now
+ int newSize = CalculateVertexStreamSize(srcStream, sourceData.vertexCount);
+ int addon = 1;
+ while (newSize > 0 && newSize < 256)
+ {
+ newSize = CalculateVertexStreamSize(srcStream, sourceData.vertexCount + addon);
+ addon++;
+ }
+
+#else
+ const int newSize = CalculateVertexStreamSize(srcStream, sourceData.vertexCount);
+#endif
+
+
+ m_Streams[stream] = srcStream;
+ if (newSize == 0)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_VBStreams[stream]);
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_StagingVB[stream]);
+ SAFE_RELEASE (m_VBStreams[stream]);
+ SAFE_RELEASE (m_StagingVB[stream]);
+ return;
+ }
+
+ const bool isDynamic = (m_StreamModes[stream] == kStreamModeDynamic);
+ const bool useStaging = !isDynamic;
+
+ if (m_VBStreams[stream] == NULL || newSize != oldSize)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_VBStreams[stream]);
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_StagingVB[stream]);
+ SAFE_RELEASE (m_VBStreams[stream]);
+ SAFE_RELEASE (m_StagingVB[stream]); // release staging VB as well here
+
+ ID3D11Device* dev = GetD3D11Device();
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = newSize;
+ desc.Usage = isDynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ if ( m_useForSO )
+ desc.BindFlags |= D3D11_BIND_STREAM_OUTPUT;
+ desc.CPUAccessFlags = isDynamic ? D3D11_CPU_ACCESS_WRITE : 0;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+ HRESULT hr = dev->CreateBuffer (&desc, NULL, &m_VBStreams[stream]);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(m_VBStreams[stream],newSize,this);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to create vertex buffer of size %d [0x%X]\n", newSize, hr);
+ return;
+ }
+ SetDebugNameD3D11 (m_VBStreams[stream], Format("VertexBuffer-%d", newSize));
+
+ if (useStaging)
+ {
+ m_StagingVB[stream] = CreateStagingBuffer (newSize);
+ SetDebugNameD3D11 (m_StagingVB[stream], Format("StagingVertexBuffer-%d", newSize));
+ }
+ }
+
+ // Don't update contents if there is no source data.
+ // This is used to update the vertex declaration only, leaving buffer intact.
+ // Also to create an empty buffer that is written to later.
+ if (!sourceData.buffer)
+ return;
+
+ HRESULT hr;
+
+ ID3D11Buffer* mapVB = NULL;
+ D3D11_MAP mapType;
+
+ if (useStaging)
+ {
+ mapVB = m_StagingVB[stream];
+ mapType = D3D11_MAP_WRITE;
+ }
+ else
+ {
+ mapVB = m_VBStreams[stream];
+ mapType = D3D11_MAP_WRITE_DISCARD;
+ }
+
+ Assert (mapVB);
+
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ hr = ctx->Map (mapVB, 0, mapType, 0, &mapped);
+ Assert (SUCCEEDED(hr));
+ CopyVertexStream (sourceData, reinterpret_cast<UInt8*>(mapped.pData), stream);
+ ctx->Unmap (mapVB, 0);
+
+ if (useStaging)
+ ctx->CopyResource (m_VBStreams[stream], m_StagingVB[stream]);
+}
+
+
+void D3D11VBO::UpdateIndexBufferData (const IndexBufferData& sourceData)
+{
+ if( !sourceData.indices )
+ {
+ m_IBSize = 0;
+ return;
+ }
+
+ Assert (m_IB);
+ HRESULT hr;
+
+ int size = sourceData.count * kVBOIndexSize;
+ if (sourceData.hasTopologies & ((1<<kPrimitiveTriangleStripDeprecated) | (1<<kPrimitiveQuads)))
+ {
+ delete[] m_IBReadable;
+ m_IBReadable = new UInt16[sourceData.count];
+ memcpy (m_IBReadable, sourceData.indices, size);
+ }
+
+ const D3D11_MAP mapType = m_IndicesDynamic ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE;
+ ID3D11Buffer* mapIB;
+ if (m_IndicesDynamic)
+ mapIB = m_IB;
+ else
+ {
+ if (!m_StagingIB)
+ m_StagingIB = CreateStagingBuffer(m_IBSize);
+ mapIB = m_StagingIB;
+ }
+
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ hr = ctx->Map (mapIB, 0, mapType, 0, &mapped);
+ Assert (SUCCEEDED(hr));
+
+ memcpy (mapped.pData, sourceData.indices, size);
+
+ ctx->Unmap (mapIB, 0);
+ if (!m_IndicesDynamic)
+ ctx->CopyResource (m_IB, m_StagingIB);
+}
+
+bool D3D11VBO::MapVertexStream( VertexStreamData& outData, unsigned stream )
+{
+ if (m_VBStreams[stream] == NULL)
+ {
+ printf_console ("d3d11: attempt to map null vertex buffer\n");
+ return false;
+ }
+ DebugAssert(!IsVertexBufferLost());
+ Assert(!m_IsStreamMapped[stream]);
+
+ const int vbSize = CalculateVertexStreamSize(m_Streams[stream], m_VertexCount);
+
+ const bool dynamic = (m_StreamModes[stream]==kStreamModeDynamic);
+
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ ID3D11Buffer* mapVB = dynamic ? m_VBStreams[stream] : m_StagingVB[stream];
+ D3D11_MAP mapType = dynamic ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE;
+ HRESULT hr = GetD3D11Context()->Map (mapVB, 0, mapType, 0, &mapped);
+ if( FAILED(hr) )
+ {
+ printf_console ("d3d11: failed to map vertex buffer %p of size %i [%x]\n", mapVB, vbSize, hr);
+ return false;
+ }
+ m_IsStreamMapped[stream] = true;
+
+ UInt8* buffer = (UInt8*)mapped.pData;
+
+ outData.buffer = buffer;
+ outData.channelMask = m_Streams[stream].channelMask;
+ outData.stride = m_Streams[stream].stride;
+ outData.vertexCount = m_VertexCount;
+
+ GetRealGfxDevice().GetFrameStats().AddUploadVBO(vbSize);
+
+ return true;
+}
+
+void D3D11VBO::UnmapVertexStream (unsigned stream)
+{
+ DebugAssert(m_VBStreams[stream]);
+ Assert(m_IsStreamMapped[stream]);
+ m_IsStreamMapped[stream] = false;
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+
+ const bool dynamic = (m_StreamModes[stream]==kStreamModeDynamic);
+ ID3D11Buffer* mapVB = dynamic ? m_VBStreams[stream] : m_StagingVB[stream];
+ ctx->Unmap (mapVB, 0);
+
+ if (!dynamic)
+ ctx->CopyResource (m_VBStreams[stream], m_StagingVB[stream]);
+}
+
+bool D3D11VBO::IsVertexBufferLost() const
+{
+ for (int s = 0; s < kMaxVertexStreams; ++s)
+ if (m_Streams[s].channelMask && !m_VBStreams[s])
+ return true;
+ return false;
+}
+
+int D3D11VBO::GetRuntimeMemorySize() const
+{
+ int vertexSize = 0;
+ for( int s = 0; s < kMaxVertexStreams; s++ )
+ vertexSize += m_Streams[s].stride;
+ return vertexSize * m_VertexCount + m_IBSize;
+}
+
+
+bool SetTopologyD3D11 (GfxPrimitiveType topology, GfxDevice& device, ID3D11DeviceContext* ctx)
+{
+ bool tessellation = device.IsShaderActive (kShaderHull) || device.IsShaderActive (kShaderDomain);
+ D3D11_PRIMITIVE_TOPOLOGY topod3d = tessellation ? kTopologyD3D11Tess[topology] : kTopologyD3D11[topology];
+ if (topod3d == D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED)
+ return false;
+
+ if (topod3d != g_ActiveTopologyD3D11)
+ {
+ g_ActiveTopologyD3D11 = topod3d;
+ D3D11_CALL (ctx->IASetPrimitiveTopology (topod3d));
+ }
+ return true;
+}
+
+
+ID3D11Buffer* D3D11VBO::GetAllWhiteBuffer()
+{
+ if (!ms_AllWhiteBuffer)
+ {
+ int maxVerts = 0x10000;
+ int size = maxVerts * sizeof(UInt32);
+ UInt8* data = new UInt8[size];
+ memset (data, 0xFF, size);
+
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = size;
+ desc.Usage = D3D11_USAGE_IMMUTABLE;
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+ D3D11_SUBRESOURCE_DATA sdata;
+ sdata.pSysMem = data;
+ sdata.SysMemPitch = 0;
+ sdata.SysMemSlicePitch = 0;
+ HRESULT hr = GetD3D11Device()->CreateBuffer (&desc, &sdata, &ms_AllWhiteBuffer);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(ms_AllWhiteBuffer,size,NULL);
+ delete[] data;
+ }
+ return ms_AllWhiteBuffer;
+}
+
+
+void D3D11VBO::BindVertexStreams(GfxDevice& device, ID3D11DeviceContext* ctx, const ChannelAssigns& channels)
+{
+ DX11_LOG_ENTER_FUNCTION("D3D11VBO::BindVertexStreams");
+ int freeStream = -1;
+ for (int s = 0; s < kMaxVertexStreams; ++s)
+ {
+ if (m_VBStreams[s])
+ {
+ UINT offset = 0;
+ UINT stride = m_Streams[s].stride;
+ D3D11_CALL (ctx->IASetVertexBuffers(s, 1, &m_VBStreams[s], &stride, &offset));
+ }
+ else
+ freeStream = s;
+ }
+
+ UpdateChannelBindingsD3D11(channels);
+
+ device.BeforeDrawCall( false );
+
+ const ChannelInfoArray* channelInfo = &m_ChannelInfo;
+ if ((channels.GetSourceMap() & VERTEX_FORMAT1(Color)) && !m_ChannelInfo[kShaderChannelColor].IsValid())
+ {
+ if (freeStream != -1)
+ {
+ static ChannelInfoArray colorChannelInfo;
+ memcpy(&colorChannelInfo, m_ChannelInfo, sizeof(colorChannelInfo));
+ ChannelInfo& colorInfo = colorChannelInfo[kShaderChannelColor];
+ colorInfo.stream = freeStream;
+ colorInfo.offset = 0;
+ colorInfo.format = kChannelFormatColor;
+ colorInfo.dimension = 1;
+ channelInfo = &colorChannelInfo;
+ ID3D11Buffer* whiteVB = GetAllWhiteBuffer();
+ UINT stride = 4;
+ UINT offset = 0;
+ D3D11_CALL (ctx->IASetVertexBuffers(freeStream, 1, &whiteVB, &stride, &offset));
+ }
+ else
+ ErrorString("Need a free stream to add default vertex colors!");
+ }
+ ID3D11InputLayout* inputLayout = GetD3D11VertexDeclaration(m_ChannelInfo);
+ SetInputLayoutD3D11 (ctx, inputLayout);
+}
+
+void D3D11VBO::BindToStreamOutput()
+{
+ const UINT offsets[] = { 0 };
+ GetD3D11Context()->SOSetTargets(1, m_VBStreams, offsets);
+}
+
+void D3D11VBO::UnbindFromStreamOutput()
+{
+ ID3D11Buffer* const buffers[] = { 0 };
+ const UINT offsets[] = { 0 };
+ GetD3D11Context()->SOSetTargets(1, buffers, offsets);
+}
+
+
+void D3D11VBO::DrawVBO (const ChannelAssigns& channels, UInt32 firstIndexByte, UInt32 indexCount, GfxPrimitiveType topology, UInt32 firstVertex, UInt32 vertexCount)
+{
+ DX11_LOG_ENTER_FUNCTION("D3D11VBO::DrawVBO");
+ // just return if no indices
+ if( m_IBSize == 0 )
+ return;
+
+ Assert(!m_IsStreamMapped[0]);
+ if (m_VBStreams[0] == 0 || m_IB == 0)
+ {
+ printf_console( "d3d: VB or IB is null\n" );
+ return;
+ }
+
+ GfxDevice& device = GetRealGfxDevice();
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+ BindVertexStreams (device, ctx, channels);
+
+ bool tessellation = device.IsShaderActive (kShaderHull) || device.IsShaderActive (kShaderDomain);
+ if (tessellation && topology == kPrimitiveTriangleStripDeprecated)
+ {
+ if (!m_IBReadable)
+ return;
+
+ const UInt16* ibSrc = (const UInt16*)((const UInt8*)m_IBReadable + firstIndexByte);
+ const int triCount = CountTrianglesInStrip (ibSrc, indexCount);
+
+ UInt32 ibBytesLocked;
+ UInt16* ibPtr = MapDynamicIndexBuffer (triCount*3, ibBytesLocked);
+ if (!ibPtr)
+ return;
+ Destripify (ibSrc, indexCount, ibPtr, triCount*3);
+ UnmapDynamicIndexBuffer ();
+ firstIndexByte = ms_CustomIBUsedBytes;
+ ms_CustomIBUsedBytes += ibBytesLocked;
+ D3D11_CALL (ctx->IASetIndexBuffer (ms_CustomIB, DXGI_FORMAT_R16_UINT, 0));
+ indexCount = ibBytesLocked/kVBOIndexSize;
+ topology = kPrimitiveTriangles;
+ }
+ else if (topology == kPrimitiveQuads && !tessellation)
+ {
+ if (!m_IBReadable)
+ return;
+ UInt32 ibBytesLocked;
+ UInt16* ibPtr = MapDynamicIndexBuffer (indexCount/4*6, ibBytesLocked);
+ if (!ibPtr)
+ return;
+ const UInt16* ibSrc = (const UInt16*)((const UInt8*)m_IBReadable + firstIndexByte);
+ FillIndexBufferForQuads (ibPtr, ibBytesLocked, ibSrc, indexCount/4);
+ UnmapDynamicIndexBuffer ();
+ firstIndexByte = ms_CustomIBUsedBytes;
+ ms_CustomIBUsedBytes += ibBytesLocked;
+ D3D11_CALL (ctx->IASetIndexBuffer (ms_CustomIB, DXGI_FORMAT_R16_UINT, 0));
+ indexCount = ibBytesLocked/kVBOIndexSize;
+ }
+ else
+ {
+ D3D11_CALL (ctx->IASetIndexBuffer (m_IB, DXGI_FORMAT_R16_UINT, 0));
+ }
+
+ // draw
+ if (!SetTopologyD3D11 (topology, device, ctx))
+ return;
+ D3D11_CALL (ctx->DrawIndexed (indexCount, firstIndexByte/2, 0));
+ device.GetFrameStats().AddDrawCall (GetPrimitiveCount(indexCount,topology,false), vertexCount);
+ DX11_MARK_DRAWING(GetPrimitiveCount(indexCount,topology,false), vertexCount);
+
+}
+
+UInt16* D3D11VBO::MapDynamicIndexBuffer (int indexCount, UInt32& outBytesUsed)
+{
+ HRESULT hr;
+ const UInt32 maxIndices = 64000;
+ Assert (indexCount <= maxIndices);
+ indexCount = std::min<UInt32>(indexCount, maxIndices);
+
+ int ibCapacity = indexCount * kVBOIndexSize;
+ int newIBSize = std::max (ibCapacity, 32*1024); // 32k IB at least
+
+ if (newIBSize > ms_CustomIBSize)
+ {
+ if (ms_CustomIB)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(ms_CustomIB);
+ ms_CustomIB->Release();
+ }
+ ms_CustomIBSize = newIBSize;
+ ms_CustomIBUsedBytes = 0;
+
+ ID3D11Device* dev = GetD3D11Device();
+
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = newIBSize;
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+ hr = dev->CreateBuffer (&desc, NULL, &ms_CustomIB);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(ms_CustomIB,newIBSize,NULL);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to create custom index buffer of size %d [%x]\n", newIBSize, hr);
+ return NULL;
+ }
+ SetDebugNameD3D11 (ms_CustomIB, Format("IndexBufferCustomDynamic-%d", newIBSize));
+ }
+
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ if (ms_CustomIBUsedBytes + ibCapacity > ms_CustomIBSize)
+ {
+ hr = ctx->Map (ms_CustomIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to lock shared index buffer with discard [%x]\n", hr);
+ return NULL;
+ }
+ ms_CustomIBUsedBytes = 0;
+ }
+ else
+ {
+ hr = ctx->Map (ms_CustomIB, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped);
+ if (FAILED(hr))
+ {
+ printf_console( "d3d11: failed to lock shared index buffer, offset %i size %i [%x]\n", ms_CustomIBUsedBytes, ibCapacity, hr);
+ return NULL;
+ }
+ }
+ outBytesUsed = ibCapacity;
+
+ return (UInt16*)((UInt8*)mapped.pData + ms_CustomIBUsedBytes);
+}
+
+void D3D11VBO::UnmapDynamicIndexBuffer ()
+{
+ GetD3D11Context()->Unmap (ms_CustomIB, 0);
+}
+
+
+#if GFX_ENABLE_DRAW_CALL_BATCHING
+void D3D11VBO::DrawCustomIndexed( const ChannelAssigns& channels, void* indices, UInt32 indexCount,
+ GfxPrimitiveType topology, UInt32 vertexRangeBegin, UInt32 vertexRangeEnd, UInt32 drawVertexCount )
+{
+ HRESULT hr;
+ Assert (!m_IsStreamMapped[0]);
+
+ if (m_VBStreams[0] == 0)
+ {
+ printf_console( "d3d11: VB is null\n" );
+ return;
+ }
+
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+
+ UInt32 ibBytesUsed;
+ UInt16* ibPtr = MapDynamicIndexBuffer (indexCount, ibBytesUsed);
+ if (!ibPtr)
+ return;
+ memcpy (ibPtr, indices, ibBytesUsed);
+ UnmapDynamicIndexBuffer ();
+
+ // draw
+ GfxDevice& device = GetRealGfxDevice();
+ BindVertexStreams(device, ctx, channels);
+
+ D3D11_CALL (ctx->IASetIndexBuffer (ms_CustomIB, DXGI_FORMAT_R16_UINT, 0));
+
+ // draw
+ if (!SetTopologyD3D11 (topology, device, ctx))
+ return;
+ D3D11_CALL (ctx->DrawIndexed (indexCount, ms_CustomIBUsedBytes / kVBOIndexSize, 0));
+ device.GetFrameStats().AddDrawCall (GetPrimitiveCount(indexCount,topology,false), drawVertexCount);
+
+ ms_CustomIBUsedBytes += ibBytesUsed;
+}
+
+#endif // GFX_ENABLE_DRAW_CALL_BATCHING
+
+
+
+void D3D11VBO::UpdateVertexData( const VertexBufferData& buffer )
+{
+ for (unsigned stream = 0; stream < kMaxVertexStreams; stream++)
+ UpdateVertexStream (buffer, stream);
+
+ memcpy (m_ChannelInfo, buffer.channels, sizeof(m_ChannelInfo));
+ m_VertexCount = buffer.vertexCount;
+}
+
+void D3D11VBO::UpdateIndexData (const IndexBufferData& buffer)
+{
+ int newSize = CalculateIndexBufferSize(buffer);
+
+ // If we have old buffer, but need different size: delete old one
+ if (newSize != m_IBSize)
+ {
+ if (m_IB)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_IB);
+ SAFE_RELEASE(m_IB);
+ }
+ if (m_StagingIB)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_StagingIB);
+ SAFE_RELEASE(m_StagingIB);
+ }
+ }
+
+ // Create buffer if we need to
+ if (!m_IB)
+ {
+ ID3D11Device* dev = GetD3D11Device();
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = newSize;
+ desc.Usage = m_IndicesDynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = m_IndicesDynamic ? D3D11_CPU_ACCESS_WRITE : 0;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+ HRESULT hr = dev->CreateBuffer (&desc, NULL, &m_IB);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(m_IB,newSize,this);
+ if( FAILED(hr) )
+ {
+ printf_console( "d3d11: failed to create index buffer of size %d [0x%X]\n", newSize, hr );
+ return;
+ }
+ SetDebugNameD3D11 (m_IB, Format("IndexBuffer-%d", newSize));
+ }
+
+ m_IBSize = newSize;
+ UpdateIndexBufferData(buffer);
+}
+
+void D3D11VBO::SetIndicesDynamic(bool dynamic)
+{
+ // do nothing if a no-op
+ if (dynamic == m_IndicesDynamic)
+ return;
+
+ VBO::SetIndicesDynamic(dynamic);
+
+ // release current index buffers
+ if (m_IB)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_IB);
+ SAFE_RELEASE(m_IB);
+ }
+ if (m_StagingIB)
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_StagingIB);
+ SAFE_RELEASE(m_StagingIB);
+ }
+}
+
+
+
+// -----------------------------------------------------------------------------
+
+
+DynamicD3D11VBO::DynamicD3D11VBO( UInt32 vbSize, UInt32 ibSize )
+: DynamicVBO()
+, m_VBSize(vbSize)
+, m_VBUsedBytes(0)
+, m_IBSize(ibSize)
+, m_IBUsedBytes(0)
+, m_VB(NULL)
+, m_IB(NULL)
+, m_LastChunkStartVertex(0)
+, m_LastChunkStartIndex(0)
+, m_QuadsIB(NULL)
+{
+}
+
+DynamicD3D11VBO::~DynamicD3D11VBO ()
+{
+ if( m_VB ) {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_VB);
+ ULONG refCount = m_VB->Release();
+ AssertIf( refCount != 0 );
+ }
+ if( m_IB ) {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_IB);
+ ULONG refCount = m_IB->Release();
+ AssertIf( refCount != 0 );
+ }
+ if( m_QuadsIB ) {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_QuadsIB);
+ ULONG refCount = m_QuadsIB->Release();
+ AssertIf( refCount != 0 );
+ }
+}
+
+void DynamicD3D11VBO::InitializeQuadsIB()
+{
+ AssertIf( m_QuadsIB );
+
+ const int kMaxQuads = 65536/4 - 4; // so we fit into 16 bit indices, minus some more just in case
+
+ UInt16* data = new UInt16[kMaxQuads*6];
+ UInt16* ib = data;
+ UInt32 baseIndex = 0;
+ for( int i = 0; i < kMaxQuads; ++i )
+ {
+ ib[0] = baseIndex + 1;
+ ib[1] = baseIndex + 2;
+ ib[2] = baseIndex;
+ ib[3] = baseIndex + 2;
+ ib[4] = baseIndex + 3;
+ ib[5] = baseIndex;
+ baseIndex += 4;
+ ib += 6;
+ }
+
+ ID3D11Device* dev = GetD3D11Device();
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = kMaxQuads * 6 * kVBOIndexSize;
+ desc.Usage = D3D11_USAGE_IMMUTABLE;
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+ D3D11_SUBRESOURCE_DATA srData;
+ srData.pSysMem = data;
+ srData.SysMemPitch = 0;
+ srData.SysMemSlicePitch = 0;
+ HRESULT hr = dev->CreateBuffer (&desc, &srData, &m_QuadsIB);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(m_QuadsIB,desc.ByteWidth,this);
+ delete[] data;
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to create quads index buffer [%x]\n", hr);
+ }
+ SetDebugNameD3D11 (m_QuadsIB, "IndexBufferQuads");
+}
+
+
+void DynamicD3D11VBO::DrawChunk (const ChannelAssigns& channels)
+{
+ DX11_LOG_ENTER_FUNCTION("DynamicD3D11VBO::DrawChunk");
+ // just return if nothing to render
+ if( !m_LastChunkShaderChannelMask )
+ return;
+
+ HRESULT hr;
+
+ AssertIf( !m_LastChunkShaderChannelMask || !m_LastChunkStride );
+ AssertIf( m_LendedChunk );
+
+ GfxDevice& device = GetRealGfxDevice();
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+
+ // setup VBO
+ DebugAssert (m_VB);
+ UINT strides = m_LastChunkStride;
+ UINT offsets = 0;
+ D3D11_CALL (ctx->IASetVertexBuffers(0, 1, &m_VB, &strides, &offsets));
+
+ UpdateChannelBindingsD3D11(channels);
+ device.BeforeDrawCall (false);
+
+ ID3D11InputLayout* inputLayout = GetD3D11VertexDeclaration (m_LastChunkShaderChannelMask);
+ SetInputLayoutD3D11 (ctx, inputLayout);
+
+ // draw
+ GfxDeviceStats& stats = device.GetFrameStats();
+ int primCount = 0;
+ if (m_LastRenderMode == kDrawTriangleStrip)
+ {
+ if (!SetTopologyD3D11(kPrimitiveTriangleStripDeprecated,device,ctx))
+ return;
+ D3D11_CALL (ctx->Draw (m_LastChunkVertices, m_LastChunkStartVertex));
+ primCount = m_LastChunkVertices-2;
+ }
+ else if (m_LastRenderMode == kDrawIndexedTriangleStrip)
+ {
+ DebugAssert (m_IB);
+ if (!SetTopologyD3D11(kPrimitiveTriangleStripDeprecated,device,ctx))
+ return;
+ D3D11_CALL (ctx->IASetIndexBuffer (m_IB, DXGI_FORMAT_R16_UINT, 0));
+ D3D11_CALL (ctx->DrawIndexed (m_LastChunkIndices, m_LastChunkStartIndex, m_LastChunkStartVertex));
+ primCount = m_LastChunkIndices-2;
+ }
+ else if( m_LastRenderMode == kDrawQuads )
+ {
+ if (!SetTopologyD3D11(kPrimitiveTriangles,device,ctx))
+ return;
+ // initialize quads index buffer if needed
+ if (!m_QuadsIB)
+ InitializeQuadsIB();
+ // if quads index buffer has valid data, draw with it
+ if (m_QuadsIB)
+ {
+ D3D11_CALL (ctx->IASetIndexBuffer (m_QuadsIB, DXGI_FORMAT_R16_UINT, 0));
+ D3D11_CALL (ctx->DrawIndexed (m_LastChunkVertices/4*6, 0, m_LastChunkStartVertex));
+ primCount = m_LastChunkVertices/2;
+ }
+ }
+ else if (m_LastRenderMode == kDrawIndexedLines)
+ {
+ DebugAssert( m_IB );
+ if (!SetTopologyD3D11(kPrimitiveLines,device,ctx))
+ return;
+ D3D11_CALL (ctx->IASetIndexBuffer (m_IB, DXGI_FORMAT_R16_UINT, 0));
+ D3D11_CALL (ctx->DrawIndexed (m_LastChunkIndices, m_LastChunkStartIndex, m_LastChunkStartVertex));
+ primCount = m_LastChunkIndices/2;
+ }
+ else if (m_LastRenderMode == kDrawIndexedPoints)
+ {
+ DebugAssert (m_IB);
+ D3D11_CALL (ctx->IASetIndexBuffer (m_IB, DXGI_FORMAT_R16_UINT, 0));
+ if (!SetTopologyD3D11 (kPrimitivePoints, device, ctx))
+ return;
+ D3D11_CALL (ctx->DrawIndexed (m_LastChunkIndices, m_LastChunkStartIndex, m_LastChunkStartVertex));
+ primCount = m_LastChunkIndices;
+ }
+ else
+ {
+ DebugAssert (m_IB);
+ D3D11_CALL (ctx->IASetIndexBuffer (m_IB, DXGI_FORMAT_R16_UINT, 0));
+ if (!SetTopologyD3D11 (kPrimitiveTriangles, device, ctx))
+ return;
+ D3D11_CALL (ctx->DrawIndexed (m_LastChunkIndices, m_LastChunkStartIndex, m_LastChunkStartVertex));
+ primCount = m_LastChunkIndices/3;
+ }
+ stats.AddDrawCall (primCount, m_LastChunkVertices);
+ DX11_MARK_DRAWING(primCount, m_LastChunkVertices);
+}
+
+
+#if UNITY_EDITOR
+void DynamicD3D11VBO::DrawChunkUserPrimitives (GfxPrimitiveType type)
+{
+ // just return if nothing to render
+ if( !m_LastChunkShaderChannelMask )
+ return;
+
+ HRESULT hr;
+
+ AssertIf( !m_LastChunkShaderChannelMask || !m_LastChunkStride );
+ AssertIf( m_LendedChunk );
+
+ ChannelAssigns channels;
+ for( int i = 0; i < kShaderChannelCount; ++i )
+ {
+ if (!(m_LastChunkShaderChannelMask & (1<<i)))
+ continue;
+ VertexComponent destComponent = kSuitableVertexComponentForChannel[i];
+ channels.Bind ((ShaderChannel)i, destComponent);
+ }
+
+ GfxDevice& device = GetRealGfxDevice();
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+
+ // setup VBO
+ DebugAssert (m_VB);
+ UINT strides = m_LastChunkStride;
+ UINT offsets = 0;
+ D3D11_CALL (ctx->IASetVertexBuffers(0, 1, &m_VB, &strides, &offsets));
+
+ UpdateChannelBindingsD3D11(channels);
+ device.BeforeDrawCall (false);
+
+ ID3D11InputLayout* inputLayout = GetD3D11VertexDeclaration (m_LastChunkShaderChannelMask);
+ SetInputLayoutD3D11 (ctx, inputLayout);
+
+ // draw
+ GfxDeviceStats& stats = device.GetFrameStats();
+ int primCount = 0;
+ switch (type)
+ {
+ case kPrimitiveTriangles:
+ if (!SetTopologyD3D11(kPrimitiveTriangles,device,ctx))
+ return;
+ D3D11_CALL (ctx->Draw (m_LastChunkVertices, m_LastChunkStartVertex));
+ primCount = m_LastChunkVertices/3;
+ break;
+ case kPrimitiveQuads:
+ if (!SetTopologyD3D11(kPrimitiveTriangles,device,ctx))
+ return;
+ // initialize quads index buffer if needed
+ if (!m_QuadsIB)
+ InitializeQuadsIB();
+ // if quads index buffer has valid data, draw with it
+ if (m_QuadsIB)
+ {
+ D3D11_CALL (ctx->IASetIndexBuffer (m_QuadsIB, DXGI_FORMAT_R16_UINT, 0));
+ D3D11_CALL (ctx->DrawIndexed (m_LastChunkVertices/4*6, 0, m_LastChunkStartVertex));
+ primCount = m_LastChunkVertices/2;
+ }
+ break;
+ case kPrimitiveLines:
+ if (!SetTopologyD3D11(kPrimitiveLines,device,ctx))
+ return;
+ D3D11_CALL (ctx->Draw (m_LastChunkVertices, m_LastChunkStartVertex));
+ primCount = m_LastChunkVertices/2;
+ break;
+ case kPrimitiveLineStrip:
+ if (!SetTopologyD3D11(kPrimitiveLineStrip,device,ctx))
+ return;
+ D3D11_CALL (ctx->Draw (m_LastChunkVertices, m_LastChunkStartVertex));
+ primCount = m_LastChunkVertices-1;
+ break;
+ default:
+ ErrorString("Primitive type not supported");
+ return;
+ }
+ stats.AddDrawCall (primCount, m_LastChunkVertices);
+}
+#endif // UNITY_EDITOR
+
+
+bool DynamicD3D11VBO::GetChunk( UInt32 shaderChannelMask, UInt32 maxVertices, UInt32 maxIndices, RenderMode renderMode, void** outVB, void** outIB )
+{
+ Assert( !m_LendedChunk );
+ Assert( maxVertices < 65536 && maxIndices < 65536*3 );
+ DebugAssertMsg(outVB != NULL && maxVertices > 0, "DynamicD3D11VBO::GetChunk - outVB: 0x%08x maxVertices: %d", outVB, maxVertices);
+ DebugAssertMsg(
+ (renderMode == kDrawIndexedQuads && (outIB != NULL && maxIndices > 0)) ||
+ (renderMode == kDrawIndexedPoints && (outIB != NULL && maxIndices > 0)) ||
+ (renderMode == kDrawIndexedLines && (outIB != NULL && maxIndices > 0)) ||
+ (renderMode == kDrawIndexedTriangles && (outIB != NULL && maxIndices > 0)) ||
+ (renderMode == kDrawIndexedTriangleStrip && (outIB != NULL && maxIndices > 0)) ||
+ (renderMode == kDrawTriangleStrip && (outIB == NULL && maxIndices == 0)) ||
+ (renderMode == kDrawQuads && (outIB == NULL && maxIndices == 0)),
+ "DynamicD3D11VBO::GetChunk - renderMode: %d outIB: 0x%08x maxIndices: %d", renderMode, outIB, maxIndices);
+
+ HRESULT hr;
+ bool success = true;
+
+ m_LendedChunk = true;
+ m_LastChunkShaderChannelMask = shaderChannelMask;
+ m_LastRenderMode = renderMode;
+
+ if( maxVertices == 0 )
+ maxVertices = 8;
+
+ m_LastChunkStride = 0;
+ for( int i = 0; i < kShaderChannelCount; ++i ) {
+ if( shaderChannelMask & (1<<i) )
+ m_LastChunkStride += VBO::GetDefaultChannelByteSize(i);
+ }
+ ID3D11Device* dev = GetD3D11Device();
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+
+ // -------- vertex buffer
+
+ DebugAssertIf( !outVB );
+ UInt32 vbCapacity = maxVertices * m_LastChunkStride;
+ // check if requested chunk is larger than current buffer
+ if( vbCapacity > m_VBSize ) {
+ m_VBSize = vbCapacity * 2; // allocate more up front
+ if( m_VB )
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_VB);
+ m_VB->Release();
+ }
+ m_VB = NULL;
+ }
+ // allocate buffer if don't have it yet
+ if( !m_VB )
+ {
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = m_VBSize;
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+ hr = dev->CreateBuffer (&desc, NULL, &m_VB);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(m_VB,m_VBSize,this);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to create dynamic vertex buffer of size %d [%x]\n", m_VBSize, hr);
+ success = false;
+ *outVB = NULL;
+ }
+ SetDebugNameD3D11 (m_VB, Format("VertexBufferDynamic-%d", m_VBSize));
+ }
+
+ // map, making sure the offset we lock is multiple of vertex stride
+ if (m_VB)
+ {
+ m_VBUsedBytes = ((m_VBUsedBytes + (m_LastChunkStride-1)) / m_LastChunkStride) * m_LastChunkStride;
+ if (m_VBUsedBytes + vbCapacity > m_VBSize)
+ {
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ hr = ctx->Map (m_VB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to lock dynamic vertex buffer with discard [%x]\n", hr);
+ *outVB = NULL;
+ success = false;
+ }
+ *outVB = mapped.pData;
+ m_VBUsedBytes = 0;
+ } else {
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ hr = ctx->Map (m_VB, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to lock vertex index buffer, offset %i size %i [%x]\n", m_VBUsedBytes, vbCapacity, hr);
+ *outVB = NULL;
+ success = false;
+ }
+ *outVB = ((UInt8*)mapped.pData) + m_VBUsedBytes;
+ }
+ m_LastChunkStartVertex = m_VBUsedBytes / m_LastChunkStride;
+ DebugAssertIf( m_LastChunkStartVertex * m_LastChunkStride != m_VBUsedBytes );
+ }
+
+ // -------- index buffer
+
+ const bool indexed = (renderMode != kDrawQuads) && (renderMode != kDrawTriangleStrip);
+ if( success && maxIndices && indexed )
+ {
+ UInt32 ibCapacity = maxIndices * kVBOIndexSize;
+ // check if requested chunk is larger than current buffer
+ if( ibCapacity > m_IBSize ) {
+ m_IBSize = ibCapacity * 2; // allocate more up front
+ if( m_IB )
+ {
+ REGISTER_EXTERNAL_GFX_DEALLOCATION(m_IB);
+ m_IB->Release();
+ }
+ m_IB = NULL;
+ }
+ // allocate buffer if don't have it yet
+ if( !m_IB )
+ {
+ D3D11_BUFFER_DESC desc;
+ desc.ByteWidth = m_IBSize;
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ desc.StructureByteStride = 0;
+ hr = dev->CreateBuffer (&desc, NULL, &m_IB);
+ REGISTER_EXTERNAL_GFX_ALLOCATION_REF(m_IB,m_IBSize,this);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to create dynamic index buffer of size %d [%x]\n", m_IBSize, hr);
+ if (m_VB)
+ ctx->Unmap (m_VB, 0);
+ }
+ SetDebugNameD3D11 (m_IB, Format("IndexBufferDynamic-%d", m_IBSize));
+ }
+ // lock it if we have IB created successfully
+ if( m_IB )
+ {
+ if( m_IBUsedBytes + ibCapacity > m_IBSize )
+ {
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ hr = ctx->Map (m_IB, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to lock dynamic index buffer with discard [%x]\n", hr);
+ *outIB = NULL;
+ success = false;
+ if (m_VB)
+ ctx->Unmap (m_VB, 0);
+ }
+ *outIB = mapped.pData;
+ m_IBUsedBytes = 0;
+ } else {
+ D3D11_MAPPED_SUBRESOURCE mapped;
+ hr = ctx->Map (m_IB, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped);
+ if (FAILED(hr))
+ {
+ printf_console ("d3d11: failed to lock dynamic index buffer, offset %i size %i [%x]\n", m_IBUsedBytes, ibCapacity, hr);
+ *outIB = NULL;
+ success = false;
+ if (m_VB)
+ ctx->Unmap (m_VB, 0);
+ }
+ *outIB = ((UInt8*)mapped.pData) + m_IBUsedBytes;
+ }
+ m_LastChunkStartIndex = m_IBUsedBytes / 2;
+ }
+ else
+ {
+ *outIB = NULL;
+ success = false;
+ }
+ }
+
+ if( !success )
+ m_LendedChunk = false;
+
+ return success;
+}
+
+void DynamicD3D11VBO::ReleaseChunk( UInt32 actualVertices, UInt32 actualIndices )
+{
+ Assert( m_LendedChunk );
+ Assert( m_LastRenderMode == kDrawIndexedTriangleStrip || m_LastRenderMode == kDrawIndexedQuads || m_LastRenderMode == kDrawIndexedPoints || m_LastRenderMode == kDrawIndexedLines || actualIndices % 3 == 0 );
+ m_LendedChunk = false;
+
+ const bool indexed = (m_LastRenderMode != kDrawQuads) && (m_LastRenderMode != kDrawTriangleStrip);
+
+ m_LastChunkVertices = actualVertices;
+ m_LastChunkIndices = actualIndices;
+
+ // unlock buffers
+ ID3D11DeviceContext* ctx = GetD3D11Context();
+ ctx->Unmap (m_VB, 0);
+ if (indexed)
+ ctx->Unmap (m_IB, 0);
+
+ if( !actualVertices || (indexed && !actualIndices) ) {
+ m_LastChunkShaderChannelMask = 0;
+ return;
+ }
+
+ UInt32 actualVBSize = actualVertices * m_LastChunkStride;
+ m_VBUsedBytes += actualVBSize;
+ UInt32 actualIBSize = actualIndices * kVBOIndexSize;
+ m_IBUsedBytes += actualIBSize;
+}
+
+