Commit dc9743fb by Manh Nguyen Committed by Commit Bot

Add buffer serialization capability

Serializes buffers' states stored on CPU. Gets buffers contents on GPU by mapping buffers to CPU's address space, then copy their data. Unmap buffers after finish. Since this feature is for tests only, it is only implemented for the Vulkan backend. Adds buffer serialization to serializeContext method so that capture replay regresssion testing now compares the states of buffers too. Bug: angleproject:4817 Change-Id: Ic9b529701014d5ba8420023a021cd5ea381bd9a1 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2295950 Commit-Queue: Manh Nguyen <nguyenmh@google.com> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent a3ed8e19
......@@ -291,6 +291,14 @@ void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed
}
}
angle::Result Buffer::getSubData(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
void *outData)
{
return mImpl->getSubData(context, offset, size, outData);
}
void Buffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
{
// Pass it along!
......
......@@ -45,6 +45,7 @@ class BufferState final : angle::NonCopyable
GLint64 getMapLength() const { return mMapLength; }
GLint64 getSize() const { return mSize; }
bool isBoundForTransformFeedback() const { return mTransformFeedbackIndexedBindingCount != 0; }
std::string getLabel() const { return mLabel; }
private:
friend class Buffer;
......@@ -108,7 +109,7 @@ class Buffer final : public RefCountObject<BufferID>,
size_t count,
bool primitiveRestartEnabled,
IndexRange *outRange) const;
const BufferState &getState() const { return mState; }
BufferUsage getUsage() const { return mState.mUsage; }
GLbitfield getAccessFlags() const { return mState.mAccessFlags; }
GLenum getAccess() const { return mState.mAccess; }
......@@ -137,6 +138,10 @@ class Buffer final : public RefCountObject<BufferID>,
bool isDoubleBoundForTransformFeedback() const;
void onTFBindingChanged(const Context *context, bool bound, bool indexed);
void onNonTFBindingChanged(int incr) { mState.mBindingCount += incr; }
angle::Result getSubData(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
void *outData);
// angle::ObserverInterface implementation.
void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;
......
......@@ -12,6 +12,7 @@
#include "common/MemoryBuffer.h"
#include "common/angleutils.h"
#include "libANGLE/BinaryStream.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Context.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/renderer/FramebufferImpl.h"
......@@ -50,25 +51,36 @@ Result ReadPixelsFromAttachment(const gl::Context *context,
Result SerializeContext(gl::BinaryOutputStream *bos, const gl::Context *context)
{
ScratchBuffer scratchBuffer(1);
const gl::FramebufferManager &framebufferManager =
context->getState().getFramebufferManagerForCapture();
for (const auto &framebuffer : framebufferManager)
{
gl::Framebuffer *framebufferPtr = framebuffer.second;
ANGLE_TRY(SerializeFramebuffer(context, bos, framebufferPtr));
ANGLE_TRY(SerializeFramebuffer(context, bos, &scratchBuffer, framebufferPtr));
}
const gl::BufferManager &bufferManager = context->getState().getBufferManagerForCapture();
for (const auto &buffer : bufferManager)
{
gl::Buffer *bufferPtr = buffer.second;
ANGLE_TRY(SerializeBuffer(context, bos, &scratchBuffer, bufferPtr));
}
scratchBuffer.clear();
return Result::Continue;
}
Result SerializeFramebuffer(const gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer)
{
return SerializeFramebufferState(context, bos, framebuffer, framebuffer->getState());
return SerializeFramebufferState(context, bos, scratchBuffer, framebuffer,
framebuffer->getState());
}
Result SerializeFramebufferState(const gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer,
const gl::FramebufferState &framebufferState)
{
......@@ -84,34 +96,32 @@ Result SerializeFramebufferState(const gl::Context *context,
const std::vector<gl::FramebufferAttachment> &colorAttachments =
framebufferState.getColorAttachments();
ScratchBuffer scratchBuffer(1);
for (const gl::FramebufferAttachment &colorAttachment : colorAttachments)
{
if (colorAttachment.isAttached())
{
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer,
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
colorAttachment));
}
}
if (framebuffer->getDepthStencilAttachment())
{
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer,
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
*framebuffer->getDepthStencilAttachment()));
}
else
{
if (framebuffer->getDepthAttachment())
{
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer,
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
*framebuffer->getDepthAttachment()));
}
if (framebuffer->getStencilAttachment())
{
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer,
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
*framebuffer->getStencilAttachment()));
}
}
scratchBuffer.clear();
return Result::Continue;
}
......@@ -158,4 +168,31 @@ void SerializeImageIndex(gl::BinaryOutputStream *bos, const gl::ImageIndex &imag
bos->writeInt(imageIndex.getLayerCount());
}
Result SerializeBuffer(const gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Buffer *buffer)
{
SerializeBufferState(bos, buffer->getState());
MemoryBuffer *dataPtr = nullptr;
ANGLE_CHECK_GL_ALLOC(
const_cast<gl::Context *>(context),
scratchBuffer->getInitialized(static_cast<size_t>(buffer->getSize()), &dataPtr, 0));
ANGLE_TRY(buffer->getSubData(context, 0, dataPtr->size(), dataPtr->data()));
bos->writeBytes(dataPtr->data(), dataPtr->size());
return Result::Continue;
}
void SerializeBufferState(gl::BinaryOutputStream *bos, const gl::BufferState &bufferState)
{
bos->writeString(bufferState.getLabel());
bos->writeEnum(bufferState.getUsage());
bos->writeInt(bufferState.getSize());
bos->writeInt(bufferState.getAccessFlags());
bos->writeInt(bufferState.getAccess());
bos->writeInt(bufferState.isMapped());
bos->writeInt(bufferState.getMapOffset());
bos->writeInt(bufferState.getMapLength());
}
} // namespace angle
......@@ -16,6 +16,8 @@
namespace gl
{
class BinaryOutputStream;
class Buffer;
class BufferState;
class Context;
class Framebuffer;
class FramebufferAttachment;
......@@ -34,10 +36,12 @@ Result SerializeContext(gl::BinaryOutputStream *bos, const gl::Context *context)
Result SerializeFramebuffer(const gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer);
Result SerializeFramebufferState(const gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer,
const gl::FramebufferState &framebufferState);
......@@ -49,5 +53,12 @@ Result SerializeFramebufferAttachment(const gl::Context *context,
void SerializeImageIndex(gl::BinaryOutputStream *bos, const gl::ImageIndex &imageIndex);
Result SerializeBuffer(const gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Buffer *buffer);
void SerializeBufferState(gl::BinaryOutputStream *bos, const gl::BufferState &bufferState);
} // namespace angle
#endif // FRAME_CAPTURE_UTILS_H_
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// BufferImpl.cpp: Implementation methods rx::BufferImpl class.
#include "libANGLE/renderer/BufferImpl.h"
namespace rx
{
angle::Result BufferImpl::getSubData(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
void *outData)
{
UNREACHABLE();
return angle::Result::Stop;
}
} // namespace rx
......@@ -65,6 +65,11 @@ class BufferImpl : public angle::Subject
bool primitiveRestartEnabled,
gl::IndexRange *outRange) = 0;
virtual angle::Result getSubData(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
void *outData);
// Override if accurate native memory size information is available
virtual GLint64 getMemorySize() const;
......
......@@ -433,6 +433,36 @@ angle::Result BufferVk::unmapImpl(ContextVk *contextVk)
return angle::Result::Continue;
}
angle::Result BufferVk::getSubData(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
void *outData)
{
ASSERT(offset + size <= getSize());
if (!mShadowBuffer.valid())
{
ASSERT(mBuffer && mBuffer->valid());
ContextVk *contextVk = vk::GetImpl(context);
ANGLE_TRY(mBuffer->waitForIdle(contextVk));
if (mBuffer->isMapped())
{
memcpy(outData, mBuffer->getMappedMemory() + offset, size);
}
else
{
uint8_t *mappedPtr = nullptr;
ANGLE_TRY(mBuffer->mapWithOffset(contextVk, &mappedPtr, offset));
memcpy(outData, mappedPtr, size);
mBuffer->unmap(contextVk->getRenderer());
}
}
else
{
memcpy(outData, mShadowBuffer.getCurrentBuffer() + offset, size);
}
return angle::Result::Continue;
}
angle::Result BufferVk::getIndexRange(const gl::Context *context,
gl::DrawElementsType type,
size_t offset,
......
......@@ -70,6 +70,10 @@ class BufferVk : public BufferImpl
GLbitfield access,
void **mapPtr) override;
angle::Result unmap(const gl::Context *context, GLboolean *result) override;
angle::Result getSubData(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
void *outData) override;
angle::Result getIndexRange(const gl::Context *context,
gl::DrawElementsType type,
......
......@@ -702,6 +702,11 @@ class BufferHelper final : public Resource
bool valid() const { return mBuffer.valid(); }
const Buffer &getBuffer() const { return mBuffer; }
VkDeviceSize getSize() const { return mSize; }
const uint8_t *getMappedMemory() const
{
ASSERT(isMapped());
return mMappedMemory;
}
bool isHostVisible() const
{
return (mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
......@@ -711,6 +716,8 @@ class BufferHelper final : public Resource
return (mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
}
bool isMapped() const { return mMappedMemory != nullptr; }
// Set write access mask when the buffer is modified externally, e.g. by host. There is no
// graph resource to create a dependency to.
void onExternalWrite(VkAccessFlags writeAccessType)
......
......@@ -412,6 +412,7 @@ libangle_sources = [
"src/libANGLE/formatutils.cpp",
"src/libANGLE/queryconversions.cpp",
"src/libANGLE/queryutils.cpp",
"src/libANGLE/renderer/BufferImpl.cpp",
"src/libANGLE/renderer/ContextImpl.cpp",
"src/libANGLE/renderer/DeviceImpl.cpp",
"src/libANGLE/renderer/DisplayImpl.cpp",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment