зеркало из https://github.com/AvaloniaUI/angle.git
Vulkan: Add support for VkPipelineCache
The cache is initialized from the application's blob cache and is occasionally written back to it for disk storage. Bug: angleproject:2516 Change-Id: I4cba4b00a7b9641c2983ef07159bc62cd10a5519 Reviewed-on: https://chromium-review.googlesource.com/1241373 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Yuly Novikov <ynovikov@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Родитель
5ddbdbf70c
Коммит
996628a4a1
2
BUILD.gn
2
BUILD.gn
|
@ -956,7 +956,7 @@ if (is_android) {
|
|||
}
|
||||
android_apk("angle_apk") {
|
||||
deps = [
|
||||
":angle_apk_assets"
|
||||
":angle_apk_assets",
|
||||
]
|
||||
if (build_apk_secondary_abi && android_64bit_target_cpu) {
|
||||
secondary_abi_shared_libraries = [
|
||||
|
|
|
@ -15,10 +15,6 @@ namespace angle
|
|||
{
|
||||
|
||||
// MemoryBuffer implementation.
|
||||
MemoryBuffer::MemoryBuffer() : mSize(0), mData(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryBuffer::~MemoryBuffer()
|
||||
{
|
||||
free(mData);
|
||||
|
|
|
@ -20,7 +20,8 @@ namespace angle
|
|||
class MemoryBuffer final : NonCopyable
|
||||
{
|
||||
public:
|
||||
MemoryBuffer();
|
||||
MemoryBuffer() = default;
|
||||
MemoryBuffer(size_t size) { resize(size); }
|
||||
~MemoryBuffer();
|
||||
|
||||
MemoryBuffer(MemoryBuffer &&other);
|
||||
|
@ -51,8 +52,8 @@ class MemoryBuffer final : NonCopyable
|
|||
void fill(uint8_t datum);
|
||||
|
||||
private:
|
||||
size_t mSize;
|
||||
uint8_t *mData;
|
||||
size_t mSize = 0;
|
||||
uint8_t *mData = nullptr;
|
||||
};
|
||||
|
||||
class ScratchBuffer final : NonCopyable
|
||||
|
|
|
@ -52,6 +52,14 @@ void BlobCache::put(const BlobCache::Key &key, angle::MemoryBuffer &&value)
|
|||
}
|
||||
}
|
||||
|
||||
void BlobCache::putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value)
|
||||
{
|
||||
if (areBlobCacheFuncsSet())
|
||||
{
|
||||
mSetBlobFunc(key.data(), key.size(), value.data(), value.size());
|
||||
}
|
||||
}
|
||||
|
||||
void BlobCache::populate(const BlobCache::Key &key, angle::MemoryBuffer &&value, CacheSource source)
|
||||
{
|
||||
CacheEntry newEntry;
|
||||
|
@ -66,7 +74,7 @@ void BlobCache::populate(const BlobCache::Key &key, angle::MemoryBuffer &&value,
|
|||
}
|
||||
}
|
||||
|
||||
bool BlobCache::get(const gl::Context *context,
|
||||
bool BlobCache::get(angle::ScratchBuffer *scratchBuffer,
|
||||
const BlobCache::Key &key,
|
||||
BlobCache::Value *valueOut)
|
||||
{
|
||||
|
@ -79,19 +87,19 @@ bool BlobCache::get(const gl::Context *context,
|
|||
return false;
|
||||
}
|
||||
|
||||
angle::MemoryBuffer *scratchBuffer;
|
||||
bool result = context->getScratchBuffer(valueSize, &scratchBuffer);
|
||||
angle::MemoryBuffer *scratchMemory;
|
||||
bool result = scratchBuffer->get(valueSize, &scratchMemory);
|
||||
if (!result)
|
||||
{
|
||||
ERR() << "Failed to allocate memory for binary blob";
|
||||
return false;
|
||||
}
|
||||
|
||||
valueSize = mGetBlobFunc(key.data(), key.size(), scratchBuffer->data(), valueSize);
|
||||
valueSize = mGetBlobFunc(key.data(), key.size(), scratchMemory->data(), valueSize);
|
||||
|
||||
// Make sure the key/value pair still exists/is unchanged after the second call
|
||||
// (modifications to the application cache by another thread are a possibility)
|
||||
if (static_cast<size_t>(valueSize) != scratchBuffer->size())
|
||||
if (static_cast<size_t>(valueSize) != scratchMemory->size())
|
||||
{
|
||||
// This warning serves to find issues with the application cache, none of which are
|
||||
// currently known to be thread-safe. If such a use ever arises, this WARN can be
|
||||
|
@ -100,7 +108,7 @@ bool BlobCache::get(const gl::Context *context,
|
|||
return false;
|
||||
}
|
||||
|
||||
*valueOut = BlobCache::Value(scratchBuffer->data(), scratchBuffer->size());
|
||||
*valueOut = BlobCache::Value(scratchMemory->data(), scratchMemory->size());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class BlobCache final : angle::NonCopyable
|
|||
Value(const uint8_t *ptr, size_t sz) : mPtr(ptr), mSize(sz) {}
|
||||
|
||||
// A very basic struct to hold the pointer and size together. The objects of this class
|
||||
// doesn't own the memory.
|
||||
// don't own the memory.
|
||||
const uint8_t *data() { return mPtr; }
|
||||
size_t size() { return mSize; }
|
||||
|
||||
|
@ -88,6 +88,9 @@ class BlobCache final : angle::NonCopyable
|
|||
// will be used. Otherwise the value is cached in this object.
|
||||
void put(const BlobCache::Key &key, angle::MemoryBuffer &&value);
|
||||
|
||||
// Store a key-blob pair in the application cache, only if application callbacks are set.
|
||||
void putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value);
|
||||
|
||||
// Store a key-blob pair in the cache without making callbacks to the application. This is used
|
||||
// to repopulate this object's cache on startup without generating callback calls.
|
||||
void populate(const BlobCache::Key &key,
|
||||
|
@ -96,10 +99,14 @@ class BlobCache final : angle::NonCopyable
|
|||
|
||||
// Check if the cache contains the blob corresponding to this key. If application callbacks are
|
||||
// set, those will be used. Otherwise they key is looked up in this object's cache.
|
||||
bool get(const gl::Context *context, const BlobCache::Key &key, BlobCache::Value *valueOut);
|
||||
ANGLE_NO_DISCARD bool get(angle::ScratchBuffer *scratchBuffer,
|
||||
const BlobCache::Key &key,
|
||||
BlobCache::Value *valueOut);
|
||||
|
||||
// For querying the contents of the cache.
|
||||
bool getAt(size_t index, const BlobCache::Key **keyOut, BlobCache::Value *valueOut);
|
||||
ANGLE_NO_DISCARD bool getAt(size_t index,
|
||||
const BlobCache::Key **keyOut,
|
||||
BlobCache::Value *valueOut);
|
||||
|
||||
// Evict a blob from the binary cache.
|
||||
void remove(const BlobCache::Key &key);
|
||||
|
|
|
@ -1543,6 +1543,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
|
|||
angle::MemoryBuffer **scratchBufferOut) const;
|
||||
ANGLE_NO_DISCARD bool getZeroFilledBuffer(size_t requstedSizeBytes,
|
||||
angle::MemoryBuffer **zeroBufferOut) const;
|
||||
angle::ScratchBuffer *getScratchBuffer() const { return &mScratchBuffer; }
|
||||
|
||||
Error prepareForDispatch();
|
||||
|
||||
|
|
|
@ -447,6 +447,8 @@ void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap
|
|||
|
||||
Error Display::initialize()
|
||||
{
|
||||
mImplementation->setBlobCache(&mBlobCache);
|
||||
|
||||
// TODO(jmadill): Store Platform in Display and init here.
|
||||
const angle::PlatformMethods *platformMethods =
|
||||
reinterpret_cast<const angle::PlatformMethods *>(
|
||||
|
|
|
@ -113,13 +113,13 @@ namespace angle
|
|||
{
|
||||
Result::operator gl::Error() const
|
||||
{
|
||||
if (mStop)
|
||||
{
|
||||
return gl::Error(GL_INTERNAL_ERROR_ANGLEX);
|
||||
}
|
||||
else
|
||||
if (mResult == ResultValue::kContinue)
|
||||
{
|
||||
return gl::NoError();
|
||||
}
|
||||
else
|
||||
{
|
||||
return gl::Error(GL_INTERNAL_ERROR_ANGLEX);
|
||||
}
|
||||
}
|
||||
} // namespace angle
|
||||
|
|
|
@ -241,16 +241,15 @@ inline Error NoError()
|
|||
|
||||
// TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/2491
|
||||
#define ANGLE_TRY_HANDLE(CONTEXT, EXPR) \
|
||||
\
|
||||
{ \
|
||||
{ \
|
||||
auto ANGLE_LOCAL_VAR = (EXPR); \
|
||||
if (ANGLE_UNLIKELY(ANGLE_LOCAL_VAR.isError())) \
|
||||
{ \
|
||||
CONTEXT->handleError(ANGLE_LOCAL_VAR); \
|
||||
return angle::Result::Stop(); \
|
||||
} \
|
||||
\
|
||||
}
|
||||
} \
|
||||
ANGLE_EMPTY_STATEMENT
|
||||
|
||||
#define ANGLE_TRY_RESULT(EXPR, RESULT) \
|
||||
{ \
|
||||
|
@ -281,15 +280,20 @@ inline Error NoError()
|
|||
namespace angle
|
||||
{
|
||||
// Result signals if calling code should continue running or early exit. A value of Stop() can
|
||||
// either indicate and Error or a non-Error early exit condition such as a detected no-op.
|
||||
// either indicate an Error or a non-Error early exit condition such as a detected no-op. A few
|
||||
// other values exist to signal special cases that are neither success nor failure but require
|
||||
// special attention.
|
||||
class ANGLE_NO_DISCARD Result
|
||||
{
|
||||
public:
|
||||
// TODO(jmadill): Rename when refactor is complete. http://anglebug.com/2491
|
||||
bool isError() const { return mStop; }
|
||||
bool isError() const { return mResult == ResultValue::kStop; }
|
||||
Result getError() { return *this; }
|
||||
Result getResult() { return *this; }
|
||||
|
||||
static Result Stop() { return Result(true); }
|
||||
static Result Continue() { return Result(false); }
|
||||
static Result Continue() { return Result(ResultValue::kContinue); }
|
||||
static Result Stop() { return Result(ResultValue::kStop); }
|
||||
static Result Incomplete() { return Result(ResultValue::kIncomplete); }
|
||||
|
||||
// TODO(jmadill): Remove when refactor is complete. http://anglebug.com/2491
|
||||
operator gl::Error() const;
|
||||
|
@ -301,13 +305,20 @@ class ANGLE_NO_DISCARD Result
|
|||
return operator gl::Error();
|
||||
}
|
||||
|
||||
bool operator==(Result other) const { return mStop == other.mStop; }
|
||||
bool operator==(Result other) const { return mResult == other.mResult; }
|
||||
|
||||
bool operator!=(Result other) const { return mStop != other.mStop; }
|
||||
bool operator!=(Result other) const { return mResult != other.mResult; }
|
||||
|
||||
private:
|
||||
Result(bool stop) : mStop(stop) {}
|
||||
bool mStop;
|
||||
enum class ResultValue
|
||||
{
|
||||
kContinue = 0,
|
||||
kStop,
|
||||
kIncomplete,
|
||||
};
|
||||
|
||||
Result(ResultValue stop) : mResult(stop) {}
|
||||
ResultValue mResult;
|
||||
};
|
||||
} // namespace angle
|
||||
|
||||
|
|
|
@ -681,7 +681,7 @@ bool MemoryProgramCache::get(const Context *context,
|
|||
const egl::BlobCache::Key &programHash,
|
||||
egl::BlobCache::Value *programOut)
|
||||
{
|
||||
return mBlobCache.get(context, programHash, programOut);
|
||||
return mBlobCache.get(context->getScratchBuffer(), programHash, programOut);
|
||||
}
|
||||
|
||||
bool MemoryProgramCache::getAt(size_t index,
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace rx
|
|||
{
|
||||
|
||||
DisplayImpl::DisplayImpl(const egl::DisplayState &state)
|
||||
: mState(state), mExtensionsInitialized(false), mCapsInitialized(false)
|
||||
: mState(state), mExtensionsInitialized(false), mCapsInitialized(false), mBlobCache(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
namespace egl
|
||||
{
|
||||
class AttributeMap;
|
||||
class BlobCache;
|
||||
class Display;
|
||||
struct DisplayState;
|
||||
struct Config;
|
||||
|
@ -79,6 +80,9 @@ class DisplayImpl : public EGLImplFactory
|
|||
|
||||
const egl::DisplayExtensions &getExtensions() const;
|
||||
|
||||
void setBlobCache(egl::BlobCache *blobCache) { mBlobCache = blobCache; }
|
||||
egl::BlobCache *getBlobCache() const { return mBlobCache; }
|
||||
|
||||
protected:
|
||||
const egl::DisplayState &mState;
|
||||
|
||||
|
@ -91,6 +95,8 @@ class DisplayImpl : public EGLImplFactory
|
|||
|
||||
mutable bool mCapsInitialized;
|
||||
mutable egl::Caps mCaps;
|
||||
|
||||
egl::BlobCache *mBlobCache;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -150,6 +150,8 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
|
|||
mDirtyBits = mNewCommandBufferDirtyBits;
|
||||
}
|
||||
|
||||
#undef INIT
|
||||
|
||||
ContextVk::~ContextVk() = default;
|
||||
|
||||
void ContextVk::onDestroy(const gl::Context *context)
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace rx
|
|||
{
|
||||
|
||||
DisplayVk::DisplayVk(const egl::DisplayState &state)
|
||||
: DisplayImpl(state), vk::Context(new RendererVk())
|
||||
: DisplayImpl(state), vk::Context(new RendererVk()), mScratchBuffer(1000u)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -181,6 +181,12 @@ void DisplayVk::generateCaps(egl::Caps *outCaps) const
|
|||
outCaps->textureNPOT = true;
|
||||
}
|
||||
|
||||
bool DisplayVk::getScratchBuffer(size_t requstedSizeBytes,
|
||||
angle::MemoryBuffer **scratchBufferOut) const
|
||||
{
|
||||
return mScratchBuffer.get(requstedSizeBytes, scratchBufferOut);
|
||||
}
|
||||
|
||||
void DisplayVk::handleError(VkResult result, const char *file, unsigned int line)
|
||||
{
|
||||
std::stringstream errorStream;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef LIBANGLE_RENDERER_VULKAN_DISPLAYVK_H_
|
||||
#define LIBANGLE_RENDERER_VULKAN_DISPLAYVK_H_
|
||||
|
||||
#include "common/MemoryBuffer.h"
|
||||
#include "libANGLE/renderer/DisplayImpl.h"
|
||||
#include "libANGLE/renderer/vulkan/vk_utils.h"
|
||||
|
||||
|
@ -74,6 +75,10 @@ class DisplayVk : public DisplayImpl, public vk::Context
|
|||
// returning a bool to indicate if the config should be supported.
|
||||
virtual bool checkConfigSupport(egl::Config *config) = 0;
|
||||
|
||||
ANGLE_NO_DISCARD bool getScratchBuffer(size_t requestedSizeBytes,
|
||||
angle::MemoryBuffer **scratchBufferOut) const;
|
||||
angle::ScratchBuffer *getScratchBuffer() const { return &mScratchBuffer; }
|
||||
|
||||
void handleError(VkResult result, const char *file, unsigned int line) override;
|
||||
|
||||
// TODO(jmadill): Remove this once refactor is done. http://anglebug.com/2491
|
||||
|
@ -87,6 +92,8 @@ class DisplayVk : public DisplayImpl, public vk::Context
|
|||
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
|
||||
void generateCaps(egl::Caps *outCaps) const override;
|
||||
|
||||
mutable angle::ScratchBuffer mScratchBuffer;
|
||||
|
||||
std::string mStoredErrorString;
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libANGLE/renderer/driver_utils.h"
|
||||
#include "libANGLE/renderer/vulkan/CommandGraph.h"
|
||||
#include "libANGLE/renderer/vulkan/CompilerVk.h"
|
||||
#include "libANGLE/renderer/vulkan/DisplayVk.h"
|
||||
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
|
||||
#include "libANGLE/renderer/vulkan/GlslangWrapper.h"
|
||||
#include "libANGLE/renderer/vulkan/ProgramVk.h"
|
||||
|
@ -44,6 +45,8 @@ namespace
|
|||
// We currently only allocate 2 uniform buffer per descriptor set, one for the fragment shader and
|
||||
// one for the vertex shader.
|
||||
constexpr size_t kUniformBufferDescriptorsPerDescriptorSet = 2;
|
||||
// Update the pipeline cache every this many swaps (if 60fps, this means every 10 minutes)
|
||||
static constexpr uint32_t kPipelineCacheVkUpdatePeriod = 10 * 60 * 60;
|
||||
|
||||
bool ShouldEnableMockICD(const egl::AttributeMap &attribs)
|
||||
{
|
||||
|
@ -295,7 +298,8 @@ RendererVk::RendererVk()
|
|||
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
|
||||
mDevice(VK_NULL_HANDLE),
|
||||
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
|
||||
mCurrentQueueSerial(mQueueSerialFactory.generate())
|
||||
mCurrentQueueSerial(mQueueSerialFactory.generate()),
|
||||
mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -316,6 +320,7 @@ void RendererVk::onDestroy(vk::Context *context)
|
|||
|
||||
mRenderPassCache.destroy(mDevice);
|
||||
mPipelineCache.destroy(mDevice);
|
||||
mPipelineCacheVk.destroy(mDevice);
|
||||
mShaderLibrary.destroy(mDevice);
|
||||
|
||||
GlslangWrapper::Release();
|
||||
|
@ -350,7 +355,7 @@ void RendererVk::onDestroy(vk::Context *context)
|
|||
mPhysicalDevice = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
angle::Result RendererVk::initialize(vk::Context *context,
|
||||
angle::Result RendererVk::initialize(DisplayVk *displayVk,
|
||||
const egl::AttributeMap &attribs,
|
||||
const char *wsiName)
|
||||
{
|
||||
|
@ -361,24 +366,25 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
|
||||
// Gather global layer properties.
|
||||
uint32_t instanceLayerCount = 0;
|
||||
ANGLE_VK_TRY(context, vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr));
|
||||
ANGLE_VK_TRY(displayVk, vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr));
|
||||
|
||||
std::vector<VkLayerProperties> instanceLayerProps(instanceLayerCount);
|
||||
if (instanceLayerCount > 0)
|
||||
{
|
||||
ANGLE_VK_TRY(context, vkEnumerateInstanceLayerProperties(&instanceLayerCount,
|
||||
instanceLayerProps.data()));
|
||||
ANGLE_VK_TRY(displayVk, vkEnumerateInstanceLayerProperties(&instanceLayerCount,
|
||||
instanceLayerProps.data()));
|
||||
}
|
||||
|
||||
uint32_t instanceExtensionCount = 0;
|
||||
ANGLE_VK_TRY(context,
|
||||
ANGLE_VK_TRY(displayVk,
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, nullptr));
|
||||
|
||||
std::vector<VkExtensionProperties> instanceExtensionProps(instanceExtensionCount);
|
||||
if (instanceExtensionCount > 0)
|
||||
{
|
||||
ANGLE_VK_TRY(context, vkEnumerateInstanceExtensionProperties(
|
||||
nullptr, &instanceExtensionCount, instanceExtensionProps.data()));
|
||||
ANGLE_VK_TRY(displayVk,
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount,
|
||||
instanceExtensionProps.data()));
|
||||
}
|
||||
|
||||
const char *const *enabledLayerNames = nullptr;
|
||||
|
@ -402,7 +408,7 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
}
|
||||
|
||||
// Verify the required extensions are in the extension names set. Fail if not.
|
||||
ANGLE_VK_TRY(context,
|
||||
ANGLE_VK_TRY(displayVk,
|
||||
VerifyExtensionsPresent(instanceExtensionProps, enabledInstanceExtensions));
|
||||
|
||||
VkApplicationInfo applicationInfo;
|
||||
|
@ -427,7 +433,7 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
instanceInfo.enabledLayerCount = enabledLayerCount;
|
||||
instanceInfo.ppEnabledLayerNames = enabledLayerNames;
|
||||
|
||||
ANGLE_VK_TRY(context, vkCreateInstance(&instanceInfo, nullptr, &mInstance));
|
||||
ANGLE_VK_TRY(displayVk, vkCreateInstance(&instanceInfo, nullptr, &mInstance));
|
||||
|
||||
if (mEnableValidationLayers)
|
||||
{
|
||||
|
@ -444,18 +450,18 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
auto createDebugReportCallback = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(
|
||||
vkGetInstanceProcAddr(mInstance, "vkCreateDebugReportCallbackEXT"));
|
||||
ASSERT(createDebugReportCallback);
|
||||
ANGLE_VK_TRY(context, createDebugReportCallback(mInstance, &debugReportInfo, nullptr,
|
||||
&mDebugReportCallback));
|
||||
ANGLE_VK_TRY(displayVk, createDebugReportCallback(mInstance, &debugReportInfo, nullptr,
|
||||
&mDebugReportCallback));
|
||||
}
|
||||
|
||||
uint32_t physicalDeviceCount = 0;
|
||||
ANGLE_VK_TRY(context, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
|
||||
ANGLE_VK_CHECK(context, physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED);
|
||||
ANGLE_VK_TRY(displayVk, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
|
||||
ANGLE_VK_CHECK(displayVk, physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED);
|
||||
|
||||
// TODO(jmadill): Handle multiple physical devices. For now, use the first device.
|
||||
std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
|
||||
ANGLE_VK_TRY(context, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount,
|
||||
physicalDevices.data()));
|
||||
ANGLE_VK_TRY(displayVk, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount,
|
||||
physicalDevices.data()));
|
||||
ChoosePhysicalDevice(physicalDevices, enableMockICD, &mPhysicalDevice,
|
||||
&mPhysicalDeviceProperties);
|
||||
|
||||
|
@ -465,7 +471,7 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
uint32_t queueCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount, nullptr);
|
||||
|
||||
ANGLE_VK_CHECK(context, queueCount > 0, VK_ERROR_INITIALIZATION_FAILED);
|
||||
ANGLE_VK_CHECK(displayVk, queueCount > 0, VK_ERROR_INITIALIZATION_FAILED);
|
||||
|
||||
mQueueFamilyProperties.resize(queueCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueCount,
|
||||
|
@ -488,7 +494,7 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
}
|
||||
}
|
||||
|
||||
ANGLE_VK_CHECK(context, graphicsQueueFamilyCount > 0, VK_ERROR_INITIALIZATION_FAILED);
|
||||
ANGLE_VK_CHECK(displayVk, graphicsQueueFamilyCount > 0, VK_ERROR_INITIALIZATION_FAILED);
|
||||
|
||||
initFeatures();
|
||||
|
||||
|
@ -496,7 +502,7 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
// queue, we'll have to wait until we see a WindowSurface to know which supports present.
|
||||
if (graphicsQueueFamilyCount == 1)
|
||||
{
|
||||
ANGLE_TRY(initializeDevice(context, firstGraphicsQueueFamily));
|
||||
ANGLE_TRY(initializeDevice(displayVk, firstGraphicsQueueFamily));
|
||||
}
|
||||
|
||||
// Store the physical device memory properties so we can find the right memory pools.
|
||||
|
@ -511,29 +517,29 @@ angle::Result RendererVk::initialize(vk::Context *context,
|
|||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
angle::Result RendererVk::initializeDevice(vk::Context *context, uint32_t queueFamilyIndex)
|
||||
angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex)
|
||||
{
|
||||
uint32_t deviceLayerCount = 0;
|
||||
ANGLE_VK_TRY(context,
|
||||
ANGLE_VK_TRY(displayVk,
|
||||
vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount, nullptr));
|
||||
|
||||
std::vector<VkLayerProperties> deviceLayerProps(deviceLayerCount);
|
||||
if (deviceLayerCount > 0)
|
||||
{
|
||||
ANGLE_VK_TRY(context, vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount,
|
||||
deviceLayerProps.data()));
|
||||
ANGLE_VK_TRY(displayVk, vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount,
|
||||
deviceLayerProps.data()));
|
||||
}
|
||||
|
||||
uint32_t deviceExtensionCount = 0;
|
||||
ANGLE_VK_TRY(context, vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
|
||||
&deviceExtensionCount, nullptr));
|
||||
ANGLE_VK_TRY(displayVk, vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
|
||||
&deviceExtensionCount, nullptr));
|
||||
|
||||
std::vector<VkExtensionProperties> deviceExtensionProps(deviceExtensionCount);
|
||||
if (deviceExtensionCount > 0)
|
||||
{
|
||||
ANGLE_VK_TRY(context, vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
|
||||
&deviceExtensionCount,
|
||||
deviceExtensionProps.data()));
|
||||
ANGLE_VK_TRY(displayVk, vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr,
|
||||
&deviceExtensionCount,
|
||||
deviceExtensionProps.data()));
|
||||
}
|
||||
|
||||
const char *const *enabledLayerNames = nullptr;
|
||||
|
@ -553,7 +559,7 @@ angle::Result RendererVk::initializeDevice(vk::Context *context, uint32_t queueF
|
|||
enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
ANGLE_VK_TRY(context, VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions));
|
||||
ANGLE_VK_TRY(displayVk, VerifyExtensionsPresent(deviceExtensionProps, enabledDeviceExtensions));
|
||||
|
||||
VkDeviceQueueCreateInfo queueCreateInfo;
|
||||
|
||||
|
@ -581,7 +587,7 @@ angle::Result RendererVk::initializeDevice(vk::Context *context, uint32_t queueF
|
|||
enabledDeviceExtensions.empty() ? nullptr : enabledDeviceExtensions.data();
|
||||
createInfo.pEnabledFeatures = nullptr; // TODO(jmadill): features
|
||||
|
||||
ANGLE_VK_TRY(context, vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
|
||||
ANGLE_VK_TRY(displayVk, vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice));
|
||||
|
||||
mCurrentQueueFamilyIndex = queueFamilyIndex;
|
||||
|
||||
|
@ -594,12 +600,15 @@ angle::Result RendererVk::initializeDevice(vk::Context *context, uint32_t queueF
|
|||
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
||||
commandPoolInfo.queueFamilyIndex = mCurrentQueueFamilyIndex;
|
||||
|
||||
ANGLE_TRY(mCommandPool.init(context, commandPoolInfo));
|
||||
ANGLE_TRY(mCommandPool.init(displayVk, commandPoolInfo));
|
||||
|
||||
// Initialize the vulkan pipeline cache
|
||||
ANGLE_TRY(initPipelineCacheVk(displayVk));
|
||||
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
angle::Result RendererVk::selectPresentQueueForSurface(vk::Context *context,
|
||||
angle::Result RendererVk::selectPresentQueueForSurface(DisplayVk *displayVk,
|
||||
VkSurfaceKHR surface,
|
||||
uint32_t *presentQueueOut)
|
||||
{
|
||||
|
@ -611,7 +620,7 @@ angle::Result RendererVk::selectPresentQueueForSurface(vk::Context *context,
|
|||
|
||||
// Check if the current device supports present on this surface.
|
||||
VkBool32 supportsPresent = VK_FALSE;
|
||||
ANGLE_VK_TRY(context,
|
||||
ANGLE_VK_TRY(displayVk,
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, mCurrentQueueFamilyIndex,
|
||||
surface, &supportsPresent));
|
||||
|
||||
|
@ -631,8 +640,8 @@ angle::Result RendererVk::selectPresentQueueForSurface(vk::Context *context,
|
|||
if ((queueInfo.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
|
||||
{
|
||||
VkBool32 supportsPresent = VK_FALSE;
|
||||
ANGLE_VK_TRY(context, vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, queueIndex,
|
||||
surface, &supportsPresent));
|
||||
ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceSupportKHR(
|
||||
mPhysicalDevice, queueIndex, surface, &supportsPresent));
|
||||
|
||||
if (supportsPresent == VK_TRUE)
|
||||
{
|
||||
|
@ -642,8 +651,8 @@ angle::Result RendererVk::selectPresentQueueForSurface(vk::Context *context,
|
|||
}
|
||||
}
|
||||
|
||||
ANGLE_VK_CHECK(context, newPresentQueue.valid(), VK_ERROR_INITIALIZATION_FAILED);
|
||||
ANGLE_TRY(initializeDevice(context, newPresentQueue.value()));
|
||||
ANGLE_VK_CHECK(displayVk, newPresentQueue.valid(), VK_ERROR_INITIALIZATION_FAILED);
|
||||
ANGLE_TRY(initializeDevice(displayVk, newPresentQueue.value()));
|
||||
|
||||
*presentQueueOut = newPresentQueue.value();
|
||||
return angle::Result::Continue();
|
||||
|
@ -701,6 +710,45 @@ void RendererVk::initFeatures()
|
|||
#endif
|
||||
}
|
||||
|
||||
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::initPipelineCacheVk(DisplayVk *display)
|
||||
{
|
||||
initPipelineCacheVkKey();
|
||||
|
||||
egl::BlobCache::Value initialData;
|
||||
bool success = display->getBlobCache()->get(display->getScratchBuffer(),
|
||||
mPipelineCacheVkBlobKey, &initialData);
|
||||
|
||||
VkPipelineCacheCreateInfo pipelineCacheCreateInfo;
|
||||
|
||||
pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
||||
pipelineCacheCreateInfo.pNext = nullptr;
|
||||
pipelineCacheCreateInfo.flags = 0;
|
||||
pipelineCacheCreateInfo.initialDataSize = success ? initialData.size() : 0;
|
||||
pipelineCacheCreateInfo.pInitialData = success ? initialData.data() : nullptr;
|
||||
|
||||
ANGLE_TRY(mPipelineCacheVk.init(display, pipelineCacheCreateInfo));
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
void RendererVk::ensureCapsInitialized() const
|
||||
{
|
||||
if (!mCapsInitialized)
|
||||
|
@ -957,8 +1005,8 @@ angle::Result RendererVk::getPipeline(vk::Context *context,
|
|||
ANGLE_TRY(
|
||||
getCompatibleRenderPass(context, pipelineDesc.getRenderPassDesc(), &compatibleRenderPass));
|
||||
|
||||
return mPipelineCache.getPipeline(context, *compatibleRenderPass, pipelineLayout,
|
||||
activeAttribLocationsMask, vertexShader.get(),
|
||||
return mPipelineCache.getPipeline(context, mPipelineCacheVk, *compatibleRenderPass,
|
||||
pipelineLayout, activeAttribLocationsMask, vertexShader.get(),
|
||||
fragmentShader.get(), pipelineDesc, pipelineOut);
|
||||
}
|
||||
|
||||
|
@ -980,6 +1028,49 @@ angle::Result RendererVk::getPipelineLayout(
|
|||
pipelineLayoutOut);
|
||||
}
|
||||
|
||||
angle::Result RendererVk::syncPipelineCacheVk(DisplayVk *displayVk)
|
||||
{
|
||||
ASSERT(mPipelineCacheVk.valid());
|
||||
|
||||
if (--mPipelineCacheVkUpdateTimeout > 0)
|
||||
{
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
mPipelineCacheVkUpdateTimeout = kPipelineCacheVkUpdatePeriod;
|
||||
|
||||
// Get the size of the cache.
|
||||
size_t pipelineCacheSize = 0;
|
||||
ANGLE_TRY(mPipelineCacheVk.getCacheData(displayVk, &pipelineCacheSize, nullptr));
|
||||
|
||||
angle::MemoryBuffer *pipelineCacheData = nullptr;
|
||||
ANGLE_VK_CHECK_ALLOC(displayVk,
|
||||
displayVk->getScratchBuffer(pipelineCacheSize, &pipelineCacheData));
|
||||
|
||||
size_t originalPipelineCacheSize = pipelineCacheSize;
|
||||
angle::Result result =
|
||||
mPipelineCacheVk.getCacheData(displayVk, &pipelineCacheSize, pipelineCacheData->data());
|
||||
ANGLE_TRY(result);
|
||||
|
||||
// Note: currently we don't accept incomplete as we don't expect it (the full size of cache
|
||||
// was determined just above), so receiving it hints at an implementation bug we would want
|
||||
// to know about early.
|
||||
ASSERT(result != angle::Result::Incomplete());
|
||||
|
||||
// If vkGetPipelineCacheData ends up writing fewer bytes than requested, zero out the rest of
|
||||
// the buffer to avoid leaking garbage memory.
|
||||
ASSERT(pipelineCacheSize <= originalPipelineCacheSize);
|
||||
if (pipelineCacheSize < originalPipelineCacheSize)
|
||||
{
|
||||
memset(pipelineCacheData->data() + pipelineCacheSize, 0,
|
||||
originalPipelineCacheSize - pipelineCacheSize);
|
||||
}
|
||||
|
||||
displayVk->getBlobCache()->putApplication(mPipelineCacheVkBlobKey, *pipelineCacheData);
|
||||
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
vk::ShaderLibrary *RendererVk::getShaderLibrary()
|
||||
{
|
||||
return &mShaderLibrary;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include "common/angleutils.h"
|
||||
#include "libANGLE/BlobCache.h"
|
||||
#include "libANGLE/Caps.h"
|
||||
#include "libANGLE/renderer/vulkan/CommandGraph.h"
|
||||
#include "libANGLE/renderer/vulkan/FeaturesVk.h"
|
||||
|
@ -23,10 +24,12 @@
|
|||
namespace egl
|
||||
{
|
||||
class AttributeMap;
|
||||
class BlobCache;
|
||||
}
|
||||
|
||||
namespace rx
|
||||
{
|
||||
class DisplayVk;
|
||||
class FramebufferVk;
|
||||
|
||||
namespace vk
|
||||
|
@ -40,7 +43,7 @@ class RendererVk : angle::NonCopyable
|
|||
RendererVk();
|
||||
~RendererVk();
|
||||
|
||||
angle::Result initialize(vk::Context *context,
|
||||
angle::Result initialize(DisplayVk *displayVk,
|
||||
const egl::AttributeMap &attribs,
|
||||
const char *wsiName);
|
||||
void onDestroy(vk::Context *context);
|
||||
|
@ -57,7 +60,7 @@ class RendererVk : angle::NonCopyable
|
|||
VkQueue getQueue() const { return mQueue; }
|
||||
VkDevice getDevice() const { return mDevice; }
|
||||
|
||||
angle::Result selectPresentQueueForSurface(vk::Context *context,
|
||||
angle::Result selectPresentQueueForSurface(DisplayVk *displayVk,
|
||||
VkSurfaceKHR surface,
|
||||
uint32_t *presentQueueOut);
|
||||
|
||||
|
@ -132,6 +135,8 @@ class RendererVk : angle::NonCopyable
|
|||
const vk::DescriptorSetLayoutPointerArray &descriptorSetLayouts,
|
||||
vk::BindingPointer<vk::PipelineLayout> *pipelineLayoutOut);
|
||||
|
||||
angle::Result syncPipelineCacheVk(DisplayVk *displayVk);
|
||||
|
||||
// This should only be called from ResourceVk.
|
||||
// TODO(jmadill): Keep in ContextVk to enable threaded rendering.
|
||||
vk::CommandGraph *getCommandGraph();
|
||||
|
@ -143,7 +148,7 @@ class RendererVk : angle::NonCopyable
|
|||
const FeaturesVk &getFeatures() const { return mFeatures; }
|
||||
|
||||
private:
|
||||
angle::Result initializeDevice(vk::Context *context, uint32_t queueFamilyIndex);
|
||||
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
|
||||
void ensureCapsInitialized() const;
|
||||
angle::Result submitFrame(vk::Context *context,
|
||||
const VkSubmitInfo &submitInfo,
|
||||
|
@ -152,6 +157,8 @@ class RendererVk : angle::NonCopyable
|
|||
void freeAllInFlightResources();
|
||||
angle::Result flushCommandGraph(vk::Context *context, vk::CommandBuffer *commandBatch);
|
||||
void initFeatures();
|
||||
void initPipelineCacheVkKey();
|
||||
angle::Result initPipelineCacheVk(DisplayVk *display);
|
||||
|
||||
mutable bool mCapsInitialized;
|
||||
mutable gl::Caps mNativeCaps;
|
||||
|
@ -198,6 +205,10 @@ class RendererVk : angle::NonCopyable
|
|||
RenderPassCache mRenderPassCache;
|
||||
PipelineCache mPipelineCache;
|
||||
|
||||
vk::PipelineCache mPipelineCacheVk;
|
||||
egl::BlobCache::Key mPipelineCacheVkBlobKey;
|
||||
uint32_t mPipelineCacheVkUpdateTimeout;
|
||||
|
||||
// See CommandGraph.h for a desription of the Command Graph.
|
||||
vk::CommandGraph mCommandGraph;
|
||||
|
||||
|
|
|
@ -588,6 +588,8 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk)
|
|||
// Get the next available swapchain image.
|
||||
ANGLE_TRY(nextSwapchainImage(displayVk));
|
||||
|
||||
ANGLE_TRY(renderer->syncPipelineCacheVk(displayVk));
|
||||
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
|
||||
|
||||
#include "common/aligned_memory.h"
|
||||
#include "libANGLE/SizedMRUCache.h"
|
||||
#include "libANGLE/BlobCache.h"
|
||||
#include "libANGLE/VertexAttribute.h"
|
||||
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
|
||||
#include "libANGLE/renderer/vulkan/ProgramVk.h"
|
||||
|
@ -436,6 +436,7 @@ void PipelineDesc::initDefaults()
|
|||
}
|
||||
|
||||
angle::Result PipelineDesc::initializePipeline(vk::Context *context,
|
||||
const vk::PipelineCache &pipelineCacheVk,
|
||||
const RenderPass &compatibleRenderPass,
|
||||
const PipelineLayout &pipelineLayout,
|
||||
const gl::AttributesMask &activeAttribLocationsMask,
|
||||
|
@ -617,7 +618,7 @@ angle::Result PipelineDesc::initializePipeline(vk::Context *context,
|
|||
createInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
createInfo.basePipelineIndex = 0;
|
||||
|
||||
ANGLE_TRY(pipelineOut->initGraphics(context, createInfo));
|
||||
ANGLE_TRY(pipelineOut->initGraphics(context, createInfo, pipelineCacheVk));
|
||||
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
@ -1125,6 +1126,7 @@ void PipelineCache::destroy(VkDevice device)
|
|||
}
|
||||
|
||||
angle::Result PipelineCache::getPipeline(vk::Context *context,
|
||||
const vk::PipelineCache &pipelineCacheVk,
|
||||
const vk::RenderPass &compatibleRenderPass,
|
||||
const vk::PipelineLayout &pipelineLayout,
|
||||
const gl::AttributesMask &activeAttribLocationsMask,
|
||||
|
@ -1145,9 +1147,9 @@ angle::Result PipelineCache::getPipeline(vk::Context *context,
|
|||
// This "if" is left here for the benefit of VulkanPipelineCachePerfTest.
|
||||
if (context != nullptr)
|
||||
{
|
||||
ANGLE_TRY(desc.initializePipeline(context, compatibleRenderPass, pipelineLayout,
|
||||
activeAttribLocationsMask, vertexModule, fragmentModule,
|
||||
&newPipeline));
|
||||
ANGLE_TRY(desc.initializePipeline(context, pipelineCacheVk, compatibleRenderPass,
|
||||
pipelineLayout, activeAttribLocationsMask, vertexModule,
|
||||
fragmentModule, &newPipeline));
|
||||
}
|
||||
|
||||
// The Serial will be updated outside of this query.
|
||||
|
|
|
@ -344,6 +344,7 @@ class PipelineDesc final
|
|||
void initDefaults();
|
||||
|
||||
angle::Result initializePipeline(vk::Context *context,
|
||||
const vk::PipelineCache &pipelineCacheVk,
|
||||
const RenderPass &compatibleRenderPass,
|
||||
const PipelineLayout &pipelineLayout,
|
||||
const gl::AttributesMask &activeAttribLocationsMask,
|
||||
|
@ -612,6 +613,7 @@ class PipelineCache final : angle::NonCopyable
|
|||
|
||||
void populate(const vk::PipelineDesc &desc, vk::Pipeline &&pipeline);
|
||||
angle::Result getPipeline(vk::Context *context,
|
||||
const vk::PipelineCache &pipelineCacheVk,
|
||||
const vk::RenderPass &compatibleRenderPass,
|
||||
const vk::PipelineLayout &pipelineLayout,
|
||||
const gl::AttributesMask &activeAttribLocationsMask,
|
||||
|
|
|
@ -826,29 +826,6 @@ angle::Result ShaderModule::init(Context *context, const VkShaderModuleCreateInf
|
|||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
// Pipeline implementation.
|
||||
Pipeline::Pipeline()
|
||||
{
|
||||
}
|
||||
|
||||
void Pipeline::destroy(VkDevice device)
|
||||
{
|
||||
if (valid())
|
||||
{
|
||||
vkDestroyPipeline(device, mHandle, nullptr);
|
||||
mHandle = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
angle::Result Pipeline::initGraphics(Context *context,
|
||||
const VkGraphicsPipelineCreateInfo &createInfo)
|
||||
{
|
||||
ASSERT(!valid());
|
||||
ANGLE_VK_TRY(context, vkCreateGraphicsPipelines(context->getDevice(), VK_NULL_HANDLE, 1,
|
||||
&createInfo, nullptr, &mHandle));
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
// PipelineLayout implementation.
|
||||
PipelineLayout::PipelineLayout()
|
||||
{
|
||||
|
@ -871,6 +848,73 @@ angle::Result PipelineLayout::init(Context *context, const VkPipelineLayoutCreat
|
|||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
// PipelineCache implementation.
|
||||
PipelineCache::PipelineCache()
|
||||
{
|
||||
}
|
||||
|
||||
void PipelineCache::destroy(VkDevice device)
|
||||
{
|
||||
if (valid())
|
||||
{
|
||||
vkDestroyPipelineCache(device, mHandle, nullptr);
|
||||
mHandle = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
angle::Result PipelineCache::init(Context *context, const VkPipelineCacheCreateInfo &createInfo)
|
||||
{
|
||||
ASSERT(!valid());
|
||||
// Note: if we are concerned with memory usage of this cache, we should give it custom
|
||||
// allocators. Also, failure of this function is of little importance.
|
||||
ANGLE_VK_TRY(context,
|
||||
vkCreatePipelineCache(context->getDevice(), &createInfo, nullptr, &mHandle));
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
angle::Result PipelineCache::getCacheData(Context *context, size_t *cacheSize, void *cacheData)
|
||||
{
|
||||
ASSERT(valid());
|
||||
|
||||
// Note: vkGetPipelineCacheData can return VK_INCOMPLETE if cacheSize is smaller than actual
|
||||
// size. There are two usages of this function. One is with *cacheSize == 0 to query the size
|
||||
// of the cache, and one is with an appropriate buffer to retrieve the cache contents.
|
||||
// VK_INCOMPLETE in the first case is an expected output. In the second case, VK_INCOMPLETE is
|
||||
// also acceptable and the resulting buffer will contain valid value by spec. Angle currently
|
||||
// ensures *cacheSize to be either 0 or of enough size, therefore VK_INCOMPLETE is not expected.
|
||||
angle::Result result = angle::Result::Stop();
|
||||
ANGLE_VK_TRY_ALLOW_INCOMPLETE(
|
||||
context, vkGetPipelineCacheData(context->getDevice(), mHandle, cacheSize, cacheData),
|
||||
result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Pipeline implementation.
|
||||
Pipeline::Pipeline()
|
||||
{
|
||||
}
|
||||
|
||||
void Pipeline::destroy(VkDevice device)
|
||||
{
|
||||
if (valid())
|
||||
{
|
||||
vkDestroyPipeline(device, mHandle, nullptr);
|
||||
mHandle = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
angle::Result Pipeline::initGraphics(Context *context,
|
||||
const VkGraphicsPipelineCreateInfo &createInfo,
|
||||
const PipelineCache &pipelineCacheVk)
|
||||
{
|
||||
ASSERT(!valid());
|
||||
ANGLE_VK_TRY(context,
|
||||
vkCreateGraphicsPipelines(context->getDevice(), pipelineCacheVk.getHandle(), 1,
|
||||
&createInfo, nullptr, &mHandle));
|
||||
return angle::Result::Continue();
|
||||
}
|
||||
|
||||
// DescriptorSetLayout implementation.
|
||||
DescriptorSetLayout::DescriptorSetLayout()
|
||||
{
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace vk
|
|||
{
|
||||
struct Format;
|
||||
|
||||
// Abstracts error handling. Implemented by both ContextVk for GL and RendererVk for EGL errors.
|
||||
// Abstracts error handling. Implemented by both ContextVk for GL and DisplayVk for EGL errors.
|
||||
class Context : angle::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
@ -531,15 +531,6 @@ class ShaderModule final : public WrappedObject<ShaderModule, VkShaderModule>
|
|||
angle::Result init(Context *context, const VkShaderModuleCreateInfo &createInfo);
|
||||
};
|
||||
|
||||
class Pipeline final : public WrappedObject<Pipeline, VkPipeline>
|
||||
{
|
||||
public:
|
||||
Pipeline();
|
||||
void destroy(VkDevice device);
|
||||
|
||||
angle::Result initGraphics(Context *context, const VkGraphicsPipelineCreateInfo &createInfo);
|
||||
};
|
||||
|
||||
class PipelineLayout final : public WrappedObject<PipelineLayout, VkPipelineLayout>
|
||||
{
|
||||
public:
|
||||
|
@ -549,6 +540,27 @@ class PipelineLayout final : public WrappedObject<PipelineLayout, VkPipelineLayo
|
|||
angle::Result init(Context *context, const VkPipelineLayoutCreateInfo &createInfo);
|
||||
};
|
||||
|
||||
class PipelineCache final : public WrappedObject<PipelineCache, VkPipelineCache>
|
||||
{
|
||||
public:
|
||||
PipelineCache();
|
||||
void destroy(VkDevice device);
|
||||
|
||||
angle::Result init(Context *context, const VkPipelineCacheCreateInfo &createInfo);
|
||||
angle::Result getCacheData(Context *context, size_t *cacheSize, void *cacheData);
|
||||
};
|
||||
|
||||
class Pipeline final : public WrappedObject<Pipeline, VkPipeline>
|
||||
{
|
||||
public:
|
||||
Pipeline();
|
||||
void destroy(VkDevice device);
|
||||
|
||||
angle::Result initGraphics(Context *context,
|
||||
const VkGraphicsPipelineCreateInfo &createInfo,
|
||||
const PipelineCache &pipelineCacheVk);
|
||||
};
|
||||
|
||||
class DescriptorSetLayout final : public WrappedObject<DescriptorSetLayout, VkDescriptorSetLayout>
|
||||
{
|
||||
public:
|
||||
|
@ -757,6 +769,19 @@ VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bo
|
|||
} \
|
||||
ANGLE_EMPTY_STATEMENT
|
||||
|
||||
#define ANGLE_VK_TRY_ALLOW_INCOMPLETE(context, command, result) \
|
||||
{ \
|
||||
auto ANGLE_LOCAL_VAR = command; \
|
||||
if (ANGLE_UNLIKELY(ANGLE_LOCAL_VAR != VK_SUCCESS && ANGLE_LOCAL_VAR != VK_INCOMPLETE)) \
|
||||
{ \
|
||||
context->handleError(ANGLE_LOCAL_VAR, __FILE__, __LINE__); \
|
||||
return angle::Result::Stop(); \
|
||||
} \
|
||||
result = ANGLE_LOCAL_VAR == VK_INCOMPLETE ? angle::Result::Incomplete() \
|
||||
: angle::Result::Continue(); \
|
||||
} \
|
||||
ANGLE_EMPTY_STATEMENT
|
||||
|
||||
#define ANGLE_VK_CHECK(context, test, error) ANGLE_VK_TRY(context, test ? VK_SUCCESS : error)
|
||||
|
||||
#define ANGLE_VK_CHECK_MATH(context, result) \
|
||||
|
|
|
@ -80,6 +80,7 @@ void VulkanPipelineCachePerfTest::step()
|
|||
{
|
||||
vk::RenderPass rp;
|
||||
vk::PipelineLayout pl;
|
||||
vk::PipelineCache pc;
|
||||
vk::ShaderModule sm;
|
||||
vk::PipelineAndSerial *result = nullptr;
|
||||
gl::AttributesMask am;
|
||||
|
@ -88,7 +89,7 @@ void VulkanPipelineCachePerfTest::step()
|
|||
{
|
||||
for (const auto &hit : mCacheHits)
|
||||
{
|
||||
(void)mCache.getPipeline(VK_NULL_HANDLE, rp, pl, am, sm, sm, hit, &result);
|
||||
(void)mCache.getPipeline(VK_NULL_HANDLE, pc, rp, pl, am, sm, sm, hit, &result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +97,7 @@ void VulkanPipelineCachePerfTest::step()
|
|||
++missCount, ++mMissIndex)
|
||||
{
|
||||
const auto &miss = mCacheMisses[mMissIndex];
|
||||
(void)mCache.getPipeline(VK_NULL_HANDLE, rp, pl, am, sm, sm, miss, &result);
|
||||
(void)mCache.getPipeline(VK_NULL_HANDLE, pc, rp, pl, am, sm, sm, miss, &result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче