From 204724bebe2484ee2d14a572d9f1074dd3f933a9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 30 Nov 2018 16:42:49 +0000 Subject: [PATCH] Add documentation for python extensions --- docs/how/how_network_capture_replay.rst | 2 +- docs/how/how_python_extension.rst | 63 +++++++++++++++++++++ docs/how/index.rst | 1 + docs/imgs/Screenshots/ExtensionManager.png | Bin 0 -> 13225 bytes docs/window/python_shell.rst | 1 + 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 docs/how/how_python_extension.rst create mode 100644 docs/imgs/Screenshots/ExtensionManager.png diff --git a/docs/how/how_network_capture_replay.rst b/docs/how/how_network_capture_replay.rst index 6d3327bbd..22c2fb9fd 100644 --- a/docs/how/how_network_capture_replay.rst +++ b/docs/how/how_network_capture_replay.rst @@ -21,7 +21,7 @@ To use a remote machine, you define a replay context for that machine. Everythin Configuring Remote Hosts ------------------------ -To configure a remote host, open the manager by opening the Tools menu and select Manage Remote Servers. +To configure a remote host, open the manager by opening the :guilabel:`Tools` menu and select :guilabel:`Manage Remote Servers`. .. figure:: ../imgs/Screenshots/RemoteHostManager.png diff --git a/docs/how/how_python_extension.rst b/docs/how/how_python_extension.rst new file mode 100644 index 000000000..564dbd53a --- /dev/null +++ b/docs/how/how_python_extension.rst @@ -0,0 +1,63 @@ +How do I write a python extension? +================================== + +RenderDoc supports python extensions using the :doc:`existing python API <../python_api/index>`. These extensions can be configured to be persistent and load whenever the RenderDoc UI does, allowing users to extend the program with custom functionality. + +Creating extensions +------------------- + +Extensions are simply python modules located in the user's RenderDoc config folder, with a json manifest. The config folder varies by platform, on Windows it's ``%APPDATA%\qrenderdoc\extensions`` and on linux it's ``~/.local/share/qrenderdoc/extensions``. Each extension is a python module subfolder under this root. You can nest subfolders, e.g. ``extensions/foo/bar/first`` would be the extension ``foo.bar.first``, and treated independently from ``extensions/foo/bar/second``. + +Next to each python module's ``__init__.py`` you should create a file ``extension.json`` following this template: + +.. highlight:: json +.. code:: json + + { + "extension_api": 1, + "name": "Extension name for users", + "version": "1.0", + "minimum_renderdoc": "1.2", + "description": "A longer description of your extension.\n\nIt can contain multiple lines", + "author": "Your name ", + "url": "url/to/repository" + } + +In this JSON the ``extension_api`` field is currently fixed to 1. + +The ``minimum_renderdoc`` field controls whether the extension can be enabled on a given RenderDoc version, and allows you to block incompatible versions of RenderDoc. + +The ``name``, ``description``, ``version``, ``author`` and ``url`` fields are all informational and presented to users when listing installed extensions. + +Without this json manifest the extension will not be enumerated by RenderDoc and displayed to users. + +Enabling extensions +------------------- + +To configure installed extensions, open the extension manager by opening the :guilabel:`Tools` menu and select :guilabel:`Manage Extensions`. + +.. figure:: ../imgs/Screenshots/ExtensionManager.png + + Extension Manager: Configures installed extensions. + +From here a list of all installed extensions is presented. By default extensions are not loaded, to load an extension either select it and press :guilabel:`Load` or else tick the box in the :guilabel:`Loaded` column in the list. As with python modules, once loaded an extension cannot be unloaded until the program is restarted. + +Once an extension is loaded to enable it permanently, tick the :guilabel:`Always Load` checkbox when the extension is selected. Once enabled this means the extension will always load when the UI starts without any user interaction. Extensions must be loaded first to ensure they can load without errors or crashes before enabling them to load at startup. + +A loaded extension can be reloaded by pressing the :guilabel:`Reload` button which will attempt to unload and load the extension again to refresh the code. This may break so if you encounter any problems it's recommended that you restart the program to ensure a clean reload. + +Writing extensions +------------------ + +A python extension when loaded will have a ``register`` function called in its module, and such a function must exist at global scope. It's defined like so for Extension API v1: + +.. highlight:: python +.. code:: python + + def register(version, pyrenderdoc): + # version is the RenderDoc Major.Minor version as a string, such as "1.2" + # pyrenderdoc is the CaptureContext handle, the same as the global available in the python shell + +Optionally you can define an ``unregister`` function to be called if the extension is reloaded. This takes no parameters and is simply an opportunity to clean-up or remove anything persistent that shouldn't hang around, before ``register`` is called again. + +Extensions use the full :doc:`python API <../python_api/index>` with all of the power that comes with it. There are interfaces geared specifically towards extensions in :doc:`the qrenderdoc module <../python_api/qrenderdoc/extensions>` which allow registering callbacks for menu items. \ No newline at end of file diff --git a/docs/how/index.rst b/docs/how/index.rst index f9266a14a..318e03019 100644 --- a/docs/how/index.rst +++ b/docs/how/index.rst @@ -16,3 +16,4 @@ How do I ...? how_annotate_capture how_import_export how_rgp_profile + how_python_extension diff --git a/docs/imgs/Screenshots/ExtensionManager.png b/docs/imgs/Screenshots/ExtensionManager.png new file mode 100644 index 0000000000000000000000000000000000000000..8bb030911056f5e6fb863c16307687cd58c174fb GIT binary patch literal 13225 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 Ud+ZSS7aTzSHcX{h`N7kF15&d9R{#J2 literal 0 HcmV?d00001 diff --git a/docs/window/python_shell.rst b/docs/window/python_shell.rst index b43f70ca8..1a1205dd0 100644 --- a/docs/window/python_shell.rst +++ b/docs/window/python_shell.rst @@ -22,3 +22,4 @@ See Also -------- * :doc:`../python_api/index` +* :doc:`../how/how_python_extension`