Commit 0ee360de by Amy Liu Committed by Commit Bot

Revert "Compression of the data from vkGetPipelineCacheData."

This reverts commit cc5083e0. Reason for revert: Re-land this patch after fixing the performance regression of big blob cache (discussed in angle issue 4722). Original change's description: > Compression of the data from vkGetPipelineCacheData. > > The size of pipelineCacheData sometimes is greater than > 64k which cannot be saved because of the Android blob cache > limitation (single cache data size should be < 64k). > Implement the compression to store more cache data. > > Bug: angleproject:4722 > Change-Id: I435b086d70d0e6378f1141464ae2bafbe076f193 > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2631511 > Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> > Reviewed-by: Jamie Madill <jmadill@chromium.org> > Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> > Reviewed-by: Geoff Lang <geofflang@chromium.org> Bug: angleproject:4722 Change-Id: Ie4de10eabf5cd8f0b4748e2c1a4c3ab6b8ea092c No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2739098Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 32bf7d41
...@@ -14,9 +14,6 @@ ...@@ -14,9 +14,6 @@
#include "libANGLE/histogram_macros.h" #include "libANGLE/histogram_macros.h"
#include "platform/PlatformMethods.h" #include "platform/PlatformMethods.h"
#define USE_SYSTEM_ZLIB
#include "compression_utils_portable.h"
namespace egl namespace egl
{ {
...@@ -32,73 +29,6 @@ enum CacheResult ...@@ -32,73 +29,6 @@ enum CacheResult
} // anonymous namespace } // anonymous namespace
// In oder to store more cache in blob cache, compress cacheData to compressedData
// before being stored.
bool CompressBlobCacheData(angle::MemoryBuffer *cacheData, angle::MemoryBuffer *compressedData)
{
uLong uncompressedSize = static_cast<uLong>(cacheData->size());
uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
// Allocate memory.
if (!compressedData->resize(expectedCompressedSize))
{
ERR() << "Failed to allocate memory for compression";
return false;
}
int zResult =
zlib_internal::GzipCompressHelper(compressedData->data(), &expectedCompressedSize,
cacheData->data(), uncompressedSize, nullptr, nullptr);
if (zResult != Z_OK)
{
ERR() << "Failed to compress cache data: " << zResult;
return false;
}
// Resize it to expected size.
if (!compressedData->resize(expectedCompressedSize))
{
return false;
}
return true;
}
bool DecompressBlobCacheData(const uint8_t *compressedData,
const size_t compressedSize,
angle::MemoryBuffer *uncompressedData)
{
// Call zlib function to decompress.
uint32_t uncompressedSize =
zlib_internal::GetGzipUncompressedSize(compressedData, compressedSize);
// Allocate enough memory.
if (!uncompressedData->resize(uncompressedSize))
{
ERR() << "Failed to allocate memory for decompression";
return false;
}
uLong destLen = uncompressedSize;
int zResult = zlib_internal::GzipUncompressHelper(
uncompressedData->data(), &destLen, compressedData, static_cast<uLong>(compressedSize));
if (zResult != Z_OK)
{
ERR() << "Failed to decompress data: " << zResult << "\n";
return false;
}
// Resize it to expected size.
if (!uncompressedData->resize(destLen))
{
return false;
}
return true;
}
BlobCache::BlobCache(size_t maxCacheSizeBytes) BlobCache::BlobCache(size_t maxCacheSizeBytes)
: mBlobCache(maxCacheSizeBytes), mSetBlobFunc(nullptr), mGetBlobFunc(nullptr) : mBlobCache(maxCacheSizeBytes), mSetBlobFunc(nullptr), mGetBlobFunc(nullptr)
{} {}
......
...@@ -48,11 +48,6 @@ struct hash<egl::BlobCacheKey> ...@@ -48,11 +48,6 @@ struct hash<egl::BlobCacheKey>
namespace egl namespace egl
{ {
bool CompressBlobCacheData(angle::MemoryBuffer *cacheData, angle::MemoryBuffer *compressedData);
bool DecompressBlobCacheData(const uint8_t *compressedData,
const size_t compressedSize,
angle::MemoryBuffer *uncompressedData);
class BlobCache final : angle::NonCopyable class BlobCache final : angle::NonCopyable
{ {
public: public:
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/ProgramImpl.h"
#include "platform/PlatformMethods.h" #include "platform/PlatformMethods.h"
#define USE_SYSTEM_ZLIB
#include "compression_utils_portable.h"
namespace gl namespace gl
{ {
...@@ -143,10 +146,18 @@ angle::Result MemoryProgramCache::getProgram(const Context *context, ...@@ -143,10 +146,18 @@ angle::Result MemoryProgramCache::getProgram(const Context *context,
size_t programSize = 0; size_t programSize = 0;
if (get(context, *hashOut, &binaryProgram, &programSize)) if (get(context, *hashOut, &binaryProgram, &programSize))
{ {
angle::MemoryBuffer uncompressedData; uint32_t uncompressedSize =
if (!egl::DecompressBlobCacheData(binaryProgram.data(), programSize, &uncompressedData)) zlib_internal::GetGzipUncompressedSize(binaryProgram.data(), programSize);
std::vector<uint8_t> uncompressedData(uncompressedSize);
uLong destLen = uncompressedSize;
int zResult = zlib_internal::GzipUncompressHelper(uncompressedData.data(), &destLen,
binaryProgram.data(),
static_cast<uLong>(programSize));
if (zResult != Z_OK)
{ {
ERR() << "Error decompressing binary data."; ERR() << "Failure to decompressed binary data: " << zResult << "\n";
return angle::Result::Incomplete; return angle::Result::Incomplete;
} }
...@@ -209,10 +220,33 @@ angle::Result MemoryProgramCache::putProgram(const egl::BlobCache::Key &programH ...@@ -209,10 +220,33 @@ angle::Result MemoryProgramCache::putProgram(const egl::BlobCache::Key &programH
angle::MemoryBuffer serializedProgram; angle::MemoryBuffer serializedProgram;
ANGLE_TRY(program->serialize(context, &serializedProgram)); ANGLE_TRY(program->serialize(context, &serializedProgram));
// Compress the program data
uLong uncompressedSize = static_cast<uLong>(serializedProgram.size());
uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
angle::MemoryBuffer compressedData; angle::MemoryBuffer compressedData;
if (!egl::CompressBlobCacheData(&serializedProgram, &compressedData)) if (!compressedData.resize(expectedCompressedSize))
{
ERR() << "Failed to allocate enough memory to hold compressed program. ("
<< expectedCompressedSize << " bytes )";
return angle::Result::Incomplete;
}
int zResult = zlib_internal::GzipCompressHelper(compressedData.data(), &expectedCompressedSize,
serializedProgram.data(), uncompressedSize,
nullptr, nullptr);
if (zResult != Z_OK)
{
FATAL() << "Error compressing binary data: " << zResult;
return angle::Result::Incomplete;
}
// Resize the buffer to the actual compressed size
if (!compressedData.resize(expectedCompressedSize))
{ {
ERR() << "Error compressing binary data."; ERR() << "Failed to resize to actual compressed program size. (" << expectedCompressedSize
<< " bytes )";
return angle::Result::Incomplete; return angle::Result::Incomplete;
} }
......
...@@ -459,147 +459,6 @@ ANGLE_MAYBE_UNUSED bool SemaphorePropertiesCompatibleWithAndroid( ...@@ -459,147 +459,6 @@ ANGLE_MAYBE_UNUSED bool SemaphorePropertiesCompatibleWithAndroid(
return true; return true;
} }
void ComputePipelineCacheVkChunkKey(VkPhysicalDeviceProperties physicalDeviceProperties,
const uint8_t chunkIndex,
egl::BlobCache::Key *hashOut)
{
std::ostringstream hashStream("ANGLE Pipeline Cache: ", std::ios_base::ate);
// Add the pipeline cache UUID to make sure the blob cache always gives a compatible pipeline
// cache. It's not particularly necessary to write it as a hex number as done here, so long as
// there is no '\0' in the result.
for (const uint32_t c : physicalDeviceProperties.pipelineCacheUUID)
{
hashStream << std::hex << c;
}
// Add the vendor and device id too for good measure.
hashStream << std::hex << physicalDeviceProperties.vendorID;
hashStream << std::hex << physicalDeviceProperties.deviceID;
// Add chunkIndex to generate unique key for chunks.
hashStream << std::hex << chunkIndex;
const std::string &hashString = hashStream.str();
angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(hashString.c_str()),
hashString.length(), hashOut->data());
}
angle::Result CompressAndStorePipelineCacheVk(VkPhysicalDeviceProperties physicalDeviceProperties,
DisplayVk *displayVk,
angle::MemoryBuffer *pipelineCacheData,
bool *success)
{
// Compress the whole pipelineCache.
angle::MemoryBuffer compressedData;
ANGLE_VK_CHECK(displayVk, egl::CompressBlobCacheData(pipelineCacheData, &compressedData),
VK_ERROR_INITIALIZATION_FAILED);
// If the size of compressedData is larger than (kMaxBlobCacheSize - sizeof(numChunks)),
// the pipelineCache still can't be stored in blob cache. Divide the large compressed
// pipelineCache into several parts to store seperately. There is no function to
// query the limit size in android.
constexpr size_t kMaxBlobCacheSize = 64 * 1024;
// Store {numChunks, chunkCompressedData} in keyData, numChunks is used to validate the data.
// For example, if the compressed size is 68841 bytes(67k), divide into {2,34421 bytes} and
// {2,34420 bytes}.
constexpr size_t kBlobHeaderSize = sizeof(uint8_t);
size_t compressedOffset = 0;
const size_t numChunks = UnsignedCeilDivide(static_cast<unsigned int>(compressedData.size()),
kMaxBlobCacheSize - kBlobHeaderSize);
size_t chunkSize = UnsignedCeilDivide(static_cast<unsigned int>(compressedData.size()),
static_cast<unsigned int>(numChunks));
for (size_t chunkIndex = 0; chunkIndex < numChunks; ++chunkIndex)
{
if (chunkIndex == numChunks - 1)
{
chunkSize = compressedData.size() - compressedOffset;
}
angle::MemoryBuffer keyData;
ANGLE_VK_CHECK(displayVk, keyData.resize(kBlobHeaderSize + chunkSize),
VK_ERROR_INITIALIZATION_FAILED);
ASSERT(numChunks <= UINT8_MAX);
keyData.data()[0] = static_cast<uint8_t>(numChunks);
memcpy(keyData.data() + kBlobHeaderSize, compressedData.data() + compressedOffset,
chunkSize);
compressedOffset += chunkSize;
// Create unique hash key.
egl::BlobCache::Key chunkCacheHash;
ComputePipelineCacheVkChunkKey(physicalDeviceProperties, chunkIndex, &chunkCacheHash);
displayVk->getBlobCache()->putApplication(chunkCacheHash, keyData);
}
*success = true;
return angle::Result::Continue;
}
angle::Result GetAndDecompressPipelineCacheVk(VkPhysicalDeviceProperties physicalDeviceProperties,
DisplayVk *displayVk,
angle::MemoryBuffer *uncompressedData,
bool *success)
{
// Compute the hash key of chunkIndex 0 and find the first cache data in blob cache.
egl::BlobCache::Key chunkCacheHash;
ComputePipelineCacheVkChunkKey(physicalDeviceProperties, 0, &chunkCacheHash);
egl::BlobCache::Value keyData;
size_t keySize = 0;
constexpr size_t kBlobHeaderSize = sizeof(uint8_t);
if (!displayVk->getBlobCache()->get(displayVk->getScratchBuffer(), chunkCacheHash, &keyData,
&keySize) ||
keyData.size() < kBlobHeaderSize)
{
return angle::Result::Continue;
}
// Get the number of chunks.
size_t numChunks = keyData.data()[0];
size_t chunkSize = keySize - kBlobHeaderSize;
size_t compressedSize = 0;
// Allocate enough memory.
angle::MemoryBuffer compressedData;
ANGLE_VK_CHECK(displayVk, compressedData.resize(chunkSize * numChunks),
VK_ERROR_INITIALIZATION_FAILED);
// To combine the parts of the pipelineCache data.
for (size_t chunkIndex = 0; chunkIndex < numChunks; ++chunkIndex)
{
// Get the unique key by chunkIndex.
ComputePipelineCacheVkChunkKey(physicalDeviceProperties, chunkIndex, &chunkCacheHash);
if (!displayVk->getBlobCache()->get(displayVk->getScratchBuffer(), chunkCacheHash, &keyData,
&keySize) ||
keyData.size() < kBlobHeaderSize)
{
// Can't find every part of the cache data.
return angle::Result::Continue;
}
size_t checkNumber = keyData.data()[0];
chunkSize = keySize - kBlobHeaderSize;
if (checkNumber != numChunks || compressedData.size() < (compressedSize + chunkSize))
{
// Validate the number value and enough space to store.
return angle::Result::Continue;
}
memcpy(compressedData.data() + compressedSize, keyData.data() + kBlobHeaderSize, chunkSize);
compressedSize += chunkSize;
}
ANGLE_VK_CHECK(
displayVk,
egl::DecompressBlobCacheData(compressedData.data(), compressedSize, uncompressedData),
VK_ERROR_INITIALIZATION_FAILED);
*success = true;
return angle::Result::Continue;
}
// Environment variable (and associated Android property) to enable Vulkan debug-utils markers // Environment variable (and associated Android property) to enable Vulkan debug-utils markers
constexpr char kEnableDebugMarkersVarName[] = "ANGLE_ENABLE_DEBUG_MARKERS"; constexpr char kEnableDebugMarkersVarName[] = "ANGLE_ENABLE_DEBUG_MARKERS";
constexpr char kEnableDebugMarkersPropertyName[] = "debug.angle.markers"; constexpr char kEnableDebugMarkersPropertyName[] = "debug.angle.markers";
...@@ -2291,19 +2150,41 @@ void RendererVk::initFeatures(DisplayVk *displayVk, ...@@ -2291,19 +2150,41 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
ApplyFeatureOverrides(&mFeatures, displayVk->getState()); ApplyFeatureOverrides(&mFeatures, displayVk->getState());
} }
void RendererVk::initPipelineCacheVkKey()
{
std::ostringstream hashStream("ANGLE Pipeline Cache: ", std::ios_base::ate);
// Add the pipeline cache UUID to make sure the blob cache always gives a compatible pipeline
// cache. It's not particularly necessary to write it as a hex number as done here, so long as
// there is no '\0' in the result.
for (const uint32_t c : mPhysicalDeviceProperties.pipelineCacheUUID)
{
hashStream << std::hex << c;
}
// Add the vendor and device id too for good measure.
hashStream << std::hex << mPhysicalDeviceProperties.vendorID;
hashStream << std::hex << mPhysicalDeviceProperties.deviceID;
const std::string &hashString = hashStream.str();
angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(hashString.c_str()),
hashString.length(), mPipelineCacheVkBlobKey.data());
}
angle::Result RendererVk::initPipelineCache(DisplayVk *display, angle::Result RendererVk::initPipelineCache(DisplayVk *display,
vk::PipelineCache *pipelineCache, vk::PipelineCache *pipelineCache,
bool *success) bool *success)
{ {
angle::MemoryBuffer initialData; initPipelineCacheVkKey();
ANGLE_TRY(
GetAndDecompressPipelineCacheVk(mPhysicalDeviceProperties, display, &initialData, success)); egl::BlobCache::Value initialData;
size_t dataSize = 0;
*success = display->getBlobCache()->get(display->getScratchBuffer(), mPipelineCacheVkBlobKey,
&initialData, &dataSize);
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {}; VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {};
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
pipelineCacheCreateInfo.flags = 0; pipelineCacheCreateInfo.flags = 0;
pipelineCacheCreateInfo.initialDataSize = *success ? initialData.size() : 0; pipelineCacheCreateInfo.initialDataSize = *success ? dataSize : 0;
pipelineCacheCreateInfo.pInitialData = *success ? initialData.data() : nullptr; pipelineCacheCreateInfo.pInitialData = *success ? initialData.data() : nullptr;
ANGLE_VK_TRY(display, pipelineCache->init(mDevice, pipelineCacheCreateInfo)); ANGLE_VK_TRY(display, pipelineCache->init(mDevice, pipelineCacheCreateInfo));
...@@ -2438,14 +2319,8 @@ angle::Result RendererVk::syncPipelineCacheVk(DisplayVk *displayVk) ...@@ -2438,14 +2319,8 @@ angle::Result RendererVk::syncPipelineCacheVk(DisplayVk *displayVk)
pipelineCacheData->size() - pipelineCacheSize); pipelineCacheData->size() - pipelineCacheSize);
} }
bool success = false; displayVk->getBlobCache()->putApplication(mPipelineCacheVkBlobKey, *pipelineCacheData);
ANGLE_TRY(CompressAndStorePipelineCacheVk(mPhysicalDeviceProperties, displayVk, mPipelineCacheDirty = false;
pipelineCacheData, &success));
if (success)
{
mPipelineCacheDirty = false;
}
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -376,6 +376,7 @@ class RendererVk : angle::NonCopyable ...@@ -376,6 +376,7 @@ class RendererVk : angle::NonCopyable
void queryDeviceExtensionFeatures(const vk::ExtensionNameList &deviceExtensionNames); void queryDeviceExtensionFeatures(const vk::ExtensionNameList &deviceExtensionNames);
void initFeatures(DisplayVk *display, const vk::ExtensionNameList &extensions); void initFeatures(DisplayVk *display, const vk::ExtensionNameList &extensions);
void initPipelineCacheVkKey();
angle::Result initPipelineCache(DisplayVk *display, angle::Result initPipelineCache(DisplayVk *display,
vk::PipelineCache *pipelineCache, vk::PipelineCache *pipelineCache,
bool *success); bool *success);
...@@ -444,6 +445,7 @@ class RendererVk : angle::NonCopyable ...@@ -444,6 +445,7 @@ class RendererVk : angle::NonCopyable
// a lock. // a lock.
std::mutex mPipelineCacheMutex; std::mutex mPipelineCacheMutex;
vk::PipelineCache mPipelineCache; vk::PipelineCache mPipelineCache;
egl::BlobCache::Key mPipelineCacheVkBlobKey;
uint32_t mPipelineCacheVkUpdateTimeout; uint32_t mPipelineCacheVkUpdateTimeout;
bool mPipelineCacheDirty; bool mPipelineCacheDirty;
bool mPipelineCacheInitialized; bool mPipelineCacheInitialized;
......
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