【问题标题】:NullPointerException when manually loading required Vulkan instance extensions手动加载所需的 Vulkan 实例扩展时出现 NullPointerException
【发布时间】:2021-09-01 04:05:02
【问题描述】:

我目前正在通过 LWJGL 使用 Vulkan 开发 Win32 应用程序,当我运行以下代码时,

            String className = "Hello Window App";
            ByteBuffer classNameBuffer = stack.UTF16(className);
            WindowProc defaultWndProc = new WindowProc() {
                public long invoke(long hwnd, int uMsg, long wParam, long lParam) {
                    if (uMsg == User32.WM_DESTROY) {
                        User32.DestroyWindow(hwnd);
                        System.exit(0);
                    } else if (uMsg == User32.WM_PAINT) {
                    } 
                    return User32.DefWindowProc(hwnd, uMsg, wParam, lParam);
                }
            };
            WNDCLASSEX wc = WNDCLASSEX.callocStack(stack);
            wc.cbSize(WNDCLASSEX.SIZEOF);
            wc.hInstance(WindowsLibrary.HINSTANCE);
            wc.lpszClassName(classNameBuffer);
            wc.lpfnWndProc(defaultWndProc);
            User32.RegisterClassEx(wc);
            hwnd = User32.CreateWindowEx(User32.WS_EX_APPWINDOW, className, "Hello Windows App",
                    User32.WS_OVERLAPPEDWINDOW, 100, 100, 640, 480, 0, 0, WindowsLibrary.HINSTANCE, 0);
            if (hwnd == 0) {
                throw new RuntimeException("Unable to create Window");
            }
            User32.ShowWindow(hwnd, User32.SW_SHOW);
            User32.SetCursorPos(0, 0);
            MSG msg = MSG.callocStack(stack);
            //GLFW.glfwInit();
            PointerBuffer ppEnabledLayerNames = null; // We'll add support for validation layers later
            // PointerBuffer windowExtensions = GLFWVulkan.glfwGetRequiredInstanceExtensions();
            PointerBuffer windowExtensions = MemoryUtil.memAllocPointer(2);
            windowExtensions.put(MemoryUtil.memASCII(KHRSurface.VK_KHR_SURFACE_EXTENSION_NAME));
            windowExtensions.put(MemoryUtil.memASCII(KHRWin32Surface.VK_KHR_WIN32_SURFACE_EXTENSION_NAME));
            PointerBuffer ppEnabledExtensionNames = windowExtensions;
            VkApplicationInfo value = VkApplicationInfo.mallocStack(stack);
            value.sType(VK11.VK_STRUCTURE_TYPE_APPLICATION_INFO);
            value.pNext(0L);
            value.pApplicationName(stack.UTF8Safe("Game"));
            value.pEngineName(stack.UTF8Safe("engine"));
            value.apiVersion(VK11.VK_MAKE_VERSION(1, 1, 0));
            VkInstanceCreateInfo pCreateInfo = VkInstanceCreateInfo.mallocStack(stack);
            pCreateInfo.sType(VK11.VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
            pCreateInfo.pNext(0L);
            pCreateInfo.flags(0);
            pCreateInfo.pApplicationInfo(value);
            pCreateInfo.ppEnabledLayerNames(ppEnabledLayerNames);
            pCreateInfo.ppEnabledExtensionNames(ppEnabledExtensionNames);
            PointerBuffer pInstance = stack.mallocPointer(1);
            if (VK11.vkCreateInstance(pCreateInfo, null, pInstance) != VK11.VK_SUCCESS) {
            }
            instance = new VkInstance(pInstance.get(0), pCreateInfo);

            VkWin32SurfaceCreateInfoKHR sfc = VkWin32SurfaceCreateInfoKHR.calloc();
            sfc.hinstance(WindowsLibrary.HINSTANCE).hwnd(hwnd)
                    .sType(KHRWin32Surface.VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR).pNext(0).flags(0);
            LongBuffer pSurface = stack.callocLong(1);
            KHRWin32Surface.vkCreateWin32SurfaceKHR(instance, sfc, null, pSurface);
            surface = pSurface.get(0);
            while (User32.GetMessage(msg, 0L, 0, 0) == true) {
                User32.TranslateMessage(msg);
                User32.DispatchMessage(msg);
            }

我得到以下异常。关于加载所需的 Vulkan 实例扩展似乎是一个错误,因为当我取消注释 GLFW.glfwInit();PointerBuffer windowExtensions = GLFWVulkan.glfwGetRequiredInstanceExtensions(); 行并使用它们来加载所需的扩展时,不会发生错误并且 Window 和 Vulkan Instance 和 Surface创建成功,也许有经验的人可以纠正我在这里做错了什么? 我试图手动加载的这两个扩展是 GLFW 方法唯一的。

Exception in thread "main" java.lang.NullPointerException
        at org.lwjgl.system.Checks.check(Checks.java:188)
        at org.lwjgl.vulkan.KHRWin32Surface.nvkCreateWin32SurfaceKHR(KHRWin32Surface.java:93)
        at org.lwjgl.vulkan.KHRWin32Surface.vkCreateWin32SurfaceKHR(KHRWin32Surface.java:151)
        at win32_test.Win32Window.init(Win32Window.java:96)
        at win32_test.Win32Window.main(Win32Window.java:34)

【问题讨论】:

    标签: java runtime-error game-engine lwjgl vulkan


    【解决方案1】:

    put() 将两个指针放入其中后,windowExtensions NIO 缓冲区的 .remaining() 将为 0。

    每当您将 NIO 缓冲区作为参数提供给 LWJGL 3 方法或结构内部时,LWJGL 3 将通过内部使用缓冲区的remaining() 方法(即limit - position)查看传递给本机函数的内存区域/数组的有效“长度”是多少(主要通过本机中的专用count/length 参数指定函数的签名或结构)。

    因此,当您将 VkInstanceCreateInfo 结构上的 ppEnabledExtensionNames(...) 成员设置为参数时(我们称之为 buffer),LWJGL 3 将首先查询 Buffer 的 position()remaining(),然后设置在PointerBuffer 的情况下,将底层C 结构的ppEnabledExtensionNames 成员设置为baseAddressOf(buffer) + buffer.position() * sizeof(uintptr_t),并将C 结构的enabledExtensionCount 成员设置为buffer.remaining()

    这意味着,LWJGL 3 将始终按照 NIO 缓冲区规范的预期方式(即作为写入/读取位置)尊重 NIO 缓冲区的 position()

    在您的情况下,由于您使用的是 relative NIO Buffer put() 方法,您会发现 windowExtensions NIO Buffer 的容量为 2,限制为 2 但也位置为 2,产生的 remaining() 为 0。

    为了修复您的代码,您必须将windowExtensions 缓冲区的位置设置为0。这可以通过多种方式实现,例如.flip() 放入缓冲区后,或者使用 absolute .put(index, ...) 方法或在相对 put 之后在缓冲区上调用 .position(0).rewind()

    【讨论】:

    • 使用.flip() 后,程序按预期运行。感谢您对我需要做的事情的非常详细的回复!
    猜你喜欢
    • 2015-08-30
    • 1970-01-01
    • 2016-12-06
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 2020-11-11
    • 1970-01-01
    相关资源
    最近更新 更多