python-vulkan-triangle icon indicating copy to clipboard operation
python-vulkan-triangle copied to clipboard

Test on MacOS

Open apenngrace opened this issue 6 years ago • 3 comments

I tried making triangle.py work on MacOS (using glfw to create a window & surface), but I got stuck. Any interest on trying to make it work? One issue is that I do not know where to put the mainloop for glfw (so that it does not just immediately exit). However, the an issue even before that is that I'm getting an error with glfw.create_window_surface. I think I'm just doing something wrong with ctypes, but I'm not sure.

I know that the vulkan SDK for Mac works at least, because the code from this repo will run (and that doing some FFI to Ctypes converting).

If you have MacOS, you can install the vulkan-sdk with brew cask install apenngrace/vulkan/vulkan-sdk.

In vk.py I added:

elif system_name == 'Darwin':
    from ctypes import CFUNCTYPE, cdll
    FUNCTYPE = CFUNCTYPE
    vk = cdll.LoadLibrary('libvulkan.dylib')

In triangle.py I added (in the system_name = platform.system() block):

elif system_name == 'Darwin':
    from macos import MacOSWindow as Window, MacOSSwapchain as BaseSwapchain

In triangle.py I added (in the extensions block at the top of create_instance):

        elif system_name == 'Darwin':
            extensions = [b'VK_KHR_surface', b'VK_MVK_macos_surface']

I created the file macos.py with this code:

import vk
import glfw

from ctypes import *
import weakref
import asyncio

class MacOSWindow(object):
    
    def __init__(self, app):
        self.width = 1280
        self.height = 720
        self.window = None
        self.app = weakref.ref(app)

        glfw.init()
        
        glfw.window_hint(glfw.CLIENT_API, glfw.NO_API)
        glfw.window_hint(glfw.VISIBLE, False)           #hidden

        self.window = glfw.create_window(self.width, self.height, 
            "Python vulkan test", None, None)

        # asyncio.ensure_future(process_events(self.app))    

    def __del__(self):
        glfw.terminate()
        

    @property
    def handle(self):
        return self.window
        # return self.__hwnd

    def dimensions(self):
        return (self.width, self.height)
        # dim = RECT()
        # GetClientRect(self.__hwnd, byref(dim))
        # return (dim.right, dim.bottom)

    def show(self):
        glfw.show_window(self.window)
        # ShowWindow(self.__hwnd, SW_SHOWNORMAL)

    def set_title(self, title):
        glfw.set_window_title(self.window, title)

        # glfwSetWindowTitle(window, "My Window");

        # title = c_wchar_p(title)
        # SetWindowTextW(self.__hwnd, title)


class MacOSSwapchain(object):

    def __init__(self, app):
        self.app = weakref.ref(app)
        self.surface = None
        self.swapchain = None
        self.images = None
        self.views = None
        self.create_surface()

    def create_surface(self):
        """
            Create a surface for the window
        """
        
        app = self.app()    #think this paren is because of weakref

        surface = c_void_p(0)

        glfw.create_window_surface(
            instance = app.instance,
            window = app.window.handle, 
            allocator = None,
            surface = byref( surface ) 
        )

        self.surface = surface

apenngrace avatar Oct 15 '18 04:10 apenngrace

I don't think there is anything wrong with your setup. It might just be that the demo is out of date (it's almost been 3 years now). Also, using asyncio was a mistake.

If you're looking to test Vulkan in python, check out this repo https://github.com/gabdube/vulkan_python_baby_steps. Its the same content, just more up to date, clearer and without the bad decisions I made in this project.

Here's a rough list of the stuff that must be done:

  1. The changes to vk.py stays the same.
  2. The window selection will go to https://github.com/gabdube/vulkan_python_baby_steps/blob/master/system/window/__init__.py
  3. Your window class will go in the same folder. Most of the code will stay the same. In order for the most basic demo to work (ex: simple_triangle), you only have to implement the translate_system_events method. A simple call to glfwPollEvents should do the job.
  4. Your create_surface function will go to https://github.com/gabdube/vulkan_python_baby_steps/blob/master/vulkan/helpers/window.py . And don't forget to include the function in the if block at the end of the file
  5. The surface extension must be added to every demo file in the create_instance function. Example: https://github.com/gabdube/vulkan_python_baby_steps/blob/master/simple_triangle.py#L128 (In retrospective, this should be changed to some kind of constant like SYSTEM_SURFACE_EXTENSION that can be imported from the wrapper)

If you have any other questions, I'll do my best to answer them.

gabdube avatar Oct 15 '18 16:10 gabdube

Thanks for the quick reply! I’m pretty new to Vulkan and finding it very challenging to understand (I have done projects with OpenCL and very basic OpenGL).

Are there any tutorials that you felt were good? I will definitely check out your baby steps repo. I’m trying the LunarG tutorial, but I still feel lost.

Have you ever tried rendering onto multiple surfaces in the same program with vulkan? That’s one the main reasons why I’m trying vulkan.

Also what about ansyncio do you think was a mistake?

Thanks! Andrew

On Oct 15, 2018, at 12:35 PM, Gabriel Dube [email protected] wrote:

I don't think there is anything wrong with your setup. It might just be that the demo is out of date (it's almost been 3 years now). Also, using asyncio was a mistake.

If you're looking to test Vulkan in python, check out this repo https://github.com/gabdube/vulkan_python_baby_steps. Its the same content, just more up to date, clearer and without the bad decisions I made in this project.

Here's a rough list of the stuff that must be done:

The changes to vk.py stays the same. The window selection will go to https://github.com/gabdube/vulkan_python_baby_steps/blob/master/system/window/init.py Your window class will go in the same folder. Most of the code will stay the same. In order for the most basic demo to work (ex: simple_triangle), you only have to implement the translate_system_events method. A simple call to glfwPollEvents should do the job. Your create_surface function will go to https://github.com/gabdube/vulkan_python_baby_steps/blob/master/vulkan/helpers/window.py . And don't forget to include the function in the if block at the end of the file The surface extension must be added to every demo file in the create_instance function. Example: https://github.com/gabdube/vulkan_python_baby_steps/blob/master/simple_triangle.py#L128 (In retrospective, this should be changed to some kind of constant like SYSTEM_SURFACE_EXTENSION that can be imported from the wrapper) If you have any other questions, I'll do my best to answer them.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

apenngrace avatar Oct 15 '18 17:10 apenngrace

I didn't learned Vulkan by following tutorials, so I can't really recommend any. The way I've done it is a mix of reading the official documentation, reading the demo from https://github.com/SaschaWillems/Vulkan and adapting the knowledge I already had from opengl.

I've tried to render to multiple surface with Vulkan, and it was an bad experience. That's because if you try to do it the dumb way (ie: each surface/swapchain/imageview has its own framebuffer) you have to duplicate your commands buffers and it can become a mess.

Using asyncio was a mistake because overall, it makes everything harder to understand. Using a good old while loop is just better.

gabdube avatar Oct 15 '18 18:10 gabdube