d3d12: Refactor index management

Separates it from vertex management and move all the logic (forced
indexing, index count calculation...) outside of GSRender.
This commit is contained in:
vlj 2015-06-29 19:20:18 +02:00 committed by Vincent Lejeune
parent 1f3fbe91e2
commit 8801abb93a
3 changed files with 151 additions and 135 deletions

View File

@ -275,9 +275,9 @@ isContained(const std::vector<std::pair<u32, u32> > &ranges, const std::pair<u32
return false;
}
std::pair<std::vector<D3D12_VERTEX_BUFFER_VIEW>, D3D12_INDEX_BUFFER_VIEW> D3D12GSRender::UploadVertexBuffers(bool indexed_draw)
std::vector<D3D12_VERTEX_BUFFER_VIEW> D3D12GSRender::UploadVertexBuffers(bool indexed_draw)
{
std::pair<std::vector<D3D12_VERTEX_BUFFER_VIEW>, D3D12_INDEX_BUFFER_VIEW> result;
std::vector<D3D12_VERTEX_BUFFER_VIEW> result;
const std::vector<VertexBufferFormat> &vertexBufferFormat = FormatVertexData(m_vertex_data);
m_IASet = getIALayout(m_device, vertexBufferFormat, m_vertex_data);
@ -310,10 +310,17 @@ std::pair<std::vector<D3D12_VERTEX_BUFFER_VIEW>, D3D12_INDEX_BUFFER_VIEW> D3D12G
vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
vertexBufferView.SizeInBytes = (UINT)subBufferSize;
vertexBufferView.StrideInBytes = (UINT)vbf.stride;
result.first.push_back(vertexBufferView);
result.push_back(vertexBufferView);
}
return result;
}
D3D12_INDEX_BUFFER_VIEW D3D12GSRender::uploadIndexBuffers(bool indexed_draw)
{
D3D12_INDEX_BUFFER_VIEW indexBufferView = {};
// Only handle quads and triangle fan now
bool forcedIndexBuffer = false;
switch (m_draw_mode - 1)
{
default:
@ -325,126 +332,140 @@ std::pair<std::vector<D3D12_VERTEX_BUFFER_VIEW>, D3D12_INDEX_BUFFER_VIEW> D3D12G
case GL_TRIANGLE_STRIP:
case GL_QUAD_STRIP:
case GL_POLYGON:
m_forcedIndexBuffer = false;
forcedIndexBuffer = false;
break;
case GL_TRIANGLE_FAN:
case GL_QUADS:
m_forcedIndexBuffer = true;
forcedIndexBuffer = true;
break;
}
if (indexed_draw || m_forcedIndexBuffer)
// No need for index buffer
if (!indexed_draw && !forcedIndexBuffer)
{
D3D12_INDEX_BUFFER_VIEW indexBufferView = {};
size_t indexSize;
m_renderingInfo.m_indexed = false;
m_renderingInfo.m_count = m_draw_array_count;
m_renderingInfo.m_baseVertex = m_draw_array_first;
return indexBufferView;
}
if (!indexed_draw)
m_renderingInfo.m_indexed = true;
// Index type
size_t indexSize;
if (!indexed_draw)
{
indexBufferView.Format = DXGI_FORMAT_R16_UINT;
indexSize = 2;
}
else
{
switch (m_indexed_array.m_type)
{
default: abort();
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
indexBufferView.Format = DXGI_FORMAT_R16_UINT;
indexSize = 2;
break;
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
indexBufferView.Format = DXGI_FORMAT_R32_UINT;
indexSize = 4;
break;
}
else
{
switch (m_indexed_array.m_type)
{
default: abort();
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
indexBufferView.Format = DXGI_FORMAT_R16_UINT;
indexSize = 2;
break;
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
indexBufferView.Format = DXGI_FORMAT_R32_UINT;
indexSize = 4;
break;
}
}
if (indexed_draw && !m_forcedIndexBuffer)
indexCount = m_indexed_array.m_data.size() / indexSize;
else if (indexed_draw && m_forcedIndexBuffer)
indexCount = 6 * m_indexed_array.m_data.size() / (4 * indexSize);
else
{
switch (m_draw_mode - 1)
{
case GL_TRIANGLE_FAN:
indexCount = (m_draw_array_count - 2) * 3;
break;
case GL_QUADS:
indexCount = m_draw_array_count * 6 / 4;
break;
}
}
size_t subBufferSize = align(indexCount * indexSize, 64);
assert(m_vertexIndexData.canAlloc(subBufferSize));
size_t heapOffset = m_vertexIndexData.alloc(subBufferSize);
ID3D12Resource *indexBuffer;
check(m_device->CreatePlacedResource(
m_vertexIndexData.m_heap,
heapOffset,
&getBufferResourceDesc(subBufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&indexBuffer)
));
void *bufferMap;
check(indexBuffer->Map(0, nullptr, (void**)&bufferMap));
if (indexed_draw && !m_forcedIndexBuffer)
streamBuffer(bufferMap, m_indexed_array.m_data.data(), subBufferSize);
else if (indexed_draw && m_forcedIndexBuffer)
{
// Only quads supported now
switch (m_indexed_array.m_type)
{
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
expandIndexedQuads<unsigned int>(bufferMap, m_indexed_array.m_data.data(), m_indexed_array.m_data.size() / 4);
break;
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
expandIndexedQuads<unsigned short>(bufferMap, m_indexed_array.m_data.data(), m_indexed_array.m_data.size() / 2);
break;
}
}
else
{
unsigned short *typedDst = static_cast<unsigned short *>(bufferMap);
switch (m_draw_mode - 1)
{
case GL_TRIANGLE_FAN:
for (unsigned i = 0; i < (m_draw_array_count - 2); i++)
{
typedDst[3 * i] = 0;
typedDst[3 * i + 1] = i + 2 - 1;
typedDst[3 * i + 2] = i + 2;
}
break;
case GL_QUADS:
for (unsigned i = 0; i < m_draw_array_count / 4; i++)
{
// First triangle
typedDst[6 * i] = 4 * i;
typedDst[6 * i + 1] = 4 * i + 1;
typedDst[6 * i + 2] = 4 * i + 2;
// Second triangle
typedDst[6 * i + 3] = 4 * i + 2;
typedDst[6 * i + 4] = 4 * i + 3;
typedDst[6 * i + 5] = 4 * i;
}
break;
}
}
indexBuffer->Unmap(0, nullptr);
m_vertexIndexData.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, subBufferSize, indexBuffer));
indexBufferView.SizeInBytes = (UINT)subBufferSize;
indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress();
result.second = indexBufferView;
}
return result;
// Index count
if (indexed_draw && !forcedIndexBuffer)
m_renderingInfo.m_count = m_indexed_array.m_data.size() / indexSize;
else if (indexed_draw && forcedIndexBuffer)
m_renderingInfo.m_count = 6 * m_indexed_array.m_data.size() / (4 * indexSize);
else
{
switch (m_draw_mode - 1)
{
case GL_TRIANGLE_FAN:
m_renderingInfo.m_count = (m_draw_array_count - 2) * 3;
break;
case GL_QUADS:
m_renderingInfo.m_count = m_draw_array_count * 6 / 4;
break;
}
}
// Base vertex
if (!indexed_draw && forcedIndexBuffer)
m_renderingInfo.m_baseVertex = m_draw_array_first;
else
m_renderingInfo.m_baseVertex = 0;
// Alloc
size_t subBufferSize = align(m_renderingInfo.m_count * indexSize, 64);
assert(m_vertexIndexData.canAlloc(subBufferSize));
size_t heapOffset = m_vertexIndexData.alloc(subBufferSize);
ID3D12Resource *indexBuffer;
check(m_device->CreatePlacedResource(
m_vertexIndexData.m_heap,
heapOffset,
&getBufferResourceDesc(subBufferSize),
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&indexBuffer)
));
void *bufferMap;
check(indexBuffer->Map(0, nullptr, (void**)&bufferMap));
if (indexed_draw && !forcedIndexBuffer)
streamBuffer(bufferMap, m_indexed_array.m_data.data(), subBufferSize);
else if (indexed_draw && forcedIndexBuffer)
{
// Only quads supported now
switch (m_indexed_array.m_type)
{
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32:
expandIndexedQuads<unsigned int>(bufferMap, m_indexed_array.m_data.data(), m_indexed_array.m_data.size() / 4);
break;
case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16:
expandIndexedQuads<unsigned short>(bufferMap, m_indexed_array.m_data.data(), m_indexed_array.m_data.size() / 2);
break;
}
}
else
{
unsigned short *typedDst = static_cast<unsigned short *>(bufferMap);
switch (m_draw_mode - 1)
{
case GL_TRIANGLE_FAN:
for (unsigned i = 0; i < (m_draw_array_count - 2); i++)
{
typedDst[3 * i] = 0;
typedDst[3 * i + 1] = i + 2 - 1;
typedDst[3 * i + 2] = i + 2;
}
break;
case GL_QUADS:
for (unsigned i = 0; i < m_draw_array_count / 4; i++)
{
// First triangle
typedDst[6 * i] = 4 * i;
typedDst[6 * i + 1] = 4 * i + 1;
typedDst[6 * i + 2] = 4 * i + 2;
// Second triangle
typedDst[6 * i + 3] = 4 * i + 2;
typedDst[6 * i + 4] = 4 * i + 3;
typedDst[6 * i + 5] = 4 * i;
}
break;
}
}
indexBuffer->Unmap(0, nullptr);
m_vertexIndexData.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, subBufferSize, indexBuffer));
indexBufferView.SizeInBytes = (UINT)subBufferSize;
indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress();
return indexBufferView;
}
void D3D12GSRender::setScaleOffset()

View File

@ -508,10 +508,11 @@ void D3D12GSRender::ExecCMD()
std::chrono::time_point<std::chrono::system_clock> startVertexTime = std::chrono::system_clock::now();
if (m_indexed_array.m_count || m_draw_array_count)
{
const std::pair<std::vector<D3D12_VERTEX_BUFFER_VIEW>, D3D12_INDEX_BUFFER_VIEW> &vertexIndexBufferViews = UploadVertexBuffers(m_indexed_array.m_count ? true : false);
commandList->IASetVertexBuffers(0, (UINT)vertexIndexBufferViews.first.size(), vertexIndexBufferViews.first.data());
if (m_forcedIndexBuffer || m_indexed_array.m_count)
commandList->IASetIndexBuffer(&vertexIndexBufferViews.second);
const std::vector<D3D12_VERTEX_BUFFER_VIEW> &vertexBufferViews = UploadVertexBuffers(m_indexed_array.m_count ? true : false);
const D3D12_INDEX_BUFFER_VIEW &indexBufferView = uploadIndexBuffers(m_indexed_array.m_count ? true : false);
commandList->IASetVertexBuffers(0, (UINT)vertexBufferViews.size(), vertexBufferViews.data());
if (m_renderingInfo.m_indexed)
commandList->IASetIndexBuffer(&indexBufferView);
}
std::chrono::time_point<std::chrono::system_clock> endVertexTime = std::chrono::system_clock::now();
m_timers.m_vertexUploadDuration += std::chrono::duration_cast<std::chrono::microseconds>(endVertexTime - startVertexTime).count();
@ -635,14 +636,13 @@ void D3D12GSRender::ExecCMD()
D3D12_RECT box =
{
0,
0,
0,
(LONG)m_surface_clip_w,
(LONG)m_surface_clip_h,
};
commandList->RSSetScissorRects(1, &box);
bool requireIndexBuffer = false;
switch (m_draw_mode - 1)
{
case GL_POINTS:
@ -664,31 +664,21 @@ void D3D12GSRender::ExecCMD()
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
break;
case GL_TRIANGLE_FAN:
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
requireIndexBuffer = true;
break;
case GL_QUADS:
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
requireIndexBuffer = true;
break;
case GL_QUAD_STRIP:
case GL_POLYGON:
default:
commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// LOG_ERROR(RSX, "Unsupported primitive type");
LOG_ERROR(RSX, "Unsupported primitive type");
break;
}
// Indexed quad
if (m_forcedIndexBuffer && m_indexed_array.m_count)
commandList->DrawIndexedInstanced((UINT)indexCount, 1, 0, 0, 0);
// Non indexed quad/triangle fan
else if (m_forcedIndexBuffer && !m_indexed_array.m_count)
commandList->DrawIndexedInstanced((UINT)indexCount, 1, 0, (UINT)m_draw_array_first, 0);
// Indexed triangles
else if (m_indexed_array.m_count)
commandList->DrawIndexedInstanced((UINT)m_indexed_array.m_data.size() / ((m_indexed_array.m_type == CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16) ? 2 : 4), 1, 0, 0, 0);
else if (m_draw_array_count)
commandList->DrawInstanced(m_draw_array_count, 1, m_draw_array_first, 0);
if (m_renderingInfo.m_indexed)
commandList->DrawIndexedInstanced((UINT)m_renderingInfo.m_count, 1, 0, m_renderingInfo.m_baseVertex, 0);
else
commandList->DrawInstanced((UINT)m_renderingInfo.m_count, 1, m_renderingInfo.m_baseVertex, 0);
check(commandList->Close());
m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&commandList);

View File

@ -331,8 +331,12 @@ private:
DataHeap<ID3D12Heap, 65536> m_UAVHeap;
DataHeap<ID3D12Heap, 65536> m_readbackResources;
bool m_forcedIndexBuffer;
size_t indexCount;
struct
{
bool m_indexed;
size_t m_count;
size_t m_baseVertex;
} m_renderingInfo;
RenderTargets m_rtts;
@ -372,7 +376,8 @@ private:
virtual void Close() override;
bool LoadProgram();
std::pair<std::vector<D3D12_VERTEX_BUFFER_VIEW>, D3D12_INDEX_BUFFER_VIEW> UploadVertexBuffers(bool indexed_draw = false);
std::vector<D3D12_VERTEX_BUFFER_VIEW> UploadVertexBuffers(bool indexed_draw = false);
D3D12_INDEX_BUFFER_VIEW uploadIndexBuffers(bool indexed_draw = false);
void setScaleOffset();
void FillVertexShaderConstantsBuffer();
void FillPixelShaderConstantsBuffer();