This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

@@ -54,8 +54,6 @@ Dolphin includes or links code of the following third-party software projects:
[zlib license](http://hg.libsdl.org/SDL/file/tip/COPYING.txt)
- [SFML](http://www.sfml-dev.org/):
[zlib license](http://www.sfml-dev.org/license.php)
- [SOIL](http://www.lonesock.net/soil.html):
[public domain](http://www.lonesock.net/soil.html)
- [SoundTouch](http://www.surina.net/soundtouch/):
[LGPLv2+](http://www.surina.net/soundtouch/license.html)
- [TAP-Windows](https://openvpn.net/):
@@ -60,14 +60,12 @@ BuildRequires: openal-soft-devel
BuildRequires: mbedtls-devel
BuildRequires: SDL2-devel
BuildRequires: SFML-devel
BuildRequires: SOIL-devel
BuildRequires: soundtouch-devel
%endif

%if 0%{?suse_version}
BuildRequires: libminiupnpc-devel
BuildRequires: libSDL2-devel
BuildRequires: libSOIL-devel
BuildRequires: lzo-devel
BuildRequires: openal-devel
BuildRequires: sfml-devel
@@ -18,6 +18,7 @@ add_library(common
GekkoDisassembler.cpp
Hash.cpp
HttpRequest.cpp
Image.cpp
IniFile.cpp
JitRegister.cpp
Logging/LogManager.cpp
@@ -54,6 +55,7 @@ PUBLIC
PRIVATE
${CURL_LIBRARIES}
${ICONV_LIBRARIES}
png
${VTUNE_LIBRARIES}
)

@@ -125,6 +125,7 @@
<ClInclude Include="FloatUtils.h" />
<ClInclude Include="Hash.h" />
<ClInclude Include="HttpRequest.h" />
<ClInclude Include="Image.h" />
<ClInclude Include="IniFile.h" />
<ClInclude Include="JitRegister.h" />
<ClInclude Include="Lazy.h" />
@@ -188,6 +189,7 @@
<ClCompile Include="GL\GLUtil.cpp" />
<ClCompile Include="Hash.cpp" />
<ClCompile Include="HttpRequest.cpp" />
<ClCompile Include="Image.cpp" />
<ClCompile Include="IniFile.cpp" />
<ClCompile Include="JitRegister.cpp" />
<ClCompile Include="LdrWatcher.cpp" />
@@ -230,6 +232,9 @@
<ProjectReference Include="$(ExternalsDir)mbedtls\mbedTLS.vcxproj">
<Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
<Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\Externals\curl\curl.vcxproj">
<Project>{bb00605c-125f-4a21-b33b-7bf418322dcb}</Project>
</ProjectReference>
@@ -51,6 +51,7 @@
<ClInclude Include="FPURoundMode.h" />
<ClInclude Include="Hash.h" />
<ClInclude Include="HttpRequest.h" />
<ClInclude Include="Image.h" />
<ClInclude Include="IniFile.h" />
<ClInclude Include="LinearDiskCache.h" />
<ClInclude Include="MathUtil.h" />
@@ -281,6 +282,7 @@
<ClCompile Include="FloatUtils.cpp" />
<ClCompile Include="Hash.cpp" />
<ClCompile Include="HttpRequest.cpp" />
<ClCompile Include="Image.cpp" />
<ClCompile Include="IniFile.cpp" />
<ClCompile Include="MathUtil.cpp" />
<ClCompile Include="MemArena.cpp" />
@@ -0,0 +1,184 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "Common/Image.h"

// Versions of libpng older than 1.5 want us to not include setjmp.h before png.h,
// so let's include png.h first of all headers
#include <png.h>

#include <csetjmp>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"

namespace Common
{
static int MultiplyAlpha(int alpha, int color)
{
const int temp = (alpha * color) + 0x80;
return ((temp + (temp >> 8)) >> 8);
}

static void PremultiplyData(png_structp png, png_row_infop row_info, png_bytep data)
{
for (png_size_t i = 0; i < row_info->rowbytes; i += 4, data += 4)
{
const png_byte alpha = data[3];
u32 w;

if (alpha == 0)
{
w = 0;
}
else
{
png_byte red = data[0];
png_byte green = data[1];
png_byte blue = data[2];

if (alpha != 0xff)
{
red = MultiplyAlpha(alpha, red);
green = MultiplyAlpha(alpha, green);
blue = MultiplyAlpha(alpha, blue);
}
w = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
}

std::memcpy(data, &w, sizeof(w));
}
}

struct ReadProgress
{
const u8* current;
const u8* end;
};

static void ReadCallback(png_structp png, png_bytep data, png_size_t size)
{
ReadProgress* progress = static_cast<ReadProgress*>(png_get_io_ptr(png));
for (size_t i = 0; i < size; ++i)
{
if (progress->current >= progress->end)
png_error(png, "Read beyond end of file"); // This makes us longjmp back to LoadPNG

data[i] = *(progress->current);
++(progress->current);
}
}

static void PNGErrorCallback(png_structp png, png_const_charp error_msg)
{
ERROR_LOG(COMMON, "PNG loading error: %s", error_msg);
longjmp(png_jmpbuf(png), 1);
}

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4611)
// VS shows the following warning even though no C++ objects are destroyed in LoadPNG:
// "warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable"
#endif

bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width_out,
u32* height_out)
{
// The const_cast is only required for libpng versions older than 1.5
const bool is_png = !png_sig_cmp(const_cast<u8*>(input.data()), 0, input.size());
if (!is_png)
return false;

png_struct* png =
png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, PNGErrorCallback, nullptr);
if (!png)
return false;

png_info* info = png_create_info_struct(png);
if (!info)
{
png_destroy_read_struct(&png, &info, nullptr);
return false;
}

// It would've been nice to use std::vector for this, but using setjmp safely
// means that we have to use this manually managed volatile pointer garbage instead.
png_byte** volatile row_pointers_volatile = nullptr;

if (setjmp(png_jmpbuf(png)))
{
free(row_pointers_volatile);
png_destroy_read_struct(&png, &info, nullptr);
return false;
}

ReadProgress read_progress{input.data(), input.data() + input.size()};
png_set_read_fn(png, &read_progress, ReadCallback);
png_read_info(png, info);

png_uint_32 width, height;
int depth, color_type, interlace;
png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, nullptr, nullptr);

if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
else if (color_type == PNG_COLOR_TYPE_GRAY)
png_set_expand_gray_1_2_4_to_8(png);

if (png_get_valid(png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png);

if (depth == 16)
png_set_strip_16(png);
else if (depth < 8)
png_set_packing(png);

if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);

if (interlace != PNG_INTERLACE_NONE)
png_set_interlace_handling(png);

png_set_bgr(png);
png_set_filler(png, 0xff, PNG_FILLER_AFTER);
png_set_read_user_transform_fn(png, PremultiplyData);
png_read_update_info(png, info);
png_get_IHDR(png, info, &width, &height, &depth, &color_type, &interlace, nullptr, nullptr);

const size_t stride = width * 4;
data_out->resize(stride * height);

png_byte** row_pointers = static_cast<png_byte**>(malloc(height * sizeof(png_byte*)));
if (!row_pointers)
{
png_destroy_read_struct(&png, &info, nullptr);
return false;
}

for (png_uint_32 i = 0; i < height; i++)
row_pointers[i] = &(*data_out)[i * stride];

row_pointers_volatile = row_pointers;

png_read_image(png, row_pointers);
png_read_end(png, info);

free(row_pointers);
png_destroy_read_struct(&png, &info, nullptr);

*width_out = width;
*height_out = height;
return true;
}

#ifdef _MSC_VER
#pragma warning(pop)
#endif

} // namespace Common
@@ -0,0 +1,15 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <vector>

#include "Common/CommonTypes.h"

namespace Common
{
bool LoadPNG(const std::vector<u8>& input, std::vector<u8>* data_out, u32* width_out,
u32* height_out);
}
@@ -46,7 +46,4 @@ target_link_libraries(videod3d
PUBLIC
common
videocommon

PRIVATE
SOIL
)
@@ -24,6 +24,5 @@ PUBLIC
videocommon

PRIVATE
SOIL
${X11_LIBRARIES}
)
@@ -22,6 +22,5 @@ PUBLIC
videocommon

PRIVATE
SOIL
${X11_LIBRARIES}
)
@@ -4,7 +4,6 @@

#include "VideoCommon/HiresTextures.h"

#include <SOIL/SOIL.h>
#include <algorithm>
#include <cinttypes>
#include <cstring>
@@ -22,6 +21,7 @@
#include "Common/FileUtil.h"
#include "Common/Flag.h"
#include "Common/Hash.h"
#include "Common/Image.h"
#include "Common/Logging/Log.h"
#include "Common/MemoryUtil.h"
#include "Common/StringUtil.h"
@@ -42,17 +42,12 @@ struct DiskTexture
static std::unordered_map<std::string, DiskTexture> s_textureMap;
static std::unordered_map<std::string, std::shared_ptr<HiresTexture>> s_textureCache;
static std::mutex s_textureCacheMutex;
static std::mutex s_textureCacheAquireMutex; // for high priority access
static Common::Flag s_textureCacheAbortLoading;

static std::thread s_prefetcher;

static const std::string s_format_prefix = "tex1_";

HiresTexture::Level::Level() : data(nullptr, SOIL_free_image_data)
{
}

void HiresTexture::Init()
{
Update();
@@ -92,10 +87,7 @@ void HiresTexture::Update()

const std::string& game_id = SConfig::GetInstance().GetGameID();
const std::string texture_directory = GetTextureDirectory(game_id);
std::vector<std::string> extensions{
".png", ".bmp", ".tga", ".dds",
".jpg" // Why not? Could be useful for large photo-like textures
};
const std::vector<std::string> extensions{".png", ".dds"};

const std::vector<std::string> texture_paths =
Common::DoFileSearch({texture_directory}, extensions, /*recursive*/ true);
@@ -155,25 +147,16 @@ void HiresTexture::Prefetch()

if (base_filename.find("_mip") == std::string::npos)
{
{
// try to get this mutex first, so the video thread is allow to get the real mutex faster
std::unique_lock<std::mutex> lk(s_textureCacheAquireMutex);
}
std::unique_lock<std::mutex> lk(s_textureCacheMutex);

auto iter = s_textureCache.find(base_filename);
if (iter == s_textureCache.end())
{
// unlock while loading a texture. This may result in a race condition where we'll load a
// texture twice,
// but it reduces the stuttering a lot. Notice: The loading library _must_ be thread safe
// now.
// But bad luck, SOIL isn't, so TODO: remove SOIL usage here and use libpng directly
// Also TODO: remove s_textureCacheAquireMutex afterwards. It won't be needed as the main
// mutex will be locked rarely
// lk.unlock();
// unlock while loading a texture. This may result in a race condition where
// we'll load a texture twice, but it reduces the stuttering a lot.
lk.unlock();
std::unique_ptr<HiresTexture> texture = Load(base_filename, 0, 0);
// lk.lock();
lk.lock();
if (texture)
{
std::shared_ptr<HiresTexture> ptr(std::move(texture));
@@ -183,9 +166,7 @@ void HiresTexture::Prefetch()
if (iter != s_textureCache.end())
{
for (const Level& l : iter->second->m_levels)
{
size_sum += l.data_size;
}
size_sum += l.data.size();
}
}

@@ -306,7 +287,6 @@ std::shared_ptr<HiresTexture> HiresTexture::Search(const u8* texture, size_t tex
std::string base_filename =
GenBaseName(texture, texture_size, tlut, tlut_size, width, height, format, has_mipmaps);

std::lock_guard<std::mutex> lk2(s_textureCacheAquireMutex);
std::lock_guard<std::mutex> lk(s_textureCacheMutex);

auto iter = s_textureCache.find(base_filename);
@@ -361,6 +341,7 @@ std::unique_ptr<HiresTexture> HiresTexture::Load(const std::string& base_filenam
file.Open(filename_iter->second.path, "rb");
std::vector<u8> buffer(file.GetSize());
file.ReadBytes(buffer.data(), file.GetSize());

if (!LoadTexture(level, buffer))
{
ERROR_LOG(VIDEO, "Custom texture %s failed to load", filename.c_str());
@@ -440,22 +421,15 @@ std::unique_ptr<HiresTexture> HiresTexture::Load(const std::string& base_filenam

bool HiresTexture::LoadTexture(Level& level, const std::vector<u8>& buffer)
{
int channels;
int width;
int height;
if (!Common::LoadPNG(buffer, &level.data, &level.width, &level.height))
return false;

u8* data = SOIL_load_image_from_memory(buffer.data(), static_cast<int>(buffer.size()), &width,
&height, &channels, SOIL_LOAD_RGBA);
if (!data)
if (level.data.empty())
return false;

// Images loaded by SOIL are converted to RGBA.
level.width = static_cast<u32>(width);
level.height = static_cast<u32>(height);
// Loaded PNG images are converted to RGBA.
level.format = AbstractTextureFormat::RGBA8;
level.data = ImageDataPointer(data, SOIL_free_image_data);
level.row_length = level.width;
level.data_size = static_cast<size_t>(level.row_length) * 4 * level.height;
return true;
}

@@ -16,8 +16,6 @@ enum class TextureFormat;
class HiresTexture
{
public:
using ImageDataPointer = std::unique_ptr<u8, void (*)(unsigned char*)>;

static void Init();
static void Update();
static void Shutdown();
@@ -39,14 +37,11 @@ class HiresTexture

struct Level
{
Level();

ImageDataPointer data;
std::vector<u8> data;
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
u32 width = 0;
u32 height = 0;
u32 row_length = 0;
size_t data_size = 0;
};
std::vector<Level> m_levels;

@@ -155,14 +155,9 @@ u32 GetBlockCount(u32 extent, u32 block_size)
return std::max(Common::AlignUp(extent, block_size) / block_size, 1u);
}

HiresTexture::ImageDataPointer AllocateLevelData(size_t size)
{
return HiresTexture::ImageDataPointer(new u8[size], [](u8* data) { delete[] data; });
}

void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)
{
u8* data_ptr = level->data.get();
u8* data_ptr = level->data.data();
for (u32 row = 0; row < level->height; row++)
{
for (u32 x = 0; x < level->row_length; x++)
@@ -176,7 +171,7 @@ void ConvertTexture_X8B8G8R8(HiresTexture::Level* level)

void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)
{
u8* data_ptr = level->data.get();
u8* data_ptr = level->data.data();
for (u32 row = 0; row < level->height; row++)
{
for (u32 x = 0; x < level->row_length; x++)
@@ -193,7 +188,7 @@ void ConvertTexture_A8R8G8B8(HiresTexture::Level* level)

void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)
{
u8* data_ptr = level->data.get();
u8* data_ptr = level->data.data();
for (u32 row = 0; row < level->height; row++)
{
for (u32 x = 0; x < level->row_length; x++)
@@ -210,14 +205,10 @@ void ConvertTexture_X8R8G8B8(HiresTexture::Level* level)

void ConvertTexture_R8G8B8(HiresTexture::Level* level)
{
// Have to reallocate the buffer for this one, since the data in the file
// does not have an alpha byte.
level->data_size = level->row_length * level->height * sizeof(u32);
HiresTexture::ImageDataPointer rgb_data = AllocateLevelData(level->data_size);
std::swap(level->data, rgb_data);
std::vector<u8> new_data(level->row_length * level->height * sizeof(u32));

const u8* rgb_data_ptr = rgb_data.get();
u8* data_ptr = level->data.get();
const u8* rgb_data_ptr = level->data.data();
u8* data_ptr = new_data.data();

for (u32 row = 0; row < level->height; row++)
{
@@ -232,6 +223,8 @@ void ConvertTexture_R8G8B8(HiresTexture::Level* level)
rgb_data_ptr += 3;
}
}

level->data = std::move(new_data);
}

bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
@@ -410,19 +403,14 @@ bool ParseDDSHeader(File::IOFile& file, DDSLoadInfo* info)
bool ReadMipLevel(HiresTexture::Level* level, File::IOFile& file, const DDSLoadInfo& info,
u32 width, u32 height, u32 row_length, size_t size)
{
// Copy to the final storage location. The deallocator here is simple, nothing extra is
// needed, compared to the SOIL-based loader.
// Copy to the final storage location.
level->width = width;
level->height = height;
level->format = info.format;
level->row_length = row_length;
level->data_size = size;
level->data = AllocateLevelData(level->data_size);
if (!file.ReadBytes(level->data.get(), level->data_size))
{
level->data.reset();
level->data.resize(size);
if (!file.ReadBytes(level->data.data(), level->data.size()))
return false;
}

// Apply conversion function for uncompressed textures.
if (info.conversion_function)
@@ -957,8 +957,8 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
if (hires_tex)
{
const auto& level = hires_tex->m_levels[0];
entry->texture->Load(0, level.width, level.height, level.row_length, level.data.get(),
level.data_size);
entry->texture->Load(0, level.width, level.height, level.row_length, level.data.data(),
level.data.size());
}

// Initialized to null because only software loading uses this buffer
@@ -1042,7 +1042,7 @@ TextureCacheBase::GetTexture(u32 address, u32 width, u32 height, const TextureFo
{
const auto& level = hires_tex->m_levels[level_index];
entry->texture->Load(level_index, level.width, level.height, level.row_length,
level.data.get(), level.data_size);
level.data.data(), level.data.size());
}
}
else
@@ -174,9 +174,6 @@
<ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
<Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)SOIL\SOIL.vcxproj">
<Project>{b441cc62-877e-4b3f-93e0-0de80544f705}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)xxhash\xxhash.vcxproj">
<Project>{677EA016-1182-440C-9345-DC88D1E98C0C}</Project>
</ProjectReference>
@@ -190,4 +187,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
@@ -49,7 +49,6 @@
<AdditionalIncludeDirectories>$(ExternalsDir)mbedtls\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ExternalsDir)pugixml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ExternalsDir)SFML\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ExternalsDir)SOIL;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ExternalsDir)Vulkan\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ExternalsDir)wxWidgets3;$(ExternalsDir)wxWidgets3\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ExternalsDir)xxhash;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -57,7 +57,7 @@
in order to prevent the trailing slash from escaping the doublequote after value replacement.
-->
<MocIncludes>"-I$(QtIncludeDir)QtWidgets" "-I$(QtIncludeDir)QtGui" "-I$(QtIncludeDir)QtCore" "-I$(QtIncludeDir) " "-I$(QtToolOutDir) " -I.</MocIncludes>
<MocIncludes>"-I$(ExternalsDir)xxhash" "-I$(ExternalsDir)zlib" "-I$(ExternalsDir)SOIL" "-I$(ExternalsDir)SFML\include" "-I$(ExternalsDir)mbedtls\include" "-I$(ExternalsDir)miniupnpc\src" "-I$(ExternalsDir)LZO" "-I$(ExternalsDir)libusbx\libusb" "-I$(ExternalsDir)libpng" "-I$(ExternalsDir)GL" "-I$(ExternalsDir)Bochs_disasm" "-I$(ExternalsDir) " "-I$(CoreDir) " $(MocIncludes)</MocIncludes>
<MocIncludes>"-I$(ExternalsDir)xxhash" "-I$(ExternalsDir)zlib" "-I$(ExternalsDir)SFML\include" "-I$(ExternalsDir)mbedtls\include" "-I$(ExternalsDir)miniupnpc\src" "-I$(ExternalsDir)LZO" "-I$(ExternalsDir)libusbx\libusb" "-I$(ExternalsDir)libpng" "-I$(ExternalsDir)GL" "-I$(ExternalsDir)Bochs_disasm" "-I$(ExternalsDir) " "-I$(CoreDir) " $(MocIncludes)</MocIncludes>
</PropertyGroup>
<Target Name="QtMoc"
BeforeTargets="ClCompile"
@@ -33,8 +33,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniupnpc", "..\Externals\m
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "png", "..\Externals\libpng\png\png.vcxproj", "{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SOIL", "..\Externals\SOIL\SOIL.vcxproj", "{B441CC62-877E-4B3F-93E0-0DE80544F705}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "..\Externals\xxhash\xxhash.vcxproj", "{677EA016-1182-440C-9345-DC88D1E98C0C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\Externals\zlib\zlib.vcxproj", "{FF213B23-2C26-4214-9F88-85271E557E87}"
@@ -147,10 +145,6 @@ Global
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Debug|x64.Build.0 = Debug|x64
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Release|x64.ActiveCfg = Release|x64
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C}.Release|x64.Build.0 = Release|x64
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Debug|x64.ActiveCfg = Debug|x64
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Debug|x64.Build.0 = Debug|x64
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Release|x64.ActiveCfg = Release|x64
{B441CC62-877E-4B3F-93E0-0DE80544F705}.Release|x64.Build.0 = Release|x64
{677EA016-1182-440C-9345-DC88D1E98C0C}.Debug|x64.ActiveCfg = Debug|x64
{677EA016-1182-440C-9345-DC88D1E98C0C}.Debug|x64.Build.0 = Debug|x64
{677EA016-1182-440C-9345-DC88D1E98C0C}.Release|x64.ActiveCfg = Release|x64
@@ -271,7 +265,6 @@ Global
{AB993F38-C31D-4897-B139-A620C42BC565} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{31643FDB-1BB8-4965-9DE7-000FC88D35AE} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{4C9F135B-A85E-430C-BAD4-4C67EF5FC12C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{B441CC62-877E-4B3F-93E0-0DE80544F705} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{677EA016-1182-440C-9345-DC88D1E98C0C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{FF213B23-2C26-4214-9F88-85271E557E87} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{EC082900-B4D8-42E9-9663-77F02F6936AE} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}