mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
Removal of WFI + address device creation crash on A6xx
This commit is contained in:
@@ -855,36 +855,53 @@ jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDri
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
namespace {
|
||||
|
||||
struct SystemDriverInfo {
|
||||
VkPhysicalDeviceProperties properties{};
|
||||
VkPhysicalDeviceDriverProperties driver{};
|
||||
};
|
||||
|
||||
SystemDriverInfo QuerySystemDriverInfo(JNIEnv* env, jstring j_hook_lib_dir) {
|
||||
const std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir);
|
||||
const Common::DynamicLibrary library{adrenotools_open_libvulkan(
|
||||
RTLD_NOW, 0, nullptr, hook_lib_dir.c_str(), nullptr, nullptr, nullptr, nullptr)};
|
||||
Vulkan::vk::InstanceDispatch dld;
|
||||
const Vulkan::vk::Instance instance = Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);
|
||||
const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
|
||||
if (devices.empty()) {
|
||||
throw Vulkan::vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
|
||||
}
|
||||
SystemDriverInfo info{};
|
||||
info.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
|
||||
VkPhysicalDeviceProperties2 properties2{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
.pNext = &info.driver,
|
||||
.properties = {},
|
||||
};
|
||||
Vulkan::vk::PhysicalDevice(devices[0], dld).GetProperties2(properties2);
|
||||
info.properties = properties2.properties;
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
|
||||
JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) {
|
||||
std::string version_string{"1.1.0"};
|
||||
std::string driver_name{"generic"};
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
const char* file_redirect_dir_{};
|
||||
int featureFlags{};
|
||||
std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir);
|
||||
auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
|
||||
nullptr, nullptr, file_redirect_dir_, nullptr);
|
||||
auto driver_library = std::make_shared<Common::DynamicLibrary>(handle);
|
||||
InputCommon::InputSubsystem input_subsystem;
|
||||
auto window =
|
||||
std::make_unique<EmuWindow_Android>(ANativeWindow_fromSurface(env, j_surf), driver_library);
|
||||
|
||||
Vulkan::vk::InstanceDispatch dld;
|
||||
Vulkan::vk::Instance vk_instance = Vulkan::CreateInstance(
|
||||
*driver_library, dld, VK_API_VERSION_1_1, Core::Frontend::WindowSystemType::Android);
|
||||
|
||||
auto surface = Vulkan::CreateSurface(vk_instance, window->GetWindowInfo());
|
||||
|
||||
auto device = Vulkan::CreateDevice(vk_instance, dld, *surface);
|
||||
|
||||
auto driver_version = device.GetDriverVersion();
|
||||
auto version_string =
|
||||
fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version),
|
||||
VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version));
|
||||
auto driver_name = device.GetDriverName();
|
||||
#else
|
||||
auto driver_version = "1.0.0";
|
||||
auto version_string = "1.1.0"; //Assume lowest Vulkan level
|
||||
auto driver_name = "generic";
|
||||
try {
|
||||
const SystemDriverInfo info = QuerySystemDriverInfo(env, j_hook_lib_dir);
|
||||
const u32 driver_version = info.properties.driverVersion;
|
||||
version_string =
|
||||
fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version),
|
||||
VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version));
|
||||
driver_name = Vulkan::vk::GetDriverName(info.driver);
|
||||
} catch (...) {
|
||||
}
|
||||
#endif
|
||||
jobjectArray j_driver_info = env->NewObjectArray(2, Common::Android::GetStringClass(), Common::Android::ToJString(env, version_string));
|
||||
env->SetObjectArrayElement(j_driver_info, 1, Common::Android::ToJString(env, driver_name));
|
||||
@@ -893,32 +910,12 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
|
||||
|
||||
jstring Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getGpuModel(JNIEnv *env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) {
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
const char* file_redirect_dir_{};
|
||||
int featureFlags{};
|
||||
std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir);
|
||||
auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
|
||||
nullptr, nullptr, file_redirect_dir_, nullptr);
|
||||
auto driver_library = std::make_shared<Common::DynamicLibrary>(handle);
|
||||
InputCommon::InputSubsystem input_subsystem;
|
||||
auto window =
|
||||
std::make_unique<EmuWindow_Android>(ANativeWindow_fromSurface(env, j_surf), driver_library);
|
||||
|
||||
Vulkan::vk::InstanceDispatch dld;
|
||||
Vulkan::vk::Instance vk_instance = Vulkan::CreateInstance(
|
||||
*driver_library, dld, VK_API_VERSION_1_1, Core::Frontend::WindowSystemType::Android);
|
||||
|
||||
auto surface = Vulkan::CreateSurface(vk_instance, window->GetWindowInfo());
|
||||
|
||||
auto device = Vulkan::CreateDevice(vk_instance, dld, *surface);
|
||||
|
||||
const std::string model_name{device.GetModelName()};
|
||||
|
||||
window.release();
|
||||
|
||||
return Common::Android::ToJString(env, model_name);
|
||||
#else
|
||||
return Common::Android::ToJString(env, "no-info");
|
||||
try {
|
||||
return Common::Android::ToJString(env, QuerySystemDriverInfo(env, j_hook_lib_dir).properties.deviceName);
|
||||
} catch (...) {
|
||||
}
|
||||
#endif
|
||||
return Common::Android::ToJString(env, "no-info");
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) {
|
||||
|
||||
@@ -92,7 +92,8 @@ void Bilinear(std::span<const f32> input, std::span<f32> output, size_t src_widt
|
||||
|
||||
const auto read_src = [&](f32 in_x, f32 in_y) {
|
||||
const size_t read_from =
|
||||
((static_cast<size_t>(in_x) * src_width + static_cast<size_t>(in_y)) >> 32) *
|
||||
((std::min)(static_cast<size_t>(in_y), src_height - 1) * src_width +
|
||||
(std::min)(static_cast<size_t>(in_x), src_width - 1)) *
|
||||
ir_components;
|
||||
return std::span<const f32>(&input[read_from], ir_components);
|
||||
};
|
||||
|
||||
@@ -226,8 +226,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
descriptor_buffer_ring, render_pass_cache, buffer_cache, texture_cache,
|
||||
gpu.ShaderNotify()),
|
||||
accelerate_dma(buffer_cache, texture_cache, scheduler),
|
||||
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
|
||||
wfi_event(device.GetLogical().CreateEvent()) {
|
||||
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler) {
|
||||
scheduler.SetQueryCache(query_cache);
|
||||
}
|
||||
|
||||
@@ -881,45 +880,7 @@ void RasterizerVulkan::FlushAndInvalidateRegion(DAddr addr, u64 size,
|
||||
}
|
||||
|
||||
void RasterizerVulkan::WaitForIdle() {
|
||||
// Everything but wait pixel operations. This intentionally includes FRAGMENT_SHADER_BIT because
|
||||
// fragment shaders can still write storage buffers.
|
||||
VkPipelineStageFlags2 flags =
|
||||
VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT |
|
||||
VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_2_TRANSFER_BIT;
|
||||
if (device.IsExtTransformFeedbackSupported()) {
|
||||
flags |= VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT;
|
||||
}
|
||||
|
||||
query_cache.NotifyWFI();
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([event = *wfi_event, flags](vk::CommandBuffer cmdbuf) {
|
||||
const VkMemoryBarrier2 barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = flags,
|
||||
.srcAccessMask = VK_ACCESS_2_NONE,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_NONE,
|
||||
};
|
||||
const VkDependencyInfo dependency_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
|
||||
.pNext = nullptr,
|
||||
.dependencyFlags = 0,
|
||||
.memoryBarrierCount = 1,
|
||||
.pMemoryBarriers = &barrier,
|
||||
.bufferMemoryBarrierCount = 0,
|
||||
.pBufferMemoryBarriers = nullptr,
|
||||
.imageMemoryBarrierCount = 0,
|
||||
.pImageMemoryBarriers = nullptr,
|
||||
};
|
||||
cmdbuf.SetEvent(event, dependency_info);
|
||||
cmdbuf.WaitEvents(event, dependency_info);
|
||||
});
|
||||
fence_manager.SignalOrdering();
|
||||
}
|
||||
|
||||
|
||||
@@ -221,7 +221,6 @@ private:
|
||||
AccelerateDMA accelerate_dma;
|
||||
FenceManager fence_manager;
|
||||
|
||||
vk::Event wfi_event;
|
||||
|
||||
boost::container::static_vector<u32, MAX_IMAGE_VIEWS> image_view_indices;
|
||||
std::array<VideoCommon::ImageViewId, MAX_IMAGE_VIEWS> image_view_ids;
|
||||
|
||||
@@ -125,13 +125,11 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkCmdSetDepthBias);
|
||||
X(vkCmdSetDepthBias2EXT);
|
||||
X(vkCmdSetDepthBounds);
|
||||
X(vkCmdSetEvent2);
|
||||
X(vkCmdSetScissor);
|
||||
X(vkCmdSetStencilCompareMask);
|
||||
X(vkCmdSetStencilReference);
|
||||
X(vkCmdSetStencilWriteMask);
|
||||
X(vkCmdSetViewport);
|
||||
X(vkCmdWaitEvents2);
|
||||
X(vkCmdBindVertexBuffers2EXT);
|
||||
X(vkCmdSetCullModeEXT);
|
||||
X(vkCmdSetDepthBoundsTestEnableEXT);
|
||||
@@ -168,7 +166,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkCreateDescriptorPool);
|
||||
X(vkCreateDescriptorSetLayout);
|
||||
X(vkCreateDescriptorUpdateTemplate);
|
||||
X(vkCreateEvent);
|
||||
X(vkCreateFence);
|
||||
X(vkCreateFramebuffer);
|
||||
X(vkCreateGraphicsPipelines);
|
||||
@@ -187,7 +184,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkDestroyDescriptorPool);
|
||||
X(vkDestroyDescriptorSetLayout);
|
||||
X(vkDestroyDescriptorUpdateTemplate);
|
||||
X(vkDestroyEvent);
|
||||
X(vkDestroyFence);
|
||||
X(vkDestroyFramebuffer);
|
||||
X(vkDestroyImage);
|
||||
@@ -208,7 +204,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkGetBufferMemoryRequirements2);
|
||||
X(vkGetDeviceBufferMemoryRequirements);
|
||||
X(vkGetDeviceQueue);
|
||||
X(vkGetEventStatus);
|
||||
X(vkGetFenceStatus);
|
||||
X(vkGetPipelineCacheData);
|
||||
X(vkGetQueryPoolResults);
|
||||
@@ -261,12 +256,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
if (!dld.vkQueueSubmit2) {
|
||||
Proc(dld.vkQueueSubmit2, dld, "vkQueueSubmit2KHR", device);
|
||||
}
|
||||
if (!dld.vkCmdSetEvent2) {
|
||||
Proc(dld.vkCmdSetEvent2, dld, "vkCmdSetEvent2KHR", device);
|
||||
}
|
||||
if (!dld.vkCmdWaitEvents2) {
|
||||
Proc(dld.vkCmdWaitEvents2, dld, "vkCmdWaitEvents2KHR", device);
|
||||
}
|
||||
|
||||
if (!dld.vkCreateRenderPass2) {
|
||||
Proc(dld.vkCreateRenderPass2, dld, "vkCreateRenderPass2KHR", device);
|
||||
@@ -361,10 +350,6 @@ void Destroy(VkDevice device, VkDescriptorUpdateTemplate handle,
|
||||
dld.vkDestroyDescriptorUpdateTemplate(device, handle, nullptr);
|
||||
}
|
||||
|
||||
void Destroy(VkDevice device, VkEvent handle, const DeviceDispatch& dld) noexcept {
|
||||
dld.vkDestroyEvent(device, handle, nullptr);
|
||||
}
|
||||
|
||||
void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept {
|
||||
dld.vkDestroyFence(device, handle, nullptr);
|
||||
}
|
||||
@@ -590,10 +575,6 @@ std::vector<VkImage> SwapchainKHR::GetImages() const {
|
||||
return images;
|
||||
}
|
||||
|
||||
void Event::SetObjectNameEXT(const char* name) const {
|
||||
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_EVENT, name);
|
||||
}
|
||||
|
||||
void ShaderModule::SetObjectNameEXT(const char* name) const {
|
||||
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SHADER_MODULE, name);
|
||||
}
|
||||
@@ -753,18 +734,6 @@ ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) cons
|
||||
return ShaderModule(object, handle, *dld);
|
||||
}
|
||||
|
||||
Event Device::CreateEvent() const {
|
||||
static constexpr VkEventCreateInfo ci{
|
||||
.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
VkEvent object;
|
||||
Check(dld->vkCreateEvent(handle, &ci, nullptr, &object));
|
||||
return Event(object, handle, *dld);
|
||||
}
|
||||
|
||||
SwapchainKHR Device::CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const {
|
||||
VkSwapchainKHR object;
|
||||
Check(dld->vkCreateSwapchainKHR(handle, &ci, nullptr, &object));
|
||||
|
||||
@@ -255,7 +255,6 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT{};
|
||||
PFN_vkCmdSetLogicOpEnableEXT vkCmdSetLogicOpEnableEXT{};
|
||||
PFN_vkCmdSetDepthClampEnableEXT vkCmdSetDepthClampEnableEXT{};
|
||||
PFN_vkCmdSetEvent2 vkCmdSetEvent2{};
|
||||
PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{};
|
||||
PFN_vkCmdSetLogicOpEXT vkCmdSetLogicOpEXT{};
|
||||
PFN_vkCmdSetLineWidth vkCmdSetLineWidth{};
|
||||
@@ -272,7 +271,6 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkCmdSetColorWriteEnableEXT vkCmdSetColorWriteEnableEXT{};
|
||||
PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT{};
|
||||
PFN_vkCmdSetColorBlendEquationEXT vkCmdSetColorBlendEquationEXT{};
|
||||
PFN_vkCmdWaitEvents2 vkCmdWaitEvents2{};
|
||||
PFN_vkCreateBuffer vkCreateBuffer{};
|
||||
PFN_vkCreateBufferView vkCreateBufferView{};
|
||||
PFN_vkCreateCommandPool vkCreateCommandPool{};
|
||||
@@ -280,7 +278,6 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkCreateDescriptorPool vkCreateDescriptorPool{};
|
||||
PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout{};
|
||||
PFN_vkCreateDescriptorUpdateTemplate vkCreateDescriptorUpdateTemplate{};
|
||||
PFN_vkCreateEvent vkCreateEvent{};
|
||||
PFN_vkCreateFence vkCreateFence{};
|
||||
PFN_vkCreateFramebuffer vkCreateFramebuffer{};
|
||||
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines{};
|
||||
@@ -299,7 +296,6 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool{};
|
||||
PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout{};
|
||||
PFN_vkDestroyDescriptorUpdateTemplate vkDestroyDescriptorUpdateTemplate{};
|
||||
PFN_vkDestroyEvent vkDestroyEvent{};
|
||||
PFN_vkDestroyFence vkDestroyFence{};
|
||||
PFN_vkDestroyFramebuffer vkDestroyFramebuffer{};
|
||||
PFN_vkDestroyImage vkDestroyImage{};
|
||||
@@ -320,7 +316,6 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2{};
|
||||
PFN_vkGetDeviceBufferMemoryRequirements vkGetDeviceBufferMemoryRequirements{};
|
||||
PFN_vkGetDeviceQueue vkGetDeviceQueue{};
|
||||
PFN_vkGetEventStatus vkGetEventStatus{};
|
||||
PFN_vkGetFenceStatus vkGetFenceStatus{};
|
||||
PFN_vkGetPipelineCacheData vkGetPipelineCacheData{};
|
||||
PFN_vkGetPipelineExecutablePropertiesKHR vkGetPipelineExecutablePropertiesKHR{};
|
||||
@@ -361,7 +356,6 @@ void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;
|
||||
void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;
|
||||
void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept;
|
||||
void Destroy(VkDevice, VkDescriptorUpdateTemplate, const DeviceDispatch&) noexcept;
|
||||
void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept;
|
||||
void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept;
|
||||
void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept;
|
||||
void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept;
|
||||
@@ -908,18 +902,6 @@ public:
|
||||
std::vector<VkImage> GetImages() const;
|
||||
};
|
||||
|
||||
class Event : public Handle<VkEvent, VkDevice, DeviceDispatch> {
|
||||
using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle;
|
||||
|
||||
public:
|
||||
/// Set object name.
|
||||
void SetObjectNameEXT(const char* name) const;
|
||||
|
||||
VkResult GetStatus() const noexcept {
|
||||
return dld->vkGetEventStatus(owner, handle);
|
||||
}
|
||||
};
|
||||
|
||||
class ShaderModule : public Handle<VkShaderModule, VkDevice, DeviceDispatch> {
|
||||
using Handle<VkShaderModule, VkDevice, DeviceDispatch>::Handle;
|
||||
|
||||
@@ -1032,8 +1014,6 @@ public:
|
||||
|
||||
[[nodiscard]] ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
|
||||
|
||||
[[nodiscard]] Event CreateEvent() const;
|
||||
|
||||
[[nodiscard]] SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
|
||||
|
||||
VkMemoryRequirements GetDeviceBufferMemoryRequirements(const VkBufferCreateInfo& ci) const noexcept;
|
||||
@@ -1445,14 +1425,6 @@ public:
|
||||
dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds);
|
||||
}
|
||||
|
||||
void SetEvent(VkEvent event, const VkDependencyInfo& dependency_info) const noexcept {
|
||||
dld->vkCmdSetEvent2(handle, event, &dependency_info);
|
||||
}
|
||||
|
||||
void WaitEvents(Span<VkEvent> events, const VkDependencyInfo& dependency_info) const noexcept {
|
||||
dld->vkCmdWaitEvents2(handle, events.size(), events.data(), &dependency_info);
|
||||
}
|
||||
|
||||
void BindVertexBuffers2EXT(u32 first_binding, u32 binding_count, const VkBuffer* buffers,
|
||||
const VkDeviceSize* offsets, const VkDeviceSize* sizes,
|
||||
const VkDeviceSize* strides) const noexcept {
|
||||
|
||||
Reference in New Issue
Block a user