Create VkImage before importing external memory
This CL is part of a chain of CLs that imports dma-bufs as VkImages to support WebGPU on Chrome OS. There are currently two steps for importing external memory into Vulkan: 1. DeviceVk::ImportExternalImage: calls into MemoryServiceOpaqueFD::ImportMemory which in turn calls into vkAllocateMemory and outputs a VkDeviceMemory handle to the imported memory. 2. TextureVk::CreateFromExternal: creates the actual TextureVk object, creates the VkImage, and binds the VkDeviceMemory from ImportExternalImage to the VkImage. For dma-buf support, however, we need to re-order these two steps because importing dma-buf memory requires a handle to the VkImage that will alias it [1]. This CL splits these two steps into three steps to ensure we create the VkImage first so we can use it in vkAllocateMemory: 1. TextureVk::CreateFromExternal: creates the TextureVk and VkImage (no longer concerns itself with vkBindImageMemory). 2. DeviceVk::ImportExternalImage: now takes the VkImage as input but is otherwise unchanged. 3. TextureVk::BindExternalMemory: calls vkBindImageMemory with handles to VkDeviceMemory and VkImage. [1] https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkMemoryDedicatedAllocateInfo.html BUG=chromium:996470 Change-Id: Id2d5951e9b573af79c44ce8c63be5210a279f946 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13780 Commit-Queue: Brian Ho <hob@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
02dd733454
commit
756a9d7e49
|
@ -595,6 +595,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
MaybeError Device::ImportExternalImage(const ExternalImageDescriptor* descriptor,
|
MaybeError Device::ImportExternalImage(const ExternalImageDescriptor* descriptor,
|
||||||
ExternalMemoryHandle memoryHandle,
|
ExternalMemoryHandle memoryHandle,
|
||||||
|
VkImage image,
|
||||||
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
||||||
VkSemaphore* outSignalSemaphore,
|
VkSemaphore* outSignalSemaphore,
|
||||||
VkDeviceMemory* outAllocation,
|
VkDeviceMemory* outAllocation,
|
||||||
|
@ -620,9 +621,11 @@ namespace dawn_native { namespace vulkan {
|
||||||
mExternalSemaphoreService->CreateExportableSemaphore());
|
mExternalSemaphoreService->CreateExportableSemaphore());
|
||||||
|
|
||||||
// Import the external image's memory
|
// Import the external image's memory
|
||||||
|
external_memory::MemoryImportParams importParams;
|
||||||
|
DAWN_TRY_ASSIGN(importParams,
|
||||||
|
mExternalMemoryService->GetMemoryImportParams(descriptor, image));
|
||||||
DAWN_TRY_ASSIGN(*outAllocation,
|
DAWN_TRY_ASSIGN(*outAllocation,
|
||||||
mExternalMemoryService->ImportMemory(
|
mExternalMemoryService->ImportMemory(memoryHandle, importParams, image));
|
||||||
memoryHandle, descriptor->allocationSize, descriptor->memoryTypeIndex));
|
|
||||||
|
|
||||||
// Import semaphores we have to wait on before using the texture
|
// Import semaphores we have to wait on before using the texture
|
||||||
for (const ExternalSemaphoreHandle& handle : waitHandles) {
|
for (const ExternalSemaphoreHandle& handle : waitHandles) {
|
||||||
|
@ -671,11 +674,19 @@ namespace dawn_native { namespace vulkan {
|
||||||
// Cleanup in case of a failure, the image creation doesn't acquire the external objects
|
// Cleanup in case of a failure, the image creation doesn't acquire the external objects
|
||||||
// if a failure happems.
|
// if a failure happems.
|
||||||
Texture* result = nullptr;
|
Texture* result = nullptr;
|
||||||
if (ConsumedError(ImportExternalImage(descriptor, memoryHandle, waitHandles,
|
// TODO(crbug.com/1026480): Consolidate this into a single CreateFromExternal call.
|
||||||
&signalSemaphore, &allocation, &waitSemaphores)) ||
|
if (ConsumedError(Texture::CreateFromExternal(this, descriptor, textureDescriptor),
|
||||||
ConsumedError(Texture::CreateFromExternal(this, descriptor, textureDescriptor,
|
&result) ||
|
||||||
signalSemaphore, allocation, waitSemaphores),
|
ConsumedError(ImportExternalImage(descriptor, memoryHandle, result->GetHandle(),
|
||||||
&result)) {
|
waitHandles, &signalSemaphore, &allocation,
|
||||||
|
&waitSemaphores)) ||
|
||||||
|
ConsumedError(result->BindExternalMemory(descriptor, signalSemaphore, allocation,
|
||||||
|
waitSemaphores))) {
|
||||||
|
// Delete the Texture if it was created
|
||||||
|
if (result != nullptr) {
|
||||||
|
delete result;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear the signal semaphore
|
// Clear the signal semaphore
|
||||||
fn.DestroySemaphore(GetVkDevice(), signalSemaphore, nullptr);
|
fn.DestroySemaphore(GetVkDevice(), signalSemaphore, nullptr);
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
MaybeError ImportExternalImage(const ExternalImageDescriptor* descriptor,
|
MaybeError ImportExternalImage(const ExternalImageDescriptor* descriptor,
|
||||||
ExternalMemoryHandle memoryHandle,
|
ExternalMemoryHandle memoryHandle,
|
||||||
|
VkImage image,
|
||||||
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
const std::vector<ExternalSemaphoreHandle>& waitHandles,
|
||||||
VkSemaphore* outSignalSemaphore,
|
VkSemaphore* outSignalSemaphore,
|
||||||
VkDeviceMemory* outAllocation,
|
VkDeviceMemory* outAllocation,
|
||||||
|
|
|
@ -406,16 +406,13 @@ namespace dawn_native { namespace vulkan {
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
ResultOrError<Texture*> Texture::CreateFromExternal(Device* device,
|
ResultOrError<Texture*> Texture::CreateFromExternal(
|
||||||
|
Device* device,
|
||||||
const ExternalImageDescriptor* descriptor,
|
const ExternalImageDescriptor* descriptor,
|
||||||
const TextureDescriptor* textureDescriptor,
|
const TextureDescriptor* textureDescriptor) {
|
||||||
VkSemaphore signalSemaphore,
|
|
||||||
VkDeviceMemory externalMemoryAllocation,
|
|
||||||
std::vector<VkSemaphore> waitSemaphores) {
|
|
||||||
std::unique_ptr<Texture> texture =
|
std::unique_ptr<Texture> texture =
|
||||||
std::make_unique<Texture>(device, textureDescriptor, TextureState::OwnedInternal);
|
std::make_unique<Texture>(device, textureDescriptor, TextureState::OwnedInternal);
|
||||||
DAWN_TRY(texture->InitializeFromExternal(
|
DAWN_TRY(texture->InitializeFromExternal(descriptor));
|
||||||
descriptor, signalSemaphore, externalMemoryAllocation, std::move((waitSemaphores))));
|
|
||||||
return texture.release();
|
return texture.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,10 +481,7 @@ namespace dawn_native { namespace vulkan {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internally managed, but imported from external handle
|
// Internally managed, but imported from external handle
|
||||||
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor,
|
MaybeError Texture::InitializeFromExternal(const ExternalImageDescriptor* descriptor) {
|
||||||
VkSemaphore signalSemaphore,
|
|
||||||
VkDeviceMemory externalMemoryAllocation,
|
|
||||||
std::vector<VkSemaphore> waitSemaphores) {
|
|
||||||
mExternalState = ExternalState::PendingAcquire;
|
mExternalState = ExternalState::PendingAcquire;
|
||||||
Device* device = ToBackend(GetDevice());
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
|
@ -519,7 +513,14 @@ namespace dawn_native { namespace vulkan {
|
||||||
device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
|
device->fn.CreateImage(device->GetVkDevice(), &createInfo, nullptr, &mHandle),
|
||||||
"CreateImage"));
|
"CreateImage"));
|
||||||
|
|
||||||
// Create the image memory and associate it with the container
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeError Texture::BindExternalMemory(const ExternalImageDescriptor* descriptor,
|
||||||
|
VkSemaphore signalSemaphore,
|
||||||
|
VkDeviceMemory externalMemoryAllocation,
|
||||||
|
std::vector<VkSemaphore> waitSemaphores) {
|
||||||
|
Device* device = ToBackend(GetDevice());
|
||||||
VkMemoryRequirements requirements;
|
VkMemoryRequirements requirements;
|
||||||
device->fn.GetImageMemoryRequirements(device->GetVkDevice(), mHandle, &requirements);
|
device->fn.GetImageMemoryRequirements(device->GetVkDevice(), mHandle, &requirements);
|
||||||
|
|
||||||
|
@ -538,7 +539,6 @@ namespace dawn_native { namespace vulkan {
|
||||||
mExternalAllocation = externalMemoryAllocation;
|
mExternalAllocation = externalMemoryAllocation;
|
||||||
mSignalSemaphore = signalSemaphore;
|
mSignalSemaphore = signalSemaphore;
|
||||||
mWaitRequirements = std::move(waitSemaphores);
|
mWaitRequirements = std::move(waitSemaphores);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,16 +39,13 @@ namespace dawn_native { namespace vulkan {
|
||||||
// Used to create a regular texture from a descriptor.
|
// Used to create a regular texture from a descriptor.
|
||||||
static ResultOrError<Texture*> Create(Device* device, const TextureDescriptor* descriptor);
|
static ResultOrError<Texture*> Create(Device* device, const TextureDescriptor* descriptor);
|
||||||
|
|
||||||
// Used to create a texture from Vulkan external memory objects.
|
// Creates a texture and initializes it with a VkImage that references an external memory
|
||||||
// Ownership of semaphores and the memory allocation is taken only if the creation is
|
// object. Before the texture can be used, the VkDeviceMemory associated with the external
|
||||||
// a success.
|
// image must be bound via Texture::BindExternalMemory.
|
||||||
static ResultOrError<Texture*> CreateFromExternal(
|
static ResultOrError<Texture*> CreateFromExternal(
|
||||||
Device* device,
|
Device* device,
|
||||||
const ExternalImageDescriptor* descriptor,
|
const ExternalImageDescriptor* descriptor,
|
||||||
const TextureDescriptor* textureDescriptor,
|
const TextureDescriptor* textureDescriptor);
|
||||||
VkSemaphore signalSemaphore,
|
|
||||||
VkDeviceMemory externalMemoryAllocation,
|
|
||||||
std::vector<VkSemaphore> waitSemaphores);
|
|
||||||
|
|
||||||
Texture(Device* device, const TextureDescriptor* descriptor, VkImage nativeImage);
|
Texture(Device* device, const TextureDescriptor* descriptor, VkImage nativeImage);
|
||||||
~Texture();
|
~Texture();
|
||||||
|
@ -68,14 +65,18 @@ namespace dawn_native { namespace vulkan {
|
||||||
uint32_t layerCount);
|
uint32_t layerCount);
|
||||||
|
|
||||||
MaybeError SignalAndDestroy(VkSemaphore* outSignalSemaphore);
|
MaybeError SignalAndDestroy(VkSemaphore* outSignalSemaphore);
|
||||||
|
// Binds externally allocated memory to the VkImage and on success, takes ownership of
|
||||||
|
// semaphores.
|
||||||
|
MaybeError BindExternalMemory(const ExternalImageDescriptor* descriptor,
|
||||||
|
VkSemaphore signalSemaphore,
|
||||||
|
VkDeviceMemory externalMemoryAllocation,
|
||||||
|
std::vector<VkSemaphore> waitSemaphores);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using TextureBase::TextureBase;
|
using TextureBase::TextureBase;
|
||||||
MaybeError InitializeAsInternalTexture();
|
MaybeError InitializeAsInternalTexture();
|
||||||
MaybeError InitializeFromExternal(const ExternalImageDescriptor* descriptor,
|
|
||||||
VkSemaphore signalSemaphore,
|
MaybeError InitializeFromExternal(const ExternalImageDescriptor* descriptor);
|
||||||
VkDeviceMemory externalMemoryAllocation,
|
|
||||||
std::vector<VkSemaphore> waitSemaphores);
|
|
||||||
|
|
||||||
void DestroyImpl() override;
|
void DestroyImpl() override;
|
||||||
MaybeError ClearTexture(CommandRecordingContext* recordingContext,
|
MaybeError ClearTexture(CommandRecordingContext* recordingContext,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "common/vulkan_platform.h"
|
#include "common/vulkan_platform.h"
|
||||||
#include "dawn_native/Error.h"
|
#include "dawn_native/Error.h"
|
||||||
|
#include "dawn_native/VulkanBackend.h"
|
||||||
#include "dawn_native/vulkan/ExternalHandle.h"
|
#include "dawn_native/vulkan/ExternalHandle.h"
|
||||||
|
|
||||||
namespace dawn_native { namespace vulkan {
|
namespace dawn_native { namespace vulkan {
|
||||||
|
@ -25,6 +26,11 @@ namespace dawn_native { namespace vulkan {
|
||||||
|
|
||||||
namespace dawn_native { namespace vulkan { namespace external_memory {
|
namespace dawn_native { namespace vulkan { namespace external_memory {
|
||||||
|
|
||||||
|
struct MemoryImportParams {
|
||||||
|
VkDeviceSize allocationSize;
|
||||||
|
uint32_t memoryTypeIndex;
|
||||||
|
};
|
||||||
|
|
||||||
class Service {
|
class Service {
|
||||||
public:
|
public:
|
||||||
explicit Service(Device* device);
|
explicit Service(Device* device);
|
||||||
|
@ -37,10 +43,15 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
||||||
VkImageUsageFlags usage,
|
VkImageUsageFlags usage,
|
||||||
VkImageCreateFlags flags);
|
VkImageCreateFlags flags);
|
||||||
|
|
||||||
|
// Returns the parameters required for importing memory
|
||||||
|
ResultOrError<MemoryImportParams> GetMemoryImportParams(
|
||||||
|
const ExternalImageDescriptor* descriptor,
|
||||||
|
VkImage image);
|
||||||
|
|
||||||
// Given an external handle pointing to memory, import it into a VkDeviceMemory
|
// Given an external handle pointing to memory, import it into a VkDeviceMemory
|
||||||
ResultOrError<VkDeviceMemory> ImportMemory(ExternalMemoryHandle handle,
|
ResultOrError<VkDeviceMemory> ImportMemory(ExternalMemoryHandle handle,
|
||||||
VkDeviceSize allocationSize,
|
const MemoryImportParams& importParams,
|
||||||
uint32_t memoryTypeIndex);
|
VkImage image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Device* mDevice = nullptr;
|
Device* mDevice = nullptr;
|
||||||
|
|
|
@ -32,10 +32,16 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
|
||||||
|
const ExternalImageDescriptor* descriptor,
|
||||||
|
VkImage image) {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("Using null memory service to interop inside Vulkan");
|
||||||
|
}
|
||||||
|
|
||||||
ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
|
ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
|
||||||
VkDeviceSize allocationSize,
|
const MemoryImportParams& importParams,
|
||||||
uint32_t memoryTypeIndex) {
|
VkImage image) {
|
||||||
return DAWN_UNIMPLEMENTED_ERROR("Using null semaphore service to interop inside Vulkan");
|
return DAWN_UNIMPLEMENTED_ERROR("Using null memory service to interop inside Vulkan");
|
||||||
}
|
}
|
||||||
|
|
||||||
}}} // namespace dawn_native::vulkan::external_memory
|
}}} // namespace dawn_native::vulkan::external_memory
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "common/Assert.h"
|
||||||
#include "dawn_native/vulkan/AdapterVk.h"
|
#include "dawn_native/vulkan/AdapterVk.h"
|
||||||
#include "dawn_native/vulkan/BackendVk.h"
|
#include "dawn_native/vulkan/BackendVk.h"
|
||||||
#include "dawn_native/vulkan/DeviceVk.h"
|
#include "dawn_native/vulkan/DeviceVk.h"
|
||||||
|
@ -79,9 +80,16 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
||||||
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
|
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
|
||||||
|
const ExternalImageDescriptor* descriptor,
|
||||||
|
VkImage image) {
|
||||||
|
MemoryImportParams params = {descriptor->allocationSize, descriptor->memoryTypeIndex};
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
|
ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
|
||||||
VkDeviceSize allocationSize,
|
const MemoryImportParams& importParams,
|
||||||
uint32_t memoryTypeIndex) {
|
VkImage image) {
|
||||||
if (handle < 0) {
|
if (handle < 0) {
|
||||||
return DAWN_VALIDATION_ERROR("Trying to import memory with invalid handle");
|
return DAWN_VALIDATION_ERROR("Trying to import memory with invalid handle");
|
||||||
}
|
}
|
||||||
|
@ -95,8 +103,8 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
||||||
VkMemoryAllocateInfo allocateInfo;
|
VkMemoryAllocateInfo allocateInfo;
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
allocateInfo.pNext = &importMemoryFdInfo;
|
allocateInfo.pNext = &importMemoryFdInfo;
|
||||||
allocateInfo.allocationSize = allocationSize;
|
allocateInfo.allocationSize = importParams.allocationSize;
|
||||||
allocateInfo.memoryTypeIndex = memoryTypeIndex;
|
allocateInfo.memoryTypeIndex = importParams.memoryTypeIndex;
|
||||||
|
|
||||||
VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
|
VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
|
||||||
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,
|
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "common/Assert.h"
|
||||||
#include "dawn_native/vulkan/AdapterVk.h"
|
#include "dawn_native/vulkan/AdapterVk.h"
|
||||||
#include "dawn_native/vulkan/BackendVk.h"
|
#include "dawn_native/vulkan/BackendVk.h"
|
||||||
#include "dawn_native/vulkan/DeviceVk.h"
|
#include "dawn_native/vulkan/DeviceVk.h"
|
||||||
|
@ -79,9 +80,16 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
||||||
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
|
!(memoryFlags & VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultOrError<MemoryImportParams> Service::GetMemoryImportParams(
|
||||||
|
const ExternalImageDescriptor* descriptor,
|
||||||
|
VkImage image) {
|
||||||
|
MemoryImportParams params = {descriptor->allocationSize, descriptor->memoryTypeIndex};
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
|
ResultOrError<VkDeviceMemory> Service::ImportMemory(ExternalMemoryHandle handle,
|
||||||
VkDeviceSize allocationSize,
|
const MemoryImportParams& importParams,
|
||||||
uint32_t memoryTypeIndex) {
|
VkImage image) {
|
||||||
if (handle == ZX_HANDLE_INVALID) {
|
if (handle == ZX_HANDLE_INVALID) {
|
||||||
return DAWN_VALIDATION_ERROR("Trying to import memory with invalid handle");
|
return DAWN_VALIDATION_ERROR("Trying to import memory with invalid handle");
|
||||||
}
|
}
|
||||||
|
@ -97,8 +105,8 @@ namespace dawn_native { namespace vulkan { namespace external_memory {
|
||||||
VkMemoryAllocateInfo allocateInfo;
|
VkMemoryAllocateInfo allocateInfo;
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
allocateInfo.pNext = &importMemoryHandleInfo;
|
allocateInfo.pNext = &importMemoryHandleInfo;
|
||||||
allocateInfo.allocationSize = allocationSize;
|
allocateInfo.allocationSize = importParams.allocationSize;
|
||||||
allocateInfo.memoryTypeIndex = memoryTypeIndex;
|
allocateInfo.memoryTypeIndex = importParams.memoryTypeIndex;
|
||||||
|
|
||||||
VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
|
VkDeviceMemory allocatedMemory = VK_NULL_HANDLE;
|
||||||
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,
|
DAWN_TRY(CheckVkSuccess(mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo,
|
||||||
|
|
Loading…
Reference in New Issue