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 ...@@ -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) void Buffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
{ {
// Pass it along! // Pass it along!
......
...@@ -45,6 +45,7 @@ class BufferState final : angle::NonCopyable ...@@ -45,6 +45,7 @@ class BufferState final : angle::NonCopyable
GLint64 getMapLength() const { return mMapLength; } GLint64 getMapLength() const { return mMapLength; }
GLint64 getSize() const { return mSize; } GLint64 getSize() const { return mSize; }
bool isBoundForTransformFeedback() const { return mTransformFeedbackIndexedBindingCount != 0; } bool isBoundForTransformFeedback() const { return mTransformFeedbackIndexedBindingCount != 0; }
std::string getLabel() const { return mLabel; }
private: private:
friend class Buffer; friend class Buffer;
...@@ -108,7 +109,7 @@ class Buffer final : public RefCountObject<BufferID>, ...@@ -108,7 +109,7 @@ class Buffer final : public RefCountObject<BufferID>,
size_t count, size_t count,
bool primitiveRestartEnabled, bool primitiveRestartEnabled,
IndexRange *outRange) const; IndexRange *outRange) const;
const BufferState &getState() const { return mState; }
BufferUsage getUsage() const { return mState.mUsage; } BufferUsage getUsage() const { return mState.mUsage; }
GLbitfield getAccessFlags() const { return mState.mAccessFlags; } GLbitfield getAccessFlags() const { return mState.mAccessFlags; }
GLenum getAccess() const { return mState.mAccess; } GLenum getAccess() const { return mState.mAccess; }
...@@ -137,6 +138,10 @@ class Buffer final : public RefCountObject<BufferID>, ...@@ -137,6 +138,10 @@ class Buffer final : public RefCountObject<BufferID>,
bool isDoubleBoundForTransformFeedback() const; bool isDoubleBoundForTransformFeedback() const;
void onTFBindingChanged(const Context *context, bool bound, bool indexed); void onTFBindingChanged(const Context *context, bool bound, bool indexed);
void onNonTFBindingChanged(int incr) { mState.mBindingCount += incr; } void onNonTFBindingChanged(int incr) { mState.mBindingCount += incr; }
angle::Result getSubData(const gl::Context *context,
GLintptr offset,
GLsizeiptr size,
void *outData);
// angle::ObserverInterface implementation. // angle::ObserverInterface implementation.
void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override; void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "common/MemoryBuffer.h" #include "common/MemoryBuffer.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/BinaryStream.h" #include "libANGLE/BinaryStream.h"
#include "libANGLE/Buffer.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Framebuffer.h" #include "libANGLE/Framebuffer.h"
#include "libANGLE/renderer/FramebufferImpl.h" #include "libANGLE/renderer/FramebufferImpl.h"
...@@ -50,25 +51,36 @@ Result ReadPixelsFromAttachment(const gl::Context *context, ...@@ -50,25 +51,36 @@ Result ReadPixelsFromAttachment(const gl::Context *context,
Result SerializeContext(gl::BinaryOutputStream *bos, const gl::Context *context) Result SerializeContext(gl::BinaryOutputStream *bos, const gl::Context *context)
{ {
ScratchBuffer scratchBuffer(1);
const gl::FramebufferManager &framebufferManager = const gl::FramebufferManager &framebufferManager =
context->getState().getFramebufferManagerForCapture(); context->getState().getFramebufferManagerForCapture();
for (const auto &framebuffer : framebufferManager) for (const auto &framebuffer : framebufferManager)
{ {
gl::Framebuffer *framebufferPtr = framebuffer.second; 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; return Result::Continue;
} }
Result SerializeFramebuffer(const gl::Context *context, Result SerializeFramebuffer(const gl::Context *context,
gl::BinaryOutputStream *bos, gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer) gl::Framebuffer *framebuffer)
{ {
return SerializeFramebufferState(context, bos, framebuffer, framebuffer->getState()); return SerializeFramebufferState(context, bos, scratchBuffer, framebuffer,
framebuffer->getState());
} }
Result SerializeFramebufferState(const gl::Context *context, Result SerializeFramebufferState(const gl::Context *context,
gl::BinaryOutputStream *bos, gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer, gl::Framebuffer *framebuffer,
const gl::FramebufferState &framebufferState) const gl::FramebufferState &framebufferState)
{ {
...@@ -84,34 +96,32 @@ Result SerializeFramebufferState(const gl::Context *context, ...@@ -84,34 +96,32 @@ Result SerializeFramebufferState(const gl::Context *context,
const std::vector<gl::FramebufferAttachment> &colorAttachments = const std::vector<gl::FramebufferAttachment> &colorAttachments =
framebufferState.getColorAttachments(); framebufferState.getColorAttachments();
ScratchBuffer scratchBuffer(1);
for (const gl::FramebufferAttachment &colorAttachment : colorAttachments) for (const gl::FramebufferAttachment &colorAttachment : colorAttachments)
{ {
if (colorAttachment.isAttached()) if (colorAttachment.isAttached())
{ {
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer, ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
colorAttachment)); colorAttachment));
} }
} }
if (framebuffer->getDepthStencilAttachment()) if (framebuffer->getDepthStencilAttachment())
{ {
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer, ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
*framebuffer->getDepthStencilAttachment())); *framebuffer->getDepthStencilAttachment()));
} }
else else
{ {
if (framebuffer->getDepthAttachment()) if (framebuffer->getDepthAttachment())
{ {
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer, ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
*framebuffer->getDepthAttachment())); *framebuffer->getDepthAttachment()));
} }
if (framebuffer->getStencilAttachment()) if (framebuffer->getStencilAttachment())
{ {
ANGLE_TRY(SerializeFramebufferAttachment(context, bos, &scratchBuffer, framebuffer, ANGLE_TRY(SerializeFramebufferAttachment(context, bos, scratchBuffer, framebuffer,
*framebuffer->getStencilAttachment())); *framebuffer->getStencilAttachment()));
} }
} }
scratchBuffer.clear();
return Result::Continue; return Result::Continue;
} }
...@@ -158,4 +168,31 @@ void SerializeImageIndex(gl::BinaryOutputStream *bos, const gl::ImageIndex &imag ...@@ -158,4 +168,31 @@ void SerializeImageIndex(gl::BinaryOutputStream *bos, const gl::ImageIndex &imag
bos->writeInt(imageIndex.getLayerCount()); 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 } // namespace angle
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
namespace gl namespace gl
{ {
class BinaryOutputStream; class BinaryOutputStream;
class Buffer;
class BufferState;
class Context; class Context;
class Framebuffer; class Framebuffer;
class FramebufferAttachment; class FramebufferAttachment;
...@@ -34,10 +36,12 @@ Result SerializeContext(gl::BinaryOutputStream *bos, const gl::Context *context) ...@@ -34,10 +36,12 @@ Result SerializeContext(gl::BinaryOutputStream *bos, const gl::Context *context)
Result SerializeFramebuffer(const gl::Context *context, Result SerializeFramebuffer(const gl::Context *context,
gl::BinaryOutputStream *bos, gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer); gl::Framebuffer *framebuffer);
Result SerializeFramebufferState(const gl::Context *context, Result SerializeFramebufferState(const gl::Context *context,
gl::BinaryOutputStream *bos, gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer, gl::Framebuffer *framebuffer,
const gl::FramebufferState &framebufferState); const gl::FramebufferState &framebufferState);
...@@ -49,5 +53,12 @@ Result SerializeFramebufferAttachment(const gl::Context *context, ...@@ -49,5 +53,12 @@ Result SerializeFramebufferAttachment(const gl::Context *context,
void SerializeImageIndex(gl::BinaryOutputStream *bos, const gl::ImageIndex &imageIndex); 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 } // namespace angle
#endif // FRAME_CAPTURE_UTILS_H_ #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 ...@@ -65,6 +65,11 @@ class BufferImpl : public angle::Subject
bool primitiveRestartEnabled, bool primitiveRestartEnabled,
gl::IndexRange *outRange) = 0; 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 // Override if accurate native memory size information is available
virtual GLint64 getMemorySize() const; virtual GLint64 getMemorySize() const;
......
...@@ -433,6 +433,36 @@ angle::Result BufferVk::unmapImpl(ContextVk *contextVk) ...@@ -433,6 +433,36 @@ angle::Result BufferVk::unmapImpl(ContextVk *contextVk)
return angle::Result::Continue; 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, angle::Result BufferVk::getIndexRange(const gl::Context *context,
gl::DrawElementsType type, gl::DrawElementsType type,
size_t offset, size_t offset,
......
...@@ -70,6 +70,10 @@ class BufferVk : public BufferImpl ...@@ -70,6 +70,10 @@ class BufferVk : public BufferImpl
GLbitfield access, GLbitfield access,
void **mapPtr) override; void **mapPtr) override;
angle::Result unmap(const gl::Context *context, GLboolean *result) 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, angle::Result getIndexRange(const gl::Context *context,
gl::DrawElementsType type, gl::DrawElementsType type,
......
...@@ -702,6 +702,11 @@ class BufferHelper final : public Resource ...@@ -702,6 +702,11 @@ class BufferHelper final : public Resource
bool valid() const { return mBuffer.valid(); } bool valid() const { return mBuffer.valid(); }
const Buffer &getBuffer() const { return mBuffer; } const Buffer &getBuffer() const { return mBuffer; }
VkDeviceSize getSize() const { return mSize; } VkDeviceSize getSize() const { return mSize; }
const uint8_t *getMappedMemory() const
{
ASSERT(isMapped());
return mMappedMemory;
}
bool isHostVisible() const bool isHostVisible() const
{ {
return (mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; return (mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0;
...@@ -711,6 +716,8 @@ class BufferHelper final : public Resource ...@@ -711,6 +716,8 @@ class BufferHelper final : public Resource
return (mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0; 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 // Set write access mask when the buffer is modified externally, e.g. by host. There is no
// graph resource to create a dependency to. // graph resource to create a dependency to.
void onExternalWrite(VkAccessFlags writeAccessType) void onExternalWrite(VkAccessFlags writeAccessType)
......
...@@ -412,6 +412,7 @@ libangle_sources = [ ...@@ -412,6 +412,7 @@ libangle_sources = [
"src/libANGLE/formatutils.cpp", "src/libANGLE/formatutils.cpp",
"src/libANGLE/queryconversions.cpp", "src/libANGLE/queryconversions.cpp",
"src/libANGLE/queryutils.cpp", "src/libANGLE/queryutils.cpp",
"src/libANGLE/renderer/BufferImpl.cpp",
"src/libANGLE/renderer/ContextImpl.cpp", "src/libANGLE/renderer/ContextImpl.cpp",
"src/libANGLE/renderer/DeviceImpl.cpp", "src/libANGLE/renderer/DeviceImpl.cpp",
"src/libANGLE/renderer/DisplayImpl.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