зеркало из https://github.com/AvaloniaUI/angle.git
Metal: Reduce memory usage of attribute re-writing
Rework vertex buffer caching to allow us to reuse parts of converted buffers. Reusing conversions dramatically drops the memory usage when drawing index ranges by offset with unaligned attributes. Bug: angleproject:6638 Change-Id: I79797da202629b1632e1397ce1227ee3d7a1c9d7 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3251467 Commit-Queue: Kyle Piddington <kpiddington@apple.com> Reviewed-by: Le Hoang Quyen <le.hoang.q@gmail.com> Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
This commit is contained in:
Родитель
0777af7050
Коммит
77eb8a491b
|
@ -326,7 +326,8 @@ ConversionBufferMtl *BufferMtl::getVertexConversionBuffer(ContextMtl *context,
|
|||
{
|
||||
for (VertexConversionBufferMtl &buffer : mVertexConversionBuffers)
|
||||
{
|
||||
if (buffer.formatID == formatID && buffer.stride == stride && buffer.offset == offset)
|
||||
if (buffer.formatID == formatID && buffer.stride == stride && buffer.offset <= offset &&
|
||||
buffer.offset % buffer.stride == offset % stride)
|
||||
{
|
||||
return &buffer;
|
||||
}
|
||||
|
|
|
@ -148,6 +148,27 @@ size_t GetVertexCount(BufferMtl *srcBuffer,
|
|||
return numVertices;
|
||||
}
|
||||
|
||||
size_t GetVertexCountWithConversion(BufferMtl *srcBuffer,
|
||||
VertexConversionBufferMtl *conversionBuffer,
|
||||
const gl::VertexBinding &binding,
|
||||
uint32_t srcFormatSize)
|
||||
{
|
||||
// Bytes usable for vertex data.
|
||||
GLint64 bytes = srcBuffer->size() -
|
||||
MIN(static_cast<GLintptr>(conversionBuffer->offset), binding.getOffset());
|
||||
if (bytes < srcFormatSize)
|
||||
return 0;
|
||||
|
||||
// Count the last vertex. It may occupy less than a full stride.
|
||||
size_t numVertices = 1;
|
||||
bytes -= srcFormatSize;
|
||||
|
||||
// Count how many strides fit remaining space.
|
||||
if (bytes > 0)
|
||||
numVertices += static_cast<size_t>(bytes) / binding.getStride();
|
||||
|
||||
return numVertices;
|
||||
}
|
||||
inline size_t GetIndexCount(BufferMtl *srcBuffer, size_t offset, gl::DrawElementsType indexType)
|
||||
{
|
||||
size_t elementSize = gl::GetDrawElementsTypeSize(indexType);
|
||||
|
@ -942,14 +963,21 @@ angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext,
|
|||
// Has the content of the buffer has changed since last conversion?
|
||||
if (!conversion->dirty)
|
||||
{
|
||||
VertexConversionBufferMtl *vertexConversionMtl =
|
||||
static_cast<VertexConversionBufferMtl *>(conversion);
|
||||
ASSERT((binding.getOffset() - vertexConversionMtl->offset) % binding.getStride() == 0);
|
||||
mConvertedArrayBufferHolders[attribIndex].set(conversion->convertedBuffer);
|
||||
mCurrentArrayBufferOffsets[attribIndex] = conversion->convertedOffset;
|
||||
mCurrentArrayBufferOffsets[attribIndex] =
|
||||
conversion->convertedOffset +
|
||||
stride * ((binding.getOffset() - vertexConversionMtl->offset) / binding.getStride());
|
||||
|
||||
mCurrentArrayBuffers[attribIndex] = &mConvertedArrayBufferHolders[attribIndex];
|
||||
mCurrentArrayBufferFormats[attribIndex] = &convertedFormat;
|
||||
mCurrentArrayBufferStrides[attribIndex] = stride;
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
numVertices = GetVertexCountWithConversion(
|
||||
srcBuffer, static_cast<VertexConversionBufferMtl *>(conversion), binding, srcFormatSize);
|
||||
|
||||
const angle::Format &convertedAngleFormat = convertedFormat.actualAngleFormat();
|
||||
bool canConvertToFloatOnGPU =
|
||||
|
@ -980,15 +1008,16 @@ angle::Result VertexArrayMtl::convertVertexBuffer(const gl::Context *glContext,
|
|||
convertedFormat, stride, numVertices, conversion));
|
||||
}
|
||||
|
||||
mConvertedArrayBufferHolders[attribIndex].set(conversion->convertedBuffer);
|
||||
mCurrentArrayBufferOffsets[attribIndex] =
|
||||
conversion->convertedOffset +
|
||||
stride *
|
||||
((binding.getOffset() - static_cast<VertexConversionBufferMtl *>(conversion)->offset) /
|
||||
binding.getStride());
|
||||
mCurrentArrayBuffers[attribIndex] = &mConvertedArrayBufferHolders[attribIndex];
|
||||
mCurrentArrayBufferFormats[attribIndex] = &convertedFormat;
|
||||
mCurrentArrayBufferStrides[attribIndex] = stride;
|
||||
|
||||
// Cache the last converted results to be re-used later if the buffer's content won't ever be
|
||||
// changed.
|
||||
conversion->convertedBuffer = mConvertedArrayBufferHolders[attribIndex].getCurrentBuffer();
|
||||
conversion->convertedOffset = mCurrentArrayBufferOffsets[attribIndex];
|
||||
|
||||
ASSERT(conversion->dirty);
|
||||
conversion->dirty = false;
|
||||
|
||||
|
@ -1016,14 +1045,15 @@ angle::Result VertexArrayMtl::convertVertexBufferCPU(ContextMtl *contextMtl,
|
|||
|
||||
const uint8_t *srcBytes = srcBuffer->getClientShadowCopyData(contextMtl);
|
||||
ANGLE_CHECK_GL_ALLOC(contextMtl, srcBytes);
|
||||
|
||||
srcBytes += binding.getOffset();
|
||||
|
||||
ANGLE_TRY(StreamVertexData(
|
||||
contextMtl, &conversion->data, srcBytes, numVertices * targetStride, 0, numVertices,
|
||||
binding.getStride(), convertedFormat.vertexLoadFunction,
|
||||
&mConvertedArrayBufferHolders[attribIndex], &mCurrentArrayBufferOffsets[attribIndex]));
|
||||
|
||||
VertexConversionBufferMtl *vertexConverison =
|
||||
static_cast<VertexConversionBufferMtl *>(conversion);
|
||||
srcBytes += MIN(binding.getOffset(), static_cast<GLintptr>(vertexConverison->offset));
|
||||
SimpleWeakBufferHolderMtl conversionBufferHolder;
|
||||
ANGLE_TRY(StreamVertexData(contextMtl, &conversion->data, srcBytes, numVertices * targetStride,
|
||||
0, numVertices, binding.getStride(),
|
||||
convertedFormat.vertexLoadFunction, &conversionBufferHolder,
|
||||
&conversion->convertedOffset));
|
||||
conversion->convertedBuffer = conversionBufferHolder.getCurrentBuffer();
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
|
@ -1049,11 +1079,13 @@ angle::Result VertexArrayMtl::convertVertexBufferGPU(const gl::Context *glContex
|
|||
ANGLE_CHECK_GL_MATH(contextMtl, numVertices <= std::numeric_limits<uint32_t>::max());
|
||||
|
||||
mtl::VertexFormatConvertParams params;
|
||||
|
||||
VertexConversionBufferMtl *vertexConversion =
|
||||
static_cast<VertexConversionBufferMtl *>(conversion);
|
||||
params.srcBuffer = srcBuffer->getCurrentBuffer();
|
||||
params.srcBufferStartOffset = static_cast<uint32_t>(binding.getOffset());
|
||||
params.srcStride = binding.getStride();
|
||||
params.srcDefaultAlphaData = convertedFormat.defaultAlpha;
|
||||
params.srcBufferStartOffset = static_cast<uint32_t>(
|
||||
MIN(static_cast<GLintptr>(vertexConversion->offset), binding.getOffset()));
|
||||
params.srcStride = binding.getStride();
|
||||
params.srcDefaultAlphaData = convertedFormat.defaultAlpha;
|
||||
|
||||
params.dstBuffer = newBuffer;
|
||||
params.dstBufferStartOffset = static_cast<uint32_t>(newBufferOffset);
|
||||
|
@ -1096,8 +1128,8 @@ angle::Result VertexArrayMtl::convertVertexBufferGPU(const gl::Context *glContex
|
|||
|
||||
ANGLE_TRY(conversion->data.commit(contextMtl));
|
||||
|
||||
mConvertedArrayBufferHolders[attribIndex].set(newBuffer);
|
||||
mCurrentArrayBufferOffsets[attribIndex] = newBufferOffset;
|
||||
conversion->convertedBuffer = newBuffer;
|
||||
conversion->convertedOffset = newBufferOffset;
|
||||
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче