end2end_tests: Forward Windows debug messages to stderr
When validation layers are enabled, D3D12 warnings and error messages are logged to the shared DBWIN_BUFFER segment of memory. This CL has makes the test environment watch for new events and logs them to stderr so they show up in the test bot logs. This helps debug problems in the D3D12 backend which previously just crashed with a general Device Lost message. Bug: none Change-Id: I0eaddf9e16303bd65579e85fe6693bd8cdfbd8da Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/26640 Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com> Reviewed-by: Bryan Bernhart <bryan.bernhart@intel.com> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
24b5971b84
commit
f580096468
|
@ -24,6 +24,7 @@
|
|||
#include "dawn_native/DawnNative.h"
|
||||
#include "dawn_wire/WireClient.h"
|
||||
#include "dawn_wire/WireServer.h"
|
||||
#include "utils/PlatformDebugLogger.h"
|
||||
#include "utils/SystemUtils.h"
|
||||
#include "utils/TerribleCommandBuffer.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
@ -35,7 +36,7 @@
|
|||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef DAWN_ENABLE_BACKEND_OPENGL
|
||||
#if defined(DAWN_ENABLE_BACKEND_OPENGL)
|
||||
# include "GLFW/glfw3.h"
|
||||
# include "dawn_native/OpenGLBackend.h"
|
||||
#endif // DAWN_ENABLE_BACKEND_OPENGL
|
||||
|
@ -81,7 +82,7 @@ namespace {
|
|||
|
||||
DawnTestEnvironment* gTestEnv = nullptr;
|
||||
|
||||
} // namespace
|
||||
} // anonymous namespace
|
||||
|
||||
const RGBA8 RGBA8::kZero = RGBA8(0, 0, 0, 0);
|
||||
const RGBA8 RGBA8::kBlack = RGBA8(0, 0, 0, 255);
|
||||
|
@ -186,6 +187,11 @@ void DawnTestEnvironment::SetEnvironment(DawnTestEnvironment* env) {
|
|||
DawnTestEnvironment::DawnTestEnvironment(int argc, char** argv) {
|
||||
ParseArgs(argc, argv);
|
||||
|
||||
if (mEnableBackendValidation) {
|
||||
mPlatformDebugLogger =
|
||||
std::unique_ptr<utils::PlatformDebugLogger>(utils::CreatePlatformDebugLogger());
|
||||
}
|
||||
|
||||
// Create a temporary instance to select available and preferred adapters. This is done before
|
||||
// test instantiation so GetAvailableAdapterTestParamsForBackends can generate test
|
||||
// parameterizations all selected adapters. We drop the instance at the end of this function
|
||||
|
@ -199,6 +205,8 @@ DawnTestEnvironment::DawnTestEnvironment(int argc, char** argv) {
|
|||
PrintTestConfigurationAndAdapterInfo();
|
||||
}
|
||||
|
||||
DawnTestEnvironment::~DawnTestEnvironment() = default;
|
||||
|
||||
void DawnTestEnvironment::ParseArgs(int argc, char** argv) {
|
||||
size_t argLen = 0; // Set when parsing --arg=X arguments
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
|
|
|
@ -155,6 +155,7 @@ BackendTestConfig VulkanBackend(std::initializer_list<const char*> forceEnabledW
|
|||
std::initializer_list<const char*> forceDisabledWorkarounds = {});
|
||||
|
||||
namespace utils {
|
||||
class PlatformDebugLogger;
|
||||
class TerribleCommandBuffer;
|
||||
} // namespace utils
|
||||
|
||||
|
@ -176,7 +177,7 @@ void InitDawnEnd2EndTestEnvironment(int argc, char** argv);
|
|||
class DawnTestEnvironment : public testing::Environment {
|
||||
public:
|
||||
DawnTestEnvironment(int argc, char** argv);
|
||||
~DawnTestEnvironment() override = default;
|
||||
~DawnTestEnvironment() override;
|
||||
|
||||
static void SetEnvironment(DawnTestEnvironment* env);
|
||||
|
||||
|
@ -219,6 +220,8 @@ class DawnTestEnvironment : public testing::Environment {
|
|||
std::string mWireTraceDir;
|
||||
std::vector<dawn_native::DeviceType> mDevicePreferences;
|
||||
std::vector<TestAdapterProperties> mAdapterProperties;
|
||||
|
||||
std::unique_ptr<utils::PlatformDebugLogger> mPlatformDebugLogger;
|
||||
};
|
||||
|
||||
class DawnTestBase {
|
||||
|
|
|
@ -70,6 +70,7 @@ static_library("dawn_utils") {
|
|||
"ComboRenderBundleEncoderDescriptor.h",
|
||||
"ComboRenderPipelineDescriptor.cpp",
|
||||
"ComboRenderPipelineDescriptor.h",
|
||||
"PlatformDebugLogger.h",
|
||||
"SystemUtils.cpp",
|
||||
"SystemUtils.h",
|
||||
"TerribleCommandBuffer.cpp",
|
||||
|
@ -89,6 +90,12 @@ static_library("dawn_utils") {
|
|||
libs = []
|
||||
frameworks = []
|
||||
|
||||
if (is_win) {
|
||||
sources += [ "WindowsDebugLogger.cpp" ]
|
||||
} else {
|
||||
sources += [ "EmptyDebugLogger.cpp" ]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
sources += [ "WindowsTimer.cpp" ]
|
||||
} else if (is_mac) {
|
||||
|
|
|
@ -22,6 +22,7 @@ target_sources(dawn_utils PRIVATE
|
|||
"ComboRenderPipelineDescriptor.h"
|
||||
"GLFWUtils.cpp"
|
||||
"GLFWUtils.h"
|
||||
"PlatformDebugLogger.h"
|
||||
"SystemUtils.cpp"
|
||||
"SystemUtils.h"
|
||||
"TerribleCommandBuffer.cpp"
|
||||
|
@ -42,6 +43,12 @@ target_link_libraries(dawn_utils
|
|||
glfw
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(dawn_utils PRIVATE "WindowsDebugLogger.cpp")
|
||||
else()
|
||||
target_sources(dawn_utils PRIVATE "EmptyDebugLogger.cpp")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(dawn_utils PRIVATE "WindowsTimer.cpp")
|
||||
elseif(APPLE)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "utils/PlatformDebugLogger.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
class EmptyDebugLogger : public PlatformDebugLogger {
|
||||
public:
|
||||
EmptyDebugLogger() = default;
|
||||
~EmptyDebugLogger() override = default;
|
||||
};
|
||||
|
||||
PlatformDebugLogger* CreatePlatformDebugLogger() {
|
||||
return new EmptyDebugLogger();
|
||||
}
|
||||
|
||||
} // namespace utils
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef UTILS_PLATFORMDEBUGLOGGER_H_
|
||||
#define UTILS_PLATFORMDEBUGLOGGER_H_
|
||||
|
||||
namespace utils {
|
||||
|
||||
class PlatformDebugLogger {
|
||||
public:
|
||||
virtual ~PlatformDebugLogger() = default;
|
||||
};
|
||||
|
||||
PlatformDebugLogger* CreatePlatformDebugLogger();
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif // UTILS_PLATFORMDEBUGLOGGER_H_
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "utils/PlatformDebugLogger.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "common/windows_with_undefs.h"
|
||||
|
||||
#include <array>
|
||||
#include <thread>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class WindowsDebugLogger : public PlatformDebugLogger {
|
||||
public:
|
||||
WindowsDebugLogger() : PlatformDebugLogger() {
|
||||
if (IsDebuggerPresent()) {
|
||||
// This condition is true when running inside Visual Studio or some other debugger.
|
||||
// Messages are already printed there so we don't need to do anything.
|
||||
return;
|
||||
}
|
||||
|
||||
mShouldExitHandle = CreateEventA(nullptr, TRUE, FALSE, nullptr);
|
||||
ASSERT(mShouldExitHandle != nullptr);
|
||||
|
||||
mThread = std::thread(
|
||||
[](HANDLE shouldExit) {
|
||||
// https://blogs.msdn.microsoft.com/reiley/2011/07/29/a-debugging-approach-to-outputdebugstring/
|
||||
// for the layout of this struct.
|
||||
struct {
|
||||
DWORD process_id;
|
||||
char data[4096 - sizeof(DWORD)];
|
||||
}* dbWinBuffer = nullptr;
|
||||
|
||||
HANDLE file = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE,
|
||||
0, sizeof(*dbWinBuffer), "DBWIN_BUFFER");
|
||||
ASSERT(file != nullptr);
|
||||
ASSERT(file != INVALID_HANDLE_VALUE);
|
||||
|
||||
dbWinBuffer = static_cast<decltype(dbWinBuffer)>(
|
||||
MapViewOfFile(file, SECTION_MAP_READ, 0, 0, 0));
|
||||
ASSERT(dbWinBuffer != nullptr);
|
||||
|
||||
HANDLE dbWinBufferReady =
|
||||
CreateEventA(nullptr, FALSE, FALSE, "DBWIN_BUFFER_READY");
|
||||
ASSERT(dbWinBufferReady != nullptr);
|
||||
|
||||
HANDLE dbWinDataReady = CreateEventA(nullptr, FALSE, FALSE, "DBWIN_DATA_READY");
|
||||
ASSERT(dbWinDataReady != nullptr);
|
||||
|
||||
std::array<HANDLE, 2> waitHandles = {shouldExit, dbWinDataReady};
|
||||
while (true) {
|
||||
SetEvent(dbWinBufferReady);
|
||||
DWORD wait = WaitForMultipleObjects(waitHandles.size(), waitHandles.data(),
|
||||
FALSE, INFINITE);
|
||||
if (wait == WAIT_OBJECT_0) {
|
||||
break;
|
||||
}
|
||||
ASSERT(wait == WAIT_OBJECT_0 + 1);
|
||||
fprintf(stderr, "%.*s\n", static_cast<int>(sizeof(dbWinBuffer->data)),
|
||||
dbWinBuffer->data);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
CloseHandle(dbWinDataReady);
|
||||
CloseHandle(dbWinBufferReady);
|
||||
UnmapViewOfFile(dbWinBuffer);
|
||||
CloseHandle(file);
|
||||
},
|
||||
mShouldExitHandle);
|
||||
}
|
||||
|
||||
~WindowsDebugLogger() override {
|
||||
if (mShouldExitHandle != nullptr) {
|
||||
ASSERT(SetEvent(mShouldExitHandle));
|
||||
CloseHandle(mShouldExitHandle);
|
||||
}
|
||||
|
||||
if (mThread.joinable()) {
|
||||
mThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::thread mThread;
|
||||
HANDLE mShouldExitHandle = INVALID_HANDLE_VALUE;
|
||||
};
|
||||
|
||||
PlatformDebugLogger* CreatePlatformDebugLogger() {
|
||||
return new WindowsDebugLogger();
|
||||
}
|
||||
|
||||
} // namespace utils
|
Loading…
Reference in New Issue