mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-11 00:56:37 +00:00
Merge pull request #3804 from unknownbrackets/headless
Implement --compare in headless
This commit is contained in:
commit
39c640d3ab
@ -24,6 +24,7 @@
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
|
||||
#include "sceKernel.h"
|
||||
@ -1089,6 +1090,8 @@ int __AtracSetContext(Atrac *atrac)
|
||||
}
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
InitFFmpeg();
|
||||
|
||||
u8* tempbuf = (u8*)av_malloc(atrac->atracBufSize);
|
||||
|
||||
atrac->pFormatCtx = avformat_alloc_context();
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "Core/HLE/sceMp3.h"
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
#include "Core/Reporting.h"
|
||||
#include "../HW/MediaEngine.h"
|
||||
#include "Core/HW/MediaEngine.h"
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
#ifndef PRId64
|
||||
@ -337,6 +337,8 @@ int sceMp3Init(u32 mp3) {
|
||||
ctx->mp3Version = ((header >> 19) & 0x3);
|
||||
|
||||
#ifdef USE_FFMPEG
|
||||
InitFFmpeg();
|
||||
|
||||
u8* avio_buffer = static_cast<u8*>(av_malloc(ctx->mp3BufSize));
|
||||
ctx->avio_context = avio_alloc_context(avio_buffer, ctx->mp3BufSize, 0, ctx, readFunc, NULL, NULL);
|
||||
ctx->avformat_context = avformat_alloc_context();
|
||||
|
@ -83,6 +83,23 @@ static int getPixelFormatBytes(int pspFormat)
|
||||
}
|
||||
}
|
||||
|
||||
void ffmpeg_logger(void *, int, const char *format, va_list va_args) {
|
||||
char tmp[1024];
|
||||
vsprintf(tmp, format, va_args);
|
||||
INFO_LOG(ME, "%s", tmp);
|
||||
}
|
||||
|
||||
bool InitFFmpeg() {
|
||||
#ifdef _DEBUG
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
#else
|
||||
av_log_set_level(AV_LOG_ERROR);
|
||||
#endif
|
||||
av_log_set_callback(&ffmpeg_logger);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MediaEngine::MediaEngine(): m_pdata(0) {
|
||||
m_pFormatCtx = 0;
|
||||
m_pCodecCtx = 0;
|
||||
@ -192,21 +209,10 @@ int _MpegReadbuffer(void *opaque, uint8_t *buf, int buf_size)
|
||||
return size;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void ffmpeg_logger(void *, int, const char *format, va_list va_args) {
|
||||
char tmp[1024];
|
||||
vsprintf(tmp, format, va_args);
|
||||
INFO_LOG(ME, "%s", tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool MediaEngine::openContext() {
|
||||
#ifdef USE_FFMPEG
|
||||
InitFFmpeg();
|
||||
|
||||
#ifdef _DEBUG
|
||||
av_log_set_level(AV_LOG_VERBOSE);
|
||||
av_log_set_callback(&ffmpeg_logger);
|
||||
#endif
|
||||
if (m_pFormatCtx || !m_pdata)
|
||||
return false;
|
||||
m_mpegheaderReadPos = 0;
|
||||
|
@ -41,6 +41,8 @@ inline s64 getMpegTimeStamp(u8* buf) {
|
||||
| ((s64)buf[1] << 32) | ((s64)buf[0] << 36);
|
||||
}
|
||||
|
||||
bool InitFFmpeg();
|
||||
|
||||
class MediaEngine
|
||||
{
|
||||
public:
|
||||
|
@ -15,22 +15,182 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Compare.h"
|
||||
#include "FileUtil.h"
|
||||
#include "headless/Compare.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
bool CompareOutput(const std::string bootFilename)
|
||||
bool teamCityMode = false;
|
||||
std::string teamCityName = "";
|
||||
|
||||
void TeamCityPrint(const char *fmt, ...)
|
||||
{
|
||||
std::string expect_filename = bootFilename.substr(bootFilename.length() - 4) + ".expected";
|
||||
if (File::Exists(expect_filename))
|
||||
{
|
||||
// TODO: Do the compare here
|
||||
if (!teamCityMode)
|
||||
return;
|
||||
|
||||
const int TEMP_BUFFER_SIZE = 32768;
|
||||
char temp[TEMP_BUFFER_SIZE];
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(temp, TEMP_BUFFER_SIZE - 1, fmt, args);
|
||||
temp[TEMP_BUFFER_SIZE - 1] = '\0';
|
||||
va_end(args);
|
||||
|
||||
printf("%s", temp);
|
||||
}
|
||||
|
||||
struct BufferedLineReader {
|
||||
const static int MAX_BUFFER = 5;
|
||||
const static int TEMP_BUFFER_SIZE = 32768;
|
||||
|
||||
BufferedLineReader(const std::string &data) : valid_(0), data_(data), pos_(0) {
|
||||
}
|
||||
|
||||
void Fill() {
|
||||
while (valid_ < MAX_BUFFER && HasLines()) {
|
||||
buffer_[valid_++] = ReadLine();
|
||||
}
|
||||
}
|
||||
|
||||
const std::string Peek(int pos) {
|
||||
if (pos >= valid_) {
|
||||
Fill();
|
||||
}
|
||||
if (pos >= valid_) {
|
||||
return "";
|
||||
}
|
||||
return buffer_[pos];
|
||||
}
|
||||
|
||||
void Skip(int count) {
|
||||
if (count > valid_) {
|
||||
count = valid_;
|
||||
}
|
||||
valid_ -= count;
|
||||
for (int i = 0; i < valid_; ++i) {
|
||||
buffer_[i] = buffer_[i + count];
|
||||
}
|
||||
Fill();
|
||||
}
|
||||
|
||||
const std::string Consume() {
|
||||
const std::string result = Peek(0);
|
||||
Skip(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual bool HasLines() {
|
||||
return pos_ != data_.npos;
|
||||
}
|
||||
|
||||
bool Compare(BufferedLineReader &other) {
|
||||
if (Peek(0) != other.Peek(0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Skip(1);
|
||||
other.Skip(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
BufferedLineReader() : valid_(0) {
|
||||
}
|
||||
|
||||
virtual std::string ReadLine() {
|
||||
size_t next = data_.find('\n', pos_);
|
||||
if (next == data_.npos) {
|
||||
std::string result = data_.substr(pos_);
|
||||
pos_ = next;
|
||||
return result;
|
||||
} else {
|
||||
std::string result = data_.substr(pos_, next - pos_);
|
||||
pos_ = next + 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
int valid_;
|
||||
std::string buffer_[MAX_BUFFER];
|
||||
const std::string data_;
|
||||
size_t pos_;
|
||||
};
|
||||
|
||||
struct BufferedLineReaderFile : public BufferedLineReader {
|
||||
BufferedLineReaderFile(std::ifstream &in) : BufferedLineReader(), in_(in) {
|
||||
}
|
||||
|
||||
virtual bool HasLines() {
|
||||
return !in_.eof();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::string ReadLine() {
|
||||
char temp[TEMP_BUFFER_SIZE];
|
||||
in_.getline(temp, TEMP_BUFFER_SIZE);
|
||||
return temp;
|
||||
}
|
||||
|
||||
std::ifstream &in_;
|
||||
};
|
||||
|
||||
bool CompareOutput(const std::string &bootFilename, const std::string &output)
|
||||
{
|
||||
std::string expect_filename = bootFilename.substr(0, bootFilename.length() - 4) + ".expected";
|
||||
std::ifstream in;
|
||||
in.open(expect_filename.c_str(), std::ios::in);
|
||||
if (!in.fail())
|
||||
{
|
||||
BufferedLineReaderFile expected(in);
|
||||
BufferedLineReader actual(output);
|
||||
|
||||
bool failed = false;
|
||||
while (expected.HasLines())
|
||||
{
|
||||
if (expected.Compare(actual))
|
||||
continue;
|
||||
|
||||
if (!failed)
|
||||
{
|
||||
TeamCityPrint("##teamcity[testFailed name='%s' message='Output different from expected file']\n", teamCityName.c_str());
|
||||
failed = true;
|
||||
}
|
||||
|
||||
// This is a really dirt simple comparing algorithm.
|
||||
|
||||
// Perhaps it was an extra line?
|
||||
if (expected.Peek(0) == actual.Peek(1))
|
||||
printf("+ %s\n", actual.Consume().c_str());
|
||||
// A single missing line?
|
||||
else if (expected.Peek(1) == actual.Peek(0))
|
||||
printf("- %s\n", expected.Consume().c_str());
|
||||
else
|
||||
{
|
||||
printf("O %s\n", actual.Consume().c_str());
|
||||
printf("E %s\n", expected.Consume().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
while (actual.HasLines())
|
||||
{
|
||||
// If it's a blank line, this will pass.
|
||||
if (actual.Compare(expected))
|
||||
continue;
|
||||
|
||||
printf("+ %s\n", actual.Consume().c_str());
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Expectation file %s not found", expect_filename.c_str());
|
||||
fprintf(stderr, "Expectation file %s not found\n", expect_filename.c_str());
|
||||
TeamCityPrint("##teamcity[testIgnored name='%s' message='Expects file missing']\n", teamCityName.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -19,5 +19,9 @@
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
bool CompareOutput(std::string bootFilename);
|
||||
extern bool teamCityMode;
|
||||
extern std::string teamCityName;
|
||||
void TeamCityPrint(const char *fmt, ...);
|
||||
|
||||
bool CompareOutput(const std::string &bootFilename, const std::string &output);
|
||||
double CompareScreenshot(const u8 *pixels, int w, int h, int stride, const std::string screenshotFilename, std::string &error);
|
@ -2,7 +2,9 @@
|
||||
// See headless.txt.
|
||||
// To build on non-windows systems, just run CMake in the SDL directory, it will build both a normal ppsspp and the headless version.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Core.h"
|
||||
@ -14,6 +16,7 @@
|
||||
#include "LogManager.h"
|
||||
#include "base/NativeApp.h"
|
||||
#include "input/input_state.h"
|
||||
#include "base/timeutil.h"
|
||||
|
||||
#include "Compare.h"
|
||||
#include "StubHost.h"
|
||||
@ -84,6 +87,7 @@ void printUsage(const char *progname, const char *reason)
|
||||
fprintf(stderr, " options: gles, software, directx9\n");
|
||||
fprintf(stderr, " --screenshot=FILE compare against a screenshot\n");
|
||||
}
|
||||
fprintf(stderr, " --timeout=SECONDS abort test it if takes longer than SECONDS\n");
|
||||
|
||||
fprintf(stderr, " -i use the interpreter\n");
|
||||
fprintf(stderr, " -j use jit (default)\n");
|
||||
@ -102,6 +106,27 @@ static HeadlessHost * getHost(GPUCore gpuCore) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string ChopFront(std::string s, std::string front)
|
||||
{
|
||||
if (s.size() >= front.size())
|
||||
{
|
||||
if (s.substr(0, front.size()) == front)
|
||||
return s.substr(front.size());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string ChopEnd(std::string s, std::string end)
|
||||
{
|
||||
if (s.size() >= end.size())
|
||||
{
|
||||
size_t endpos = s.size() - end.size();
|
||||
if (s.substr(endpos) == end)
|
||||
return s.substr(0, endpos);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
bool fullLog = false;
|
||||
@ -113,6 +138,7 @@ int main(int argc, const char* argv[])
|
||||
const char *mountIso = 0;
|
||||
const char *screenshotFilename = 0;
|
||||
bool readMount = false;
|
||||
double timeout = -1.0;
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
@ -154,6 +180,10 @@ int main(int argc, const char* argv[])
|
||||
gpuCore = GPU_GLES;
|
||||
else if (!strncmp(argv[i], "--screenshot=", strlen("--screenshot=")) && strlen(argv[i]) > strlen("--screenshot="))
|
||||
screenshotFilename = argv[i] + strlen("--screenshot=");
|
||||
else if (!strncmp(argv[i], "--timeout=", strlen("--timeout=")) && strlen(argv[i]) > strlen("--timeout="))
|
||||
timeout = strtod(argv[i] + strlen("--timeout="), NULL);
|
||||
else if (!strcmp(argv[i], "--teamcity"))
|
||||
teamCityMode = true;
|
||||
else if (bootFilename == 0)
|
||||
bootFilename = argv[i];
|
||||
else
|
||||
@ -199,6 +229,8 @@ int main(int argc, const char* argv[])
|
||||
logman->AddListener(type, printfLogger);
|
||||
}
|
||||
|
||||
std::string output;
|
||||
|
||||
CoreParameter coreParameter;
|
||||
coreParameter.cpuCore = useJit ? CPU_JIT : CPU_INTERPRETER;
|
||||
coreParameter.gpuCore = glWorking ? gpuCore : GPU_NULL;
|
||||
@ -207,7 +239,9 @@ int main(int argc, const char* argv[])
|
||||
coreParameter.mountIso = mountIso ? mountIso : "";
|
||||
coreParameter.startPaused = false;
|
||||
coreParameter.enableDebugging = false;
|
||||
coreParameter.printfEmuLog = true;
|
||||
coreParameter.printfEmuLog = !autoCompare;
|
||||
if (autoCompare)
|
||||
coreParameter.collectEmuLog = &output;
|
||||
coreParameter.headLess = true;
|
||||
coreParameter.renderWidth = 480;
|
||||
coreParameter.renderHeight = 272;
|
||||
@ -249,17 +283,29 @@ int main(int argc, const char* argv[])
|
||||
g_Config.flashDirectory = g_Config.memCardDirectory+"/flash/";
|
||||
#endif
|
||||
|
||||
if (teamCityMode) {
|
||||
// Kinda ugly, trying to guesstimate the test name from filename...
|
||||
teamCityName = ChopEnd(ChopFront(ChopFront(bootFilename, "tests/"), "pspautotests/tests/"), ".prx");
|
||||
}
|
||||
|
||||
if (!PSP_Init(coreParameter, &error_string)) {
|
||||
fprintf(stderr, "Failed to start %s. Error: %s\n", coreParameter.fileToStart.c_str(), error_string.c_str());
|
||||
printf("TESTERROR\n");
|
||||
TeamCityPrint("##teamcity[testIgnored name='%s' message='PRX/ELF missing']\n", teamCityName.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
TeamCityPrint("##teamcity[testStarted name='%s' captureStandardOutput='true']\n", teamCityName.c_str());
|
||||
|
||||
host->BootDone();
|
||||
|
||||
if (screenshotFilename != 0)
|
||||
headlessHost->SetComparisonScreenshot(screenshotFilename);
|
||||
|
||||
time_update();
|
||||
bool doCompare = true;
|
||||
double deadline = timeout < 0.0 ? std::numeric_limits<float>::infinity() : time_now() + timeout;
|
||||
|
||||
coreState = CORE_RUNNING;
|
||||
while (coreState == CORE_RUNNING)
|
||||
{
|
||||
@ -271,17 +317,31 @@ int main(int argc, const char* argv[])
|
||||
coreState = CORE_RUNNING;
|
||||
headlessHost->SwapBuffers();
|
||||
}
|
||||
time_update();
|
||||
if (time_now() > deadline) {
|
||||
// Don't compare, print the output at least up to this point, and bail.
|
||||
printf("%s", output.c_str());
|
||||
doCompare = false;
|
||||
|
||||
host->SendDebugOutput("TIMEOUT\n");
|
||||
TeamCityPrint("##teamcity[testFailed name='%s' message='Test timeout']\n", teamCityName.c_str());
|
||||
Core_Stop();
|
||||
}
|
||||
}
|
||||
|
||||
host->ShutdownGL();
|
||||
PSP_Shutdown();
|
||||
|
||||
headlessHost->FlushDebugOutput();
|
||||
|
||||
delete host;
|
||||
host = NULL;
|
||||
headlessHost = NULL;
|
||||
|
||||
if (autoCompare)
|
||||
CompareOutput(bootFilename);
|
||||
if (autoCompare && doCompare)
|
||||
CompareOutput(bootFilename, output);
|
||||
|
||||
TeamCityPrint("##teamcity[testFinished name='%s']\n", teamCityName.c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -46,11 +46,29 @@ public:
|
||||
virtual bool IsDebuggingEnabled() {return false;}
|
||||
virtual bool AttemptLoadSymbolMap() {return false;}
|
||||
|
||||
virtual void SendDebugOutput(const std::string &output) { fwrite(output.data(), sizeof(char), output.length(), stdout); }
|
||||
virtual void SendDebugOutput(const std::string &output) {
|
||||
if (output.find('\n') != output.npos) {
|
||||
DoFlushDebugOutput();
|
||||
fwrite(output.data(), sizeof(char), output.length(), stdout);
|
||||
} else {
|
||||
debugOutputBuffer_ += output;
|
||||
}
|
||||
}
|
||||
virtual void FlushDebugOutput() {
|
||||
DoFlushDebugOutput();
|
||||
}
|
||||
inline void DoFlushDebugOutput() {
|
||||
if (!debugOutputBuffer_.empty()) {
|
||||
fwrite(debugOutputBuffer_.data(), sizeof(char), debugOutputBuffer_.length(), stdout);
|
||||
debugOutputBuffer_.clear();
|
||||
}
|
||||
}
|
||||
virtual void SetComparisonScreenshot(const std::string &filename) {}
|
||||
|
||||
|
||||
// Unique for HeadlessHost
|
||||
virtual void SwapBuffers() {}
|
||||
|
||||
protected:
|
||||
std::string debugOutputBuffer_;
|
||||
};
|
@ -22,6 +22,9 @@
|
||||
#include "Common/CommonWindows.h"
|
||||
#include <io.h>
|
||||
|
||||
#include "Core/CoreParameter.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "gfx_es2/gl_state.h"
|
||||
#include "gfx/gl_common.h"
|
||||
@ -72,10 +75,6 @@ void SetVSync(int value)
|
||||
|
||||
void WindowsHeadlessHost::LoadNativeAssets()
|
||||
{
|
||||
// Native is kinda talkative, but that's annoying in our case.
|
||||
out = _fdopen(_dup(_fileno(stdout)), "wt");
|
||||
freopen("NUL", "wt", stdout);
|
||||
|
||||
VFSRegister("", new DirectoryAssetReader("assets/"));
|
||||
VFSRegister("", new DirectoryAssetReader(""));
|
||||
VFSRegister("", new DirectoryAssetReader("../"));
|
||||
@ -83,16 +82,24 @@ void WindowsHeadlessHost::LoadNativeAssets()
|
||||
VFSRegister("", new DirectoryAssetReader("../Windows/"));
|
||||
|
||||
gl_lost_manager_init();
|
||||
|
||||
// See SendDebugOutput() for how things get back on track.
|
||||
}
|
||||
|
||||
void WindowsHeadlessHost::SendDebugOutput(const std::string &output)
|
||||
{
|
||||
fwrite(output.data(), sizeof(char), output.length(), out);
|
||||
fwrite(output.data(), sizeof(char), output.length(), stdout);
|
||||
OutputDebugStringUTF8(output.c_str());
|
||||
}
|
||||
|
||||
void WindowsHeadlessHost::SendOrCollectDebugOutput(const std::string &data)
|
||||
{
|
||||
if (PSP_CoreParameter().printfEmuLog)
|
||||
SendDebugOutput(data);
|
||||
else if (PSP_CoreParameter().collectEmuLog)
|
||||
*PSP_CoreParameter().collectEmuLog += data;
|
||||
else
|
||||
DEBUG_LOG(COMMON, "%s", data.c_str());
|
||||
}
|
||||
|
||||
void WindowsHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h)
|
||||
{
|
||||
// We ignore the current framebuffer parameters and just grab the full screen.
|
||||
@ -100,19 +107,24 @@ void WindowsHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h)
|
||||
const static int FRAME_HEIGHT = 272;
|
||||
u8 *pixels = new u8[FRAME_WIDTH * FRAME_HEIGHT * 4];
|
||||
|
||||
// TODO: Maybe this code should be moved into GLES_GPU.
|
||||
// TODO: Maybe this code should be moved into GLES_GPU to support DirectX/etc.
|
||||
glReadBuffer(GL_FRONT);
|
||||
glReadPixels(0, 0, FRAME_WIDTH, FRAME_HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
std::string error;
|
||||
double errors = CompareScreenshot(pixels, FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH, comparisonScreenshot, error);
|
||||
if (errors < 0)
|
||||
fprintf_s(out, "%s\n", error.c_str());
|
||||
SendOrCollectDebugOutput(error);
|
||||
|
||||
if (errors > 0)
|
||||
{
|
||||
fprintf_s(out, "Screenshot error: %f%%\n", errors * 100.0f);
|
||||
char temp[256];
|
||||
sprintf_s(temp, "Screenshot error: %f%%\n", errors * 100.0f);
|
||||
SendOrCollectDebugOutput(temp);
|
||||
}
|
||||
|
||||
if (errors > 0 && !teamCityMode)
|
||||
{
|
||||
// Lazy, just read in the original header to output the failed screenshot.
|
||||
u8 header[14 + 40] = {0};
|
||||
FILE *bmp = fopen(comparisonScreenshot.c_str(), "rb");
|
||||
@ -129,7 +141,7 @@ void WindowsHeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h)
|
||||
fwrite(pixels, sizeof(u32), FRAME_WIDTH * FRAME_HEIGHT, saved);
|
||||
fclose(saved);
|
||||
|
||||
fprintf_s(out, "Actual output written to: __testfailure.bmp\n");
|
||||
SendOrCollectDebugOutput("Actual output written to: __testfailure.bmp\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,10 +40,10 @@ public:
|
||||
private:
|
||||
bool ResizeGL();
|
||||
void LoadNativeAssets();
|
||||
void SendOrCollectDebugOutput(const std::string &output);
|
||||
|
||||
HWND hWnd;
|
||||
HDC hDC;
|
||||
HGLRC hRC;
|
||||
FILE *out;
|
||||
std::string comparisonScreenshot;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user