mirror of https://github.com/PCSX2/pcsx2.git
GS: Support creating/replaying dumps in zstandard format
This commit is contained in:
parent
0f8bbfd64c
commit
df5e175b86
|
@ -46,7 +46,7 @@
|
||||||
#include "SettingWidgetBinder.h"
|
#include "SettingWidgetBinder.h"
|
||||||
|
|
||||||
static constexpr char DISC_IMAGE_FILTER[] =
|
static constexpr char DISC_IMAGE_FILTER[] =
|
||||||
QT_TRANSLATE_NOOP("MainWindow", "All File Types (*.bin *.iso *.cue *.chd *.cso *.gz *.elf *.irx *.m3u *.gs *.gs.xz);;"
|
QT_TRANSLATE_NOOP("MainWindow", "All File Types (*.bin *.iso *.cue *.chd *.cso *.gz *.elf *.irx *.m3u *.gs *.gs.xz *.gs.zst);;"
|
||||||
"Single-Track Raw Images (*.bin *.iso);;"
|
"Single-Track Raw Images (*.bin *.iso);;"
|
||||||
"Cue Sheets (*.cue);;"
|
"Cue Sheets (*.cue);;"
|
||||||
"MAME CHD Images (*.chd);;"
|
"MAME CHD Images (*.chd);;"
|
||||||
|
@ -55,7 +55,7 @@ static constexpr char DISC_IMAGE_FILTER[] =
|
||||||
"ELF Executables (*.elf);;"
|
"ELF Executables (*.elf);;"
|
||||||
"IRX Executables (*.irx);;"
|
"IRX Executables (*.irx);;"
|
||||||
"Playlists (*.m3u);;"
|
"Playlists (*.m3u);;"
|
||||||
"GS Dumps (*.gs *.gs.xz)");
|
"GS Dumps (*.gs *.gs.xz *.gs.zst)");
|
||||||
|
|
||||||
const char* MainWindow::DEFAULT_THEME_NAME = "darkfusion";
|
const char* MainWindow::DEFAULT_THEME_NAME = "darkfusion";
|
||||||
|
|
||||||
|
|
|
@ -1194,7 +1194,12 @@
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>LZMA (XZ)</string>
|
<string>LZMA (xz)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Zstandard (zst)</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
|
|
|
@ -1604,6 +1604,7 @@ target_link_libraries(PCSX2_FLAGS INTERFACE
|
||||||
PkgConfig::SAMPLERATE
|
PkgConfig::SAMPLERATE
|
||||||
PNG::PNG
|
PNG::PNG
|
||||||
LibLZMA::LibLZMA
|
LibLZMA::LibLZMA
|
||||||
|
Zstd::Zstd
|
||||||
${LIBC_LIBRARIES}
|
${LIBC_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,8 @@ enum class TexturePreloadingLevel : u8
|
||||||
enum class GSDumpCompressionMethod : u8
|
enum class GSDumpCompressionMethod : u8
|
||||||
{
|
{
|
||||||
Uncompressed,
|
Uncompressed,
|
||||||
LZMA
|
LZMA,
|
||||||
|
Zstandard,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Template function for casting enumerations to their underlying type
|
// Template function for casting enumerations to their underlying type
|
||||||
|
|
|
@ -1276,7 +1276,8 @@ void GSApp::Init()
|
||||||
m_gs_tv_shaders.push_back(GSSetting(4, "Wave filter", ""));
|
m_gs_tv_shaders.push_back(GSSetting(4, "Wave filter", ""));
|
||||||
|
|
||||||
m_gs_dump_compression.push_back(GSSetting(static_cast<u32>(GSDumpCompressionMethod::Uncompressed), "Uncompressed", ""));
|
m_gs_dump_compression.push_back(GSSetting(static_cast<u32>(GSDumpCompressionMethod::Uncompressed), "Uncompressed", ""));
|
||||||
m_gs_dump_compression.push_back(GSSetting(static_cast<u32>(GSDumpCompressionMethod::LZMA), "LZMA (XZ)", ""));
|
m_gs_dump_compression.push_back(GSSetting(static_cast<u32>(GSDumpCompressionMethod::LZMA), "LZMA (xz)", ""));
|
||||||
|
m_gs_dump_compression.push_back(GSSetting(static_cast<u32>(GSDumpCompressionMethod::Zstandard), "Zstandard (zst)", ""));
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// Avoid to clutter the ini file with useless options
|
// Avoid to clutter the ini file with useless options
|
||||||
|
|
|
@ -226,3 +226,92 @@ void GSDumpXz::Compress(lzma_action action, lzma_ret expected_status)
|
||||||
|
|
||||||
} while (m_strm.avail_out == 0);
|
} while (m_strm.avail_out == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// GSDumpZstd implementation
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
GSDumpZst::GSDumpZst(const std::string& fn, const std::string& serial, u32 crc,
|
||||||
|
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||||
|
const freezeData& fd, const GSPrivRegSet* regs)
|
||||||
|
: GSDumpBase(fn + ".gs.zst")
|
||||||
|
{
|
||||||
|
m_strm = ZSTD_createCStream();
|
||||||
|
|
||||||
|
// Compression level 6 provides a good balance between speed and ratio.
|
||||||
|
ZSTD_CCtx_setParameter(m_strm, ZSTD_c_compressionLevel, 6);
|
||||||
|
|
||||||
|
m_in_buff.reserve(_1mb);
|
||||||
|
m_out_buff.resize(_1mb);
|
||||||
|
|
||||||
|
AddHeader(serial, crc, screenshot_width, screenshot_height, screenshot_pixels, fd, regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
GSDumpZst::~GSDumpZst()
|
||||||
|
{
|
||||||
|
// Finish the stream
|
||||||
|
Compress(ZSTD_e_end);
|
||||||
|
|
||||||
|
ZSTD_freeCStream(m_strm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSDumpZst::AppendRawData(const void* data, size_t size)
|
||||||
|
{
|
||||||
|
size_t old_size = m_in_buff.size();
|
||||||
|
m_in_buff.resize(old_size + size);
|
||||||
|
memcpy(&m_in_buff[old_size], data, size);
|
||||||
|
MayFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSDumpZst::AppendRawData(u8 c)
|
||||||
|
{
|
||||||
|
m_in_buff.push_back(c);
|
||||||
|
MayFlush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSDumpZst::MayFlush()
|
||||||
|
{
|
||||||
|
if (m_in_buff.size() >= _1mb)
|
||||||
|
Compress(ZSTD_e_continue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSDumpZst::Compress(ZSTD_EndDirective action)
|
||||||
|
{
|
||||||
|
if (m_in_buff.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ZSTD_inBuffer inbuf = {m_in_buff.data(), m_in_buff.size(), 0};
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ZSTD_outBuffer outbuf = {m_out_buff.data(), m_out_buff.size(), 0};
|
||||||
|
|
||||||
|
const size_t remaining = ZSTD_compressStream2(m_strm, &outbuf, &inbuf, action);
|
||||||
|
if (ZSTD_isError(remaining))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "GSDumpZstd: Error %s\n", ZSTD_getErrorName(remaining));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outbuf.pos > 0)
|
||||||
|
{
|
||||||
|
Write(m_out_buff.data(), outbuf.pos);
|
||||||
|
outbuf.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == ZSTD_e_end)
|
||||||
|
{
|
||||||
|
// break when compression output has finished
|
||||||
|
if (remaining == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// break when all input data is consumed
|
||||||
|
if (inbuf.pos == inbuf.size)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_in_buff.clear();
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "GSRegs.h"
|
#include "GSRegs.h"
|
||||||
#include "Renderers/SW/GSVertexSW.h"
|
#include "Renderers/SW/GSVertexSW.h"
|
||||||
#include <lzma.h>
|
#include <lzma.h>
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -110,3 +111,22 @@ public:
|
||||||
const freezeData& fd, const GSPrivRegSet* regs);
|
const freezeData& fd, const GSPrivRegSet* regs);
|
||||||
virtual ~GSDumpXz();
|
virtual ~GSDumpXz();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GSDumpZst final : public GSDumpBase
|
||||||
|
{
|
||||||
|
ZSTD_CStream* m_strm;
|
||||||
|
|
||||||
|
std::vector<u8> m_in_buff;
|
||||||
|
std::vector<u8> m_out_buff;
|
||||||
|
|
||||||
|
void MayFlush();
|
||||||
|
void Compress(ZSTD_EndDirective action);
|
||||||
|
void AppendRawData(const void* data, size_t size);
|
||||||
|
void AppendRawData(u8 c);
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSDumpZst(const std::string& fn, const std::string& serial, u32 crc,
|
||||||
|
u32 screenshot_width, u32 screenshot_height, const u32* screenshot_pixels,
|
||||||
|
const freezeData& fd, const GSPrivRegSet* regs);
|
||||||
|
virtual ~GSDumpZst();
|
||||||
|
};
|
||||||
|
|
|
@ -66,6 +66,8 @@ std::unique_ptr<GSDumpFile> GSDumpFile::OpenGSDump(const char* filename, const c
|
||||||
|
|
||||||
if (StringUtil::EndsWithNoCase(filename, ".xz"))
|
if (StringUtil::EndsWithNoCase(filename, ".xz"))
|
||||||
return std::make_unique<GSDumpLzma>(fp, nullptr);
|
return std::make_unique<GSDumpLzma>(fp, nullptr);
|
||||||
|
else if (StringUtil::EndsWithNoCase(filename, ".zst"))
|
||||||
|
return std::make_unique<GSDumpDecompressZst>(fp, nullptr);
|
||||||
else
|
else
|
||||||
return std::make_unique<GSDumpRaw>(fp, nullptr);
|
return std::make_unique<GSDumpRaw>(fp, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -359,6 +361,95 @@ GSDumpLzma::~GSDumpLzma()
|
||||||
_aligned_free(m_area);
|
_aligned_free(m_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
GSDumpDecompressZst::GSDumpDecompressZst(FILE* file, FILE* repack_file)
|
||||||
|
: GSDumpFile(file, repack_file)
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSDumpDecompressZst::Initialize()
|
||||||
|
{
|
||||||
|
m_strm = ZSTD_createDStream();
|
||||||
|
|
||||||
|
m_area = (uint8_t*)_aligned_malloc(OUTPUT_BUFFER_SIZE, 32);
|
||||||
|
m_inbuf.src = (uint8_t*)_aligned_malloc(INPUT_BUFFER_SIZE, 32);
|
||||||
|
m_inbuf.pos = 0;
|
||||||
|
m_inbuf.size = 0;
|
||||||
|
m_avail = 0;
|
||||||
|
m_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GSDumpDecompressZst::Decompress()
|
||||||
|
{
|
||||||
|
ZSTD_outBuffer outbuf = { m_area, OUTPUT_BUFFER_SIZE, 0 };
|
||||||
|
while (outbuf.pos == 0)
|
||||||
|
{
|
||||||
|
// Nothing left in the input buffer. Read data from the file
|
||||||
|
if (m_inbuf.pos == m_inbuf.size && !feof(m_fp))
|
||||||
|
{
|
||||||
|
m_inbuf.size = fread((void*)m_inbuf.src, 1, INPUT_BUFFER_SIZE, m_fp);
|
||||||
|
m_inbuf.pos = 0;
|
||||||
|
|
||||||
|
if (ferror(m_fp))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Read error: %s\n", strerror(errno));
|
||||||
|
throw "BAD"; // Just exit the program
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ret = ZSTD_decompressStream(m_strm, &outbuf, &m_inbuf);
|
||||||
|
if (ZSTD_isError(ret))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Decoder error: (error code %s)\n", ZSTD_getErrorName(ret));
|
||||||
|
throw "BAD"; // Just exit the program
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_start = 0;
|
||||||
|
m_avail = outbuf.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GSDumpDecompressZst::IsEof()
|
||||||
|
{
|
||||||
|
return feof(m_fp) && m_avail == 0 && m_inbuf.pos == m_inbuf.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GSDumpDecompressZst::Read(void* ptr, size_t size)
|
||||||
|
{
|
||||||
|
size_t off = 0;
|
||||||
|
uint8_t* dst = (uint8_t*)ptr;
|
||||||
|
while (size && !IsEof())
|
||||||
|
{
|
||||||
|
if (m_avail == 0)
|
||||||
|
{
|
||||||
|
Decompress();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t l = std::min(size, m_avail);
|
||||||
|
memcpy(dst + off, m_area + m_start, l);
|
||||||
|
m_avail -= l;
|
||||||
|
size -= l;
|
||||||
|
m_start += l;
|
||||||
|
off += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (off > 0)
|
||||||
|
Repack(ptr, off);
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
GSDumpDecompressZst::~GSDumpDecompressZst()
|
||||||
|
{
|
||||||
|
ZSTD_freeDStream(m_strm);
|
||||||
|
|
||||||
|
if (m_inbuf.src)
|
||||||
|
_aligned_free((void*)m_inbuf.src);
|
||||||
|
if (m_area)
|
||||||
|
_aligned_free(m_area);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
GSDumpRaw::GSDumpRaw(FILE* file, FILE* repack_file)
|
GSDumpRaw::GSDumpRaw(FILE* file, FILE* repack_file)
|
||||||
|
|
|
@ -15,11 +15,13 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <lzma.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <lzma.h>
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
#define GEN_REG_ENUM_CLASS_CONTENT(ClassName, EntryName, Value) \
|
#define GEN_REG_ENUM_CLASS_CONTENT(ClassName, EntryName, Value) \
|
||||||
EntryName = Value,
|
EntryName = Value,
|
||||||
|
|
||||||
|
@ -358,6 +360,30 @@ public:
|
||||||
size_t Read(void* ptr, size_t size) final;
|
size_t Read(void* ptr, size_t size) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GSDumpDecompressZst : public GSDumpFile
|
||||||
|
{
|
||||||
|
static constexpr u32 INPUT_BUFFER_SIZE = 512 * _1kb;
|
||||||
|
static constexpr u32 OUTPUT_BUFFER_SIZE = 2 * _1mb;
|
||||||
|
|
||||||
|
ZSTD_DStream* m_strm;
|
||||||
|
ZSTD_inBuffer m_inbuf;
|
||||||
|
|
||||||
|
uint8_t* m_area;
|
||||||
|
|
||||||
|
size_t m_avail;
|
||||||
|
size_t m_start;
|
||||||
|
|
||||||
|
void Decompress();
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSDumpDecompressZst(FILE* file, FILE* repack_file);
|
||||||
|
virtual ~GSDumpDecompressZst();
|
||||||
|
|
||||||
|
bool IsEof() final;
|
||||||
|
size_t Read(void* ptr, size_t size) final;
|
||||||
|
};
|
||||||
|
|
||||||
class GSDumpRaw : public GSDumpFile
|
class GSDumpRaw : public GSDumpFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -564,7 +564,7 @@ void GSRenderer::VSync(u32 field, bool registers_written)
|
||||||
fd, m_regs));
|
fd, m_regs));
|
||||||
compression_str = "with no compression";
|
compression_str = "with no compression";
|
||||||
}
|
}
|
||||||
else
|
else if (GSConfig.GSDumpCompression == GSDumpCompressionMethod::LZMA)
|
||||||
{
|
{
|
||||||
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, GetDumpSerial(), m_crc,
|
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpXz(m_snapshot, GetDumpSerial(), m_crc,
|
||||||
DUMP_SCREENSHOT_WIDTH, DUMP_SCREENSHOT_HEIGHT,
|
DUMP_SCREENSHOT_WIDTH, DUMP_SCREENSHOT_HEIGHT,
|
||||||
|
@ -572,6 +572,14 @@ void GSRenderer::VSync(u32 field, bool registers_written)
|
||||||
fd, m_regs));
|
fd, m_regs));
|
||||||
compression_str = "with LZMA compression";
|
compression_str = "with LZMA compression";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dump = std::unique_ptr<GSDumpBase>(new GSDumpZst(m_snapshot, GetDumpSerial(), m_crc,
|
||||||
|
DUMP_SCREENSHOT_WIDTH, DUMP_SCREENSHOT_HEIGHT,
|
||||||
|
screenshot_pixels.empty() ? nullptr : screenshot_pixels.data(),
|
||||||
|
fd, m_regs));
|
||||||
|
compression_str = "with Zstandard compression";
|
||||||
|
}
|
||||||
|
|
||||||
delete[] fd.data;
|
delete[] fd.data;
|
||||||
|
|
||||||
|
@ -642,7 +650,7 @@ void GSRenderer::QueueSnapshot(const std::string& path, u32 gsdump_frames)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Allows for providing a complete path
|
// Allows for providing a complete path
|
||||||
if (path.size() > 4 && StringUtil::compareNoCase(path.substr(path.size() - 4, 4), ".png"))
|
if (path.size() > 4 && StringUtil::EndsWithNoCase(path, ".png"))
|
||||||
{
|
{
|
||||||
m_snapshot = path.substr(0, path.size() - 4);
|
m_snapshot = path.substr(0, path.size() - 4);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1111,7 +1111,9 @@ bool VMManager::IsElfFileName(const std::string& path)
|
||||||
|
|
||||||
bool VMManager::IsGSDumpFileName(const std::string& path)
|
bool VMManager::IsGSDumpFileName(const std::string& path)
|
||||||
{
|
{
|
||||||
return (StringUtil::EndsWithNoCase(path, ".gs") || StringUtil::EndsWithNoCase(path, ".gs.xz"));
|
return (StringUtil::EndsWithNoCase(path, ".gs") ||
|
||||||
|
StringUtil::EndsWithNoCase(path, ".gs.xz") ||
|
||||||
|
StringUtil::EndsWithNoCase(path, ".gs.zst"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::Execute()
|
void VMManager::Execute()
|
||||||
|
|
|
@ -222,6 +222,8 @@ void Dialogs::GSDumpDialog::GetDumpsList()
|
||||||
dumps.push_back(filename.substr(0, filename.length() - 3));
|
dumps.push_back(filename.substr(0, filename.length() - 3));
|
||||||
else if (filename.EndsWith(".gs.xz"))
|
else if (filename.EndsWith(".gs.xz"))
|
||||||
dumps.push_back(filename.substr(0, filename.length() - 6));
|
dumps.push_back(filename.substr(0, filename.length() - 6));
|
||||||
|
else if (filename.EndsWith(".gs.zst"))
|
||||||
|
dumps.push_back(filename.substr(0, filename.length() - 7));
|
||||||
cont = snaps.GetNext(&filename);
|
cont = snaps.GetNext(&filename);
|
||||||
}
|
}
|
||||||
std::sort(dumps.begin(), dumps.end(), [](const wxString& a, const wxString& b) { return a.CmpNoCase(b) < 0; });
|
std::sort(dumps.begin(), dumps.end(), [](const wxString& a, const wxString& b) { return a.CmpNoCase(b) < 0; });
|
||||||
|
@ -249,6 +251,8 @@ void Dialogs::GSDumpDialog::SelectedDump(wxListEvent& evt)
|
||||||
wxString filename = g_Conf->Folders.Snapshots.ToAscii() + ("/" + evt.GetText()) + ".gs";
|
wxString filename = g_Conf->Folders.Snapshots.ToAscii() + ("/" + evt.GetText()) + ".gs";
|
||||||
if (!wxFileExists(filename))
|
if (!wxFileExists(filename))
|
||||||
filename.append(".xz");
|
filename.append(".xz");
|
||||||
|
if (!wxFileExists(filename))
|
||||||
|
filename = filename.RemoveLast(3).append(".zst");
|
||||||
if (wxFileExists(filename_preview))
|
if (wxFileExists(filename_preview))
|
||||||
{
|
{
|
||||||
auto img = wxImage(filename_preview);
|
auto img = wxImage(filename_preview);
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\imgui\imgui;$(SolutionDir)3rdparty\imgui\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\imgui\imgui;$(SolutionDir)3rdparty\imgui\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libzip;$(SolutionDir)3rdparty\libzip\libzip\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libzip;$(SolutionDir)3rdparty\libzip\libzip\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\d3d12memalloc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\d3d12memalloc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\zstd\zstd\lib</AdditionalIncludeDirectories>
|
||||||
<ExceptionHandling>Async</ExceptionHandling>
|
<ExceptionHandling>Async</ExceptionHandling>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\sdl2\include;$(SolutionDir)3rdparty\sdl2\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\sdl2\include;$(SolutionDir)3rdparty\sdl2\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libzip;$(SolutionDir)3rdparty\libzip\libzip\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libzip;$(SolutionDir)3rdparty\libzip\libzip\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\d3d12memalloc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\d3d12memalloc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\zstd\zstd\lib</AdditionalIncludeDirectories>
|
||||||
<ExceptionHandling>Async</ExceptionHandling>
|
<ExceptionHandling>Async</ExceptionHandling>
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
||||||
|
|
Loading…
Reference in New Issue