手动加载所需的Vulkan实例扩展时的java NullPointerException
我目前正在通过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();
行的注释,并使用它们来加载所需的扩展时,错误不会发生,窗口和Vulkan实例和曲面创建成功,也许有经验的人可以纠正我在这里做错了什么?
我试图手动加载的这两个扩展是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)
# 1 楼答案
在
put()
两个指针进入windowExtensions
NIO缓冲区后,它的.remaining()
值将为0每当您将NIO缓冲区作为参数提供给LWJGL 3方法或结构内部时,LWJGL 3将尊重NIO缓冲区的配置/状态,即它的
position()
和limit()
,通过在内部使用缓冲区的remaining()
方法(即limit - position
),查看传递给本机函数的内存区域/数组的有效“长度”(主要通过本机函数签名或结构中的专用count
/length
参数指定)因此,当您将
VkInstanceCreateInfo
结构上的ppEnabledExtensionNames(...)
成员设置为参数(这里我们称之为buffer
)时,LWJGL 3将首先查询缓冲区的position()
和remaining()
,然后在PointerBuffer
的情况下,将底层C结构的ppEnabledExtensionNames
成员设置为baseAddressOf(buffer) + buffer.position() * sizeof(uintptr_t)
,并将C结构的enabledExtensionCount
成员设置为{这意味着,LWJGL 3将始终按照NIO缓冲区规范(即作为写/读位置)的预期方式尊重NIO缓冲区的
position()
在您的例子中,由于您使用的是相对NIO Buffer
put()
方法,您会发现windowExtensions
NIO Buffer的容量为2,限制为2,但位置为2,产生的remaining()
为0为了修复代码,必须将
windowExtensions
缓冲区的位置设置为0。这可以通过多种方式实现,例如在放入缓冲区后.flip()
使用缓冲区,或者在相对放入后使用绝对.put(index, ...)
方法或调用.position(0)
或.rewind()
缓冲区