Commit dce37b7d by Manh Nguyen Committed by Commit Bot

Serialize framebuffers + compare contexts for CaptureReplayTests

Adds to frame capture the ability to serialize a frame's pre-swap GL state and store it in the binary data file Adds to CaptureReplayTests the ability to compare its serialized GL state with the serialized state pulled from the binary data file Adds a serialization module that serializes framebuffers' GL states and the contents of their color attachments Adds checks to automation script so that it would skips tests that do not produce the expected trace files Adds exception handling to automation script so that it will not crash when a replay build crashes Bug: angleproject:4779 Change-Id: I40a02e018073749e79f0ddbfd3d4065745548f46 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2258295 Commit-Queue: Manh Nguyen <nguyenmh@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 5fec8ecf
......@@ -98,6 +98,12 @@ config("internal_config") {
defines += [ "ANGLE_IS_32_BIT_CPU" ]
}
if (is_win) {
defines += [ "ANGLE_IS_WIN" ]
} else if (is_linux) {
defines += [ "ANGLE_IS_LINUX" ]
}
if (angle_enable_trace) {
defines += [ "ANGLE_ENABLE_DEBUG_TRACE=1" ]
}
......@@ -907,6 +913,14 @@ angle_static_library("libGLESv2_static") {
public_deps = [ ":libANGLE" ]
}
angle_static_library("libGLESv2_with_capture_static") {
sources = libglesv2_sources
configs += [ ":debug_annotations_config" ]
public_configs += [ ":angle_static" ]
deps = [ ":includes" ]
public_deps = [ ":libANGLE_with_capture" ]
}
angle_shared_library("libGLESv1_CM") {
sources = libglesv1_cm_sources
output_name = "libGLESv1_CM${angle_libs_suffix}"
......@@ -987,6 +1001,19 @@ angle_shared_library("libEGL") {
angle_static_library("libEGL_static") {
sources = libegl_sources
configs += [
":debug_annotations_config",
":library_name_config",
]
public_configs += [ ":angle_static" ]
deps = [
":includes",
":libGLESv2_static",
]
}
angle_static_library("libEGL_with_capture_static") {
sources = libegl_sources
configs += [
":debug_annotations_config",
......@@ -997,7 +1024,7 @@ angle_static_library("libEGL_static") {
deps = [
":includes",
":libGLESv2_static",
":libGLESv2_with_capture_static",
]
}
......
......@@ -73,6 +73,8 @@ Some simple environment variables control frame capture:
foo::ReplayContext1Frame(i);
}
```
* `ANGLE_CAPTURE_SERIALIZE_STATE`:
* Set to `1` to enable GL state serialization. Default is `0`.
A good way to test out the capture is to use environment variables in conjunction with the sample
template. For example:
......
......@@ -236,8 +236,10 @@ class BinaryOutputStream : angle::NonCopyable
const void *data() const { return mData.size() ? &mData[0] : nullptr; }
const std::vector<uint8_t> &getData() const { return mData; }
private:
std::vector<char> mData;
std::vector<uint8_t> mData;
template <typename T>
void write(const T *v, size_t num)
......
......@@ -8437,7 +8437,7 @@ egl::Error Context::unsetDefaultFramebuffer()
return egl::NoError();
}
void Context::onPostSwap() const
void Context::onPreSwap() const
{
// Dump frame capture if enabled.
mFrameCapture->onEndFrame(this);
......
......@@ -604,7 +604,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
return mTransformFeedbackMap;
}
void onPostSwap() const;
void onPreSwap() const;
Program *getActiveLinkedProgram() const;
......
......@@ -28,6 +28,7 @@
#include "libANGLE/VertexArray.h"
#include "libANGLE/capture_gles_2_0_autogen.h"
#include "libANGLE/capture_gles_3_0_autogen.h"
#include "libANGLE/frame_capture_utils.h"
#include "libANGLE/gl_enum_utils.h"
#include "libANGLE/queryconversions.h"
#include "libANGLE/queryutils.h"
......@@ -44,12 +45,13 @@ namespace angle
namespace
{
constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
constexpr char kCaptureLabel[] = "ANGLE_CAPTURE_LABEL";
constexpr char kCompression[] = "ANGLE_CAPTURE_COMPRESSION";
constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
constexpr char kCaptureLabel[] = "ANGLE_CAPTURE_LABEL";
constexpr char kCompression[] = "ANGLE_CAPTURE_COMPRESSION";
constexpr char kSerializeStateEnabledVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
constexpr size_t kBinaryAlignment = 16;
......@@ -910,7 +912,7 @@ void WriteCppReplay(bool compression,
void WriteCppReplayIndexFiles(bool compression,
const std::string &outDir,
gl::ContextID contextId,
const gl::Context *context,
const std::string &captureLabel,
uint32_t frameStart,
uint32_t frameEnd,
......@@ -918,8 +920,28 @@ void WriteCppReplayIndexFiles(bool compression,
EGLint drawSurfaceHeight,
size_t readBufferSize,
const gl::AttribArray<size_t> &clientArraySizes,
const HasResourceTypeMap &hasResourceType)
const HasResourceTypeMap &hasResourceType,
bool serializeStateEnabled,
std::vector<uint8_t> &binaryData)
{
gl::ContextID contextId = context->id();
size_t serializedContextLength = 0;
size_t serializedContextOffset = 0;
if (serializeStateEnabled)
{
gl::BinaryOutputStream serializedContextData{};
if (SerializeContext(&serializedContextData, const_cast<gl::Context *>(context)) !=
Result::Continue)
{
return;
}
// store serialized context behind capture replay data
serializedContextLength = serializedContextData.length();
serializedContextOffset = rx::roundUp(binaryData.size(), kBinaryAlignment);
binaryData.resize(serializedContextOffset + serializedContextLength);
memcpy(binaryData.data() + serializedContextOffset, serializedContextData.data(),
serializedContextLength);
}
size_t maxClientArraySize = MaxClientArraySize(clientArraySizes);
std::stringstream header;
......@@ -927,8 +949,7 @@ void WriteCppReplayIndexFiles(bool compression,
header << "#pragma once\n";
header << "\n";
header << "#include \"util/gles_loader_autogen.h\"\n";
header << "#include \"util/egl_loader_autogen.h\"\n";
header << "#include \"util/util_gl.h\"\n";
header << "\n";
header << "#include <cstdint>\n";
header << "#include <cstdio>\n";
......@@ -967,6 +988,11 @@ void WriteCppReplayIndexFiles(bool compression,
header << "void ReplayContext" << static_cast<int>(contextId)
<< "Frame(uint32_t frameIndex);\n";
header << "void ResetContext" << static_cast<int>(contextId) << "Replay();\n";
if (serializeStateEnabled)
{
header << "std::vector<uint8_t> GetSerializedContextState" << static_cast<int>(contextId)
<< "Data();\n";
}
header << "\n";
header << "using FramebufferChangeCallback = void(*)(void *userData, GLenum target, GLuint "
"framebuffer);\n";
......@@ -1098,6 +1124,21 @@ void WriteCppReplayIndexFiles(bool compression,
source << " }\n";
source << "}\n";
source << "\n";
if (serializeStateEnabled)
{
source << "std::vector<uint8_t> GetSerializedContextState" << static_cast<int>(contextId)
<< "Data()\n";
source << "{\n";
source << " std::vector<uint8_t> serializedContextData(" << serializedContextLength
<< ");\n";
source << " memcpy(serializedContextData.data(), &gBinaryData["
<< serializedContextOffset << "], " << serializedContextLength << ");\n";
source << " return serializedContextData;\n";
source << "}\n";
source << "\n";
}
source << "void SetBinaryDataDecompressCallback(DecompressCallback callback)\n";
source << "{\n";
source << " gDecompressCallback = callback;\n";
......@@ -3145,6 +3186,7 @@ ReplayContext::~ReplayContext() {}
FrameCapture::FrameCapture()
: mEnabled(true),
mSerializeStateEnabled(false),
mCompression(true),
mClientVertexArrayMap{},
mFrameIndex(0),
......@@ -3206,6 +3248,12 @@ FrameCapture::FrameCapture()
{
mCompression = false;
}
std::string serializeStateEnabledFromEnv =
angle::GetEnvironmentVar(kSerializeStateEnabledVarName);
if (serializeStateEnabledFromEnv == "1")
{
mSerializeStateEnabled = true;
}
}
FrameCapture::~FrameCapture() = default;
......@@ -3863,10 +3911,10 @@ void FrameCapture::onEndFrame(const gl::Context *context)
// Save the index files after the last frame.
if (mFrameIndex == mFrameEnd)
{
WriteCppReplayIndexFiles(mCompression, mOutDirectory, context->id(), mCaptureLabel,
WriteCppReplayIndexFiles(mCompression, mOutDirectory, context, mCaptureLabel,
mFrameStart, mFrameEnd, mDrawSurfaceWidth, mDrawSurfaceHeight,
mReadBufferSize, mClientArraySizes, mHasResourceType);
mReadBufferSize, mClientArraySizes, mHasResourceType,
mSerializeStateEnabled, mBinaryData);
if (!mBinaryData.empty())
{
SaveBinaryData(mCompression, mOutDirectory, context->id(), mCaptureLabel,
......
......@@ -311,6 +311,7 @@ class FrameCapture final : angle::NonCopyable
std::vector<uint8_t> mBinaryData;
bool mEnabled = false;
bool mSerializeStateEnabled;
std::string mOutDirectory;
std::string mCaptureLabel;
bool mCompression;
......
......@@ -357,7 +357,7 @@ FramebufferState::FramebufferState(const Caps &caps, FramebufferID id, ContextID
FramebufferState::~FramebufferState() {}
const std::string &FramebufferState::getLabel()
const std::string &FramebufferState::getLabel() const
{
return mLabel;
}
......
......@@ -65,7 +65,7 @@ class FramebufferState final : angle::NonCopyable
FramebufferState(const Caps &caps, FramebufferID id, ContextID owningContextID);
~FramebufferState();
const std::string &getLabel();
const std::string &getLabel() const;
size_t getReadIndex() const;
const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const;
......@@ -248,6 +248,8 @@ class Framebuffer final : public angle::ObserverInterface,
return mState.mColorAttachments;
}
const FramebufferState &getState() const { return mState; }
const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const;
bool isMultiview() const;
bool readDisallowedByMultiview() const;
......
......@@ -158,8 +158,6 @@ void Surface::postSwap(const gl::Context *context)
mInitState = gl::InitState::MayNeedInit;
onStateChange(angle::SubjectMessage::SubjectChanged);
}
context->onPostSwap();
}
Error Surface::initialize(const Display *display)
......@@ -278,6 +276,7 @@ EGLint Surface::getType() const
Error Surface::swap(const gl::Context *context)
{
ANGLE_TRACE_EVENT0("gpu.angle", "egl::Surface::swap");
context->onPreSwap();
context->getState().getOverlay()->onSwap();
......
//
// 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.
//
// frame_capture_utils.cpp:
// ANGLE frame capture util implementation.
//
#include "libANGLE/frame_capture_utils.h"
#include "common/MemoryBuffer.h"
#include "common/angleutils.h"
#include "libANGLE/BinaryStream.h"
#include "libANGLE/Context.h"
#include "libANGLE/Framebuffer.h"
#define ANGLE_STATIC_ASSERT_SIZE(className, classSize) \
static_assert( \
sizeof(className) == classSize, \
ANGLE_STRINGIFY(className) " class has changed. Please " \
"update its serialize method in " __FILE__);
namespace angle
{
Result ReadPixelsFromAttachment(gl::Context *context,
gl::Framebuffer *framebuffer,
const gl::FramebufferAttachment &framebufferAttachment,
ScratchBuffer *scratchBuffer,
MemoryBuffer **pixels)
{
gl::Extents extents = framebufferAttachment.getSize();
gl::Format format = framebufferAttachment.getFormat();
ANGLE_CHECK_GL_ALLOC(
context,
scratchBuffer->get(format.info->pixelBytes * extents.width * extents.height, pixels));
ANGLE_TRY(framebuffer->readPixels(context, gl::Rectangle{0, 0, extents.width, extents.height},
format.info->format, format.info->type, gl::PixelPackState{},
nullptr, (*pixels)->data()));
return Result::Continue;
}
Result SerializeContext(gl::BinaryOutputStream *bos, gl::Context *context)
{
const gl::FramebufferManager &framebufferManager =
context->getState().getFramebufferManagerForCapture();
for (const auto &framebuffer : framebufferManager)
{
gl::Framebuffer *framebufferPtr = framebuffer.second;
ANGLE_TRY(SerializeFramebuffer(context, bos, framebufferPtr));
}
return Result::Continue;
}
Result SerializeFramebuffer(gl::Context *context,
gl::BinaryOutputStream *bos,
gl::Framebuffer *framebuffer)
{
#if defined(ANGLE_IS_64_BIT_CPU) && (defined(ANGLE_IS_WIN) || defined(ANGLE_IS_LINUX))
constexpr size_t kSizeOfGlFramebuffer = 744;
ANGLE_STATIC_ASSERT_SIZE(gl::Framebuffer, kSizeOfGlFramebuffer)
#endif
return SerializeFramebufferState(context, bos, framebuffer, framebuffer->getState());
}
Result SerializeFramebufferState(gl::Context *context,
gl::BinaryOutputStream *bos,
gl::Framebuffer *framebuffer,
const gl::FramebufferState &framebufferState)
{
#if defined(ANGLE_IS_64_BIT_CPU) && (defined(ANGLE_IS_WIN) || defined(ANGLE_IS_LINUX))
constexpr size_t kSizeOfGlFramebufferState = 488;
ANGLE_STATIC_ASSERT_SIZE(gl::FramebufferState, kSizeOfGlFramebufferState)
#endif
bos->writeInt(framebufferState.id().value);
bos->writeString(framebufferState.getLabel());
bos->writeIntVector(framebufferState.getDrawBufferStates());
bos->writeInt(framebufferState.getReadBufferState());
bos->writeInt(framebufferState.getDefaultWidth());
bos->writeInt(framebufferState.getDefaultHeight());
bos->writeInt(framebufferState.getDefaultSamples());
bos->writeInt(framebufferState.getDefaultFixedSampleLocations());
bos->writeInt(framebufferState.getDefaultLayers());
context->bindFramebuffer(GL_FRAMEBUFFER, framebufferState.id());
ANGLE_TRY(framebuffer->syncState(context, GL_FRAMEBUFFER));
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,
colorAttachment));
}
}
scratchBuffer.clear();
return Result::Continue;
}
Result SerializeFramebufferAttachment(gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer,
const gl::FramebufferAttachment &framebufferAttachment)
{
#if defined(ANGLE_IS_64_BIT_CPU) && (defined(ANGLE_IS_WIN) || defined(ANGLE_IS_LINUX))
constexpr size_t kSizeOfGlFramebufferAttachment = 48;
ANGLE_STATIC_ASSERT_SIZE(gl::FramebufferAttachment, kSizeOfGlFramebufferAttachment)
#endif
bos->writeInt(framebufferAttachment.type());
// serialize target variable
bos->writeInt(framebufferAttachment.getBinding());
if (framebufferAttachment.type() == GL_TEXTURE)
{
SerializeImageIndex(bos, framebufferAttachment.getTextureImageIndex());
}
bos->writeInt(framebufferAttachment.getNumViews());
bos->writeInt(framebufferAttachment.isMultiview());
bos->writeInt(framebufferAttachment.getBaseViewIndex());
bos->writeInt(framebufferAttachment.getRenderToTextureSamples());
MemoryBuffer *pixelsPtr = nullptr;
context->readBuffer(framebufferAttachment.getBinding());
ANGLE_TRY(framebuffer->syncState(context, GL_FRAMEBUFFER));
ANGLE_TRY(ReadPixelsFromAttachment(context, framebuffer, framebufferAttachment, scratchBuffer,
&pixelsPtr));
bos->writeBytes(pixelsPtr->data(), pixelsPtr->size());
return Result::Continue;
}
void SerializeImageIndex(gl::BinaryOutputStream *bos, const gl::ImageIndex &imageIndex)
{
// size of ImageIndex on 64-bit and 86-bit systems are the same
constexpr size_t kSizeOfGlImageIndex = 16;
ANGLE_STATIC_ASSERT_SIZE(gl::ImageIndex, kSizeOfGlImageIndex)
bos->writeEnum(imageIndex.getType());
bos->writeInt(imageIndex.getLevelIndex());
bos->writeInt(imageIndex.getLayerIndex());
bos->writeInt(imageIndex.getLayerCount());
}
} // namespace angle
//
// 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.
//
// frame_capture_utils.h:
// ANGLE frame capture utils interface.
//
#ifndef FRAME_CAPTURE_UTILS_H_
#define FRAME_CAPTURE_UTILS_H_
#include <vector>
#include "libANGLE/Error.h"
namespace gl
{
class BinaryOutputStream;
class Context;
class Framebuffer;
class FramebufferAttachment;
class FramebufferState;
class ImageIndex;
} // namespace gl
typedef unsigned int GLenum;
namespace angle
{
class MemoryBuffer;
class ScratchBuffer;
Result SerializeContext(gl::BinaryOutputStream *bos, gl::Context *context);
Result SerializeFramebuffer(gl::Context *context,
gl::BinaryOutputStream *bos,
gl::Framebuffer *framebuffer);
Result SerializeFramebufferState(gl::Context *context,
gl::BinaryOutputStream *bos,
gl::Framebuffer *framebuffer,
const gl::FramebufferState &framebufferState);
Result SerializeFramebufferAttachment(gl::Context *context,
gl::BinaryOutputStream *bos,
ScratchBuffer *scratchBuffer,
gl::Framebuffer *framebuffer,
const gl::FramebufferAttachment &framebufferAttachment);
void SerializeImageIndex(gl::BinaryOutputStream *bos, const gl::ImageIndex &imageIndex);
} // namespace angle
#endif // FRAME_CAPTURE_UTILS_H_
......@@ -913,6 +913,8 @@ libangle_capture_sources = [
"src/libANGLE/capture_gles_ext_autogen.cpp",
"src/libANGLE/capture_gles_ext_params.cpp",
"src/libANGLE/frame_capture_replay_autogen.cpp",
"src/libANGLE/frame_capture_utils.cpp",
"src/libANGLE/frame_capture_utils.h",
"src/libANGLE/frame_capture_utils_autogen.cpp",
"src/libANGLE/gl_enum_utils.cpp",
"src/libANGLE/gl_enum_utils_autogen.cpp",
......
......@@ -128,11 +128,15 @@ class Test():
return (e.returncode, e.output)
def BuildReplay(self, build_dir, replay_exec):
RunGnGen(build_dir, [("use_goma", self.use_goma),
("angle_with_capture_by_default", "true"),
("angle_build_capture_replay_tests", "true")])
RunAutoninja(build_dir, replay_exec)
Logger.log("Built replay of " + self.full_test_name)
try:
RunGnGen(build_dir, [("use_goma", self.use_goma),
("angle_with_capture_by_default", "true"),
("angle_build_capture_replay_tests", "true")])
RunAutoninja(build_dir, replay_exec)
Logger.log("Built replay of " + self.full_test_name)
return (0, "Built replay of " + self.full_test_name)
except subprocess.CalledProcessError as e:
return (e.returncode, e.output)
def RunReplay(self, build_dir, replay_exec):
try:
......@@ -149,19 +153,27 @@ class Test():
def ClearFolderContent(path):
all_files = []
for f in os.listdir(path):
if os.path.isfile(path + "/" + f) and f.startswith("angle_capture_context"):
os.remove(path + "/" + f)
if os.path.isfile(os.path.join(path, f)) and f.startswith("angle_capture_context"):
os.remove(os.path.join(path, f))
def CanRunReplay(path):
files = [
required_trace_files = {
"angle_capture_context1.h", "angle_capture_context1.cpp",
"angle_capture_context1_files.txt", "angle_capture_context1_frame000.cpp"
]
for file in files:
if not os.path.isfile(path + "/" + file):
}
binary_data_file = "angle_capture_context1.angledata.gz"
required_trace_files_count = 0
for f in os.listdir(path):
if f in required_trace_files:
required_trace_files_count += 1
elif os.path.isfile(os.path.join(path, f)) and f != binary_data_file and \
f.startswith("angle_capture_context"):
# if trace_files of another context exists, then the test creates multiple contexts
# or capture multiple frames
return False
return True
# angle_capture_context1.angledata.gz can be missing
return required_trace_files_count == len(required_trace_files)
def SetCWDToAngleFolder():
......@@ -179,7 +191,8 @@ def main(build_dir, verbose, use_goma, gtest_filter, test_exec):
if not os.path.isdir(capture_out_dir):
os.mkdir(capture_out_dir)
environment_vars = [("ANGLE_CAPTURE_FRAME_END", "0"),
("ANGLE_CAPTURE_OUT_DIR", capture_out_dir)]
("ANGLE_CAPTURE_OUT_DIR", capture_out_dir),
("ANGLE_CAPTURE_SERIALIZE_STATE", "1")]
replay_exec = "capture_replay_tests"
if platform == "win32":
test_exec += ".exe"
......@@ -197,29 +210,48 @@ def main(build_dir, verbose, use_goma, gtest_filter, test_exec):
for environment_var in environment_vars:
os.environ[environment_var[0]] = environment_var[1]
passed_count = 0
failed_count = 0
skipped_count = 0
failed_tests = []
for test in all_tests:
if verbose:
print("*" * 30)
ClearFolderContent(capture_out_dir)
os.environ["ANGLE_CAPTURE_ENABLED"] = "1"
run_output = test.Run(build_dir + "/" + test_exec)
if run_output[0] == 0 and CanRunReplay(capture_out_dir):
os.environ["ANGLE_CAPTURE_ENABLED"] = "0"
test.BuildReplay(build_dir, replay_exec)
replay_output = test.RunReplay(build_dir, replay_exec)
if replay_output[0] != 0:
print("Failed: " + test.full_test_name)
print(replay_output[1])
else:
print("Passed: " + test.full_test_name)
else:
if run_output[0] != 0 or not CanRunReplay(capture_out_dir):
print("Skipped: " + test.full_test_name + ". Skipping replay since capture" + \
"didn't produce appropriate files or has crashed")
" didn't produce appropriate files or has crashed")
skipped_count += 1
continue
os.environ["ANGLE_CAPTURE_ENABLED"] = "0"
build_output = test.BuildReplay(build_dir, replay_exec)
if build_output[0] != 0:
print("Skipped: " + test.full_test_name + ". Skipping replay since failing to" + \
" build replay")
skipped_count += 1
continue
replay_output = test.RunReplay(build_dir, replay_exec)
if replay_output[0] != 0:
print("Failed: " + test.full_test_name)
print(replay_output[1])
failed_count += 1
failed_tests.append(test.full_test_name)
else:
print("Passed: " + test.full_test_name)
passed_count += 1
for environment_var in environment_vars:
del os.environ[environment_var[0]]
if os.path.isdir(capture_out_dir):
shutil.rmtree(capture_out_dir)
print("\n\n\n")
print("Passed:", passed_count, "Failed:", failed_count, "Skipped:", skipped_count)
print("Failed tests:")
for failed_test in failed_tests:
print("\t" + failed_test)
if __name__ == "__main__":
......
......@@ -27,12 +27,15 @@ if (angle_build_capture_replay_tests) {
sources =
rebase_path(_trace_sources, ".", "traces") + [ "CaptureReplayTest.cpp" ]
deps = [
"$angle_root:angle_common",
"$angle_root:angle_compression",
"../../../:angle_common",
"../../../util:angle_util",
"../../../util:angle_util_loader_headers",
"$angle_root:libEGL_with_capture_static",
"$angle_root/util:angle_util_static",
]
configs += [
"$angle_root:library_name_config",
"$angle_root:libANGLE_config",
]
configs += [ "../../../:library_name_config" ]
suppressed_configs += [ "$angle_root:constructor_and_destructor_warnings" ]
......
......@@ -8,11 +8,11 @@
//
#include "common/system_utils.h"
#include "libANGLE/Context.h"
#include "libANGLE/frame_capture_utils.h"
#include "util/EGLPlatformParameters.h"
#include "util/EGLWindow.h"
#include "util/OSWindow.h"
#include "util/egl_loader_autogen.h"
#include "util/gles_loader_autogen.h"
#include <stdint.h>
#include <string.h>
......@@ -38,6 +38,10 @@ std::function<void(int)> ReplayContextFrame = reinterpret_cast<void (*)(int)>(
std::function<void()> ResetContextReplay = reinterpret_cast<void (*)()>(
ANGLE_MACRO_CONCAT(ResetContext,
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Replay)));
std::function<std::vector<uint8_t>()> GetSerializedContextStateData =
reinterpret_cast<std::vector<uint8_t> (*)()>(
ANGLE_MACRO_CONCAT(GetSerializedContextState,
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Data)));
class CaptureReplayTest
{
......@@ -113,8 +117,6 @@ class CaptureReplayTest
return -1;
}
angle::LoadGLES(eglGetProcAddress);
int result = 0;
if (!initialize())
......@@ -123,6 +125,18 @@ class CaptureReplayTest
}
draw();
gl::Context *context = static_cast<gl::Context *>(mEGLWindow->getContext());
gl::BinaryOutputStream bos;
if (angle::SerializeContext(&bos, context) != angle::Result::Continue)
{
return -1;
}
bool isEqual = compareSerializedStates(bos);
if (!isEqual)
{
result = -1;
}
swap();
mEGLWindow->destroyGL();
......@@ -132,6 +146,11 @@ class CaptureReplayTest
}
private:
bool compareSerializedStates(const gl::BinaryOutputStream &replaySerializedContextData)
{
return GetSerializedContextStateData() == replaySerializedContextData.getData();
}
uint32_t mWidth;
uint32_t mHeight;
OSWindow *mOSWindow;
......
......@@ -27,6 +27,8 @@
# include "angle_gl.h"
#endif // defined(ANGLE_USE_UTIL_LOADER)
#include <string>
namespace angle
{
inline bool CheckExtensionExists(const char *allExtensions, const std::string &extName)
......
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