1
$\begingroup$

I'm looking for a way to have Blender 2.8 render with Cycles using CUDA but only for Nvidia GPUs (no CPUs selected) and do the same using OpenCL with only AMD GPUs (no CPUs selected).

My goal is to basically have a "CUDA script" that when run passes all available Nvidia GPUs in the system to Blender to render, while another "OpenCL script" sends all AMD cards.

I can detect and select a certain card with wmic but I can't find a way to match my behavior in the GUI of Edit > Preferences > System > CUDA > (only select Nvidia GPUs) for example.

Is it possible to have a blend file containing a script to render with just GPUs of a particular technology?

Thanks,

.trey

$\endgroup$

1 Answer 1

1
$\begingroup$

You can filter the devices returned by get_devices() by their type. The following script enables all CUDA devices that aren't CPUs. You can do the same for OpenCL or even combine the two into one script. If you want to disable CPUs that are already enabled in the preferences, you'd have to add an else case that sets device.use = False.

import bpy

preferences = bpy.context.preferences
cycles_preferences = preferences.addons['cycles'].preferences
cuda_devices, opencl_devices = cycles_preferences.get_devices()

cycles_preferences.compute_device_type = 'CUDA'

for device in cuda_devices:
    if device.type != 'CPU':
        print(f'Activating {device.name}')
        device.use = True

An add-on could be implemented like this:

bl_info = {
    "name": "Enable GPU devices",
    "author": "Robert Guetzkow",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "Properties > Render > Enable GPU panel",
    "description": "Enable GPU devices (CUDA/OpenCL) for rendering",
    "warning": "",
    "wiki_url": "",
    "category": "3D View"}

import bpy


def enable_gpus(device_type):
    preferences = bpy.context.preferences
    cycles_preferences = preferences.addons["cycles"].preferences
    cuda_devices, opencl_devices = cycles_preferences.get_devices()

    if device_type == "CUDA":
        devices = cuda_devices
    elif device_type == "OPENCL":
        devices = opencl_devices
    else:
        raise RuntimeError("Unsupported device type")

    activated_gpus = []

    for device in devices:
        if device.type == "CPU":
            device.use = False
        else:
            device.use = True
            activated_gpus.append(device.name)

    cycles_preferences.compute_device_type = device_type
    bpy.context.scene.cycles.device = "GPU"

    return activated_gpus


class PREFERENCES_OT_enable_cuda(bpy.types.Operator):
    bl_idname = "preferences.enable_cuda"
    bl_label = "Enable all CUDA GPUs"
    bl_description = "Enable all CUDA GPUs as render devices, CPUs will be deactivated."
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        try:
            activated_gpus = enable_gpus("CUDA")
        except (RuntimeError, TypeError) as e:
            print(e)
            self.report({"ERROR"}, e)

        if not activated_gpus:
            self.report({"WARNING"}, "No CUDA compatible GPUs found.")
        else:
            self.report({"INFO"}, f"Activated {', '.join(activated_gpus)}")

        return {"FINISHED"}


class PREFERENCES_OT_enable_opencl(bpy.types.Operator):
    bl_idname = "preferences.enable_opencl"
    bl_label = "Enable all OpenCL GPUs"
    bl_description = "Enable all OpenCL GPUs as render devices, CPUs will be deactivated."
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        try:
            activated_gpus = enable_gpus("OPENCL")
        except (RuntimeError, TypeError) as e:
            print(e)
            self.report({"ERROR"}, e)

        if not activated_gpus:
            self.report({"WARNING"}, "No OpenCL compatible GPUs found.")
        else:
            self.report({"INFO"}, f"Activated {', '.join(activated_gpus)}")

        return {"FINISHED"}


class ENABLE_GPU_PT_panel(bpy.types.Panel):
    bl_label = "Enable GPU"
    bl_category = "Name of your tab"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "render"
    COMPAT_ENGINES = {"CYCLES"}

    @classmethod
    def poll(cls, context):
        engine = context.scene.render.engine
        return (engine in cls.COMPAT_ENGINES)

    def draw(self, context):
        layout = self.layout
        layout.operator(PREFERENCES_OT_enable_cuda.bl_idname)
        layout.operator(PREFERENCES_OT_enable_opencl.bl_idname)


classes = (ENABLE_GPU_PT_panel, PREFERENCES_OT_enable_cuda, PREFERENCES_OT_enable_opencl)


def register():
    for cls in classes:
        bpy.utils.register_class(cls)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)


if __name__ == "__main__":
    register()

Screenshot

$\endgroup$
4
  • $\begingroup$ The API for this isn't well documented, but you can take a look at the source how the device lists get populated in def get_devices_for_type(self, compute_device_type) in properties.py. $\endgroup$
    – Robert Gützkow
    Oct 3, 2019 at 19:23
  • $\begingroup$ Okay, I'll take a look at the API but based on your example, is it correct that the text could be put into the blend file, and the command line could be used to start rendering the file with all non-CPU CUDA devices, and then the same for OpenCL devices with another file and the text modified for OpenCL? I'm looking at a GUI for the user to kick off either CUDA or OpenCL (device-based) rendering. I'll spend some time experimenting but I appreciate the help. $\endgroup$ Oct 4, 2019 at 15:06
  • $\begingroup$ @TreyMorton The script as is could be loaded into Blender's text editor and executed using the Run Script button. In order to create buttons in the GUI that perform these operations, you would have to write an add-on. The operator would/could perform the same steps as the script above. $\endgroup$
    – Robert Gützkow
    Oct 4, 2019 at 18:22
  • $\begingroup$ @TreyMorton I've updated my answer that now shows how to write an add-on for this task $\endgroup$
    – Robert Gützkow
    Oct 4, 2019 at 22:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .