def gen_rgb_to_yuv():
    global context
    from xpra.codecs.csc_opencl.opencl_kernels import gen_rgb_to_yuv_kernels, rgb_mode_to_indexes, indexes_to_rgb_mode
    #for RGB to YUV support we need to be able to handle the channel_order,
    #with READ_ONLY and both with COPY_HOST_PTR and USE_HOST_PTR since we
    #do not know in advance which one we can use..
    RGB_to_YUV_KERNELS = {}
    sif = pyopencl.get_supported_image_formats(context, mem_flags.WRITE_ONLY,  pyopencl.mem_object_type.IMAGE2D)
    sif_copy = pyopencl.get_supported_image_formats(context, mem_flags.READ_ONLY | mem_flags.COPY_HOST_PTR,  pyopencl.mem_object_type.IMAGE2D)
    log("get_supported_image_formats(READ_ONLY | COPY_HOST_PTR, IMAGE2D)=%s", sif)
    sif_use = pyopencl.get_supported_image_formats(context, mem_flags.READ_ONLY | mem_flags.USE_HOST_PTR,  pyopencl.mem_object_type.IMAGE2D)
    log("get_supported_image_formats(READ_ONLY | USE_HOST_PTR, IMAGE2D)=%s", sif)
    if not has_image_format(sif_copy, pyopencl.channel_order.R, pyopencl.channel_type.UNSIGNED_INT8) or \
       not has_image_format(sif_use, pyopencl.channel_order.R, pyopencl.channel_type.UNSIGNED_INT8):
        log.error("cannot convert to YUV without support for READ_ONLY R channel with both COPY_HOST_PTR and USE_HOST_PTR")
        return  {}
    missing = []
    found_rgb = set()
    def add_rgb_to_yuv(src_rgb_mode, kernel_rgb_mode, upload_rgb_mode, channel_order):
        log("add_rgb_to_yuv%s", (src_rgb_mode, kernel_rgb_mode, upload_rgb_mode, CHANNEL_ORDER_TO_STR.get(channel_order)))
        kernels = gen_rgb_to_yuv_kernels(kernel_rgb_mode)
        #log("kernels(%s)=%s", rgb_mode, kernels)
        for key, k_def in kernels.items():
            ksrc, dst = key
            assert ksrc==kernel_rgb_mode
            kname, ksrc = k_def
            RGB_to_YUV_KERNELS[(src_rgb_mode, dst)] = (kname, upload_rgb_mode, channel_order, ksrc)
            found_rgb.add(src_rgb_mode)
    for src_rgb_mode, channel_order in IN_CHANNEL_ORDER:
        errs = []
        if not has_image_format(sif_copy, channel_order, pyopencl.channel_type.UNSIGNED_INT8):
            errs.append("COPY_HOST_PTR")
        if not has_image_format(sif_use, channel_order, pyopencl.channel_type.UNSIGNED_INT8):
            errs.append("USE_HOST_PTR")
        if len(errs)>0:
            log("RGB 2 YUV: channel order %s is not supported in READ_ONLY mode(s): %s", src_rgb_mode, " or ".join(errs))
            missing.append((src_rgb_mode, channel_order))
            continue
        #OpenCL handles this rgb mode natively,
        #so we can generate the kernel for RGB(x) format:
        #(and let the copy to device deal natively with the format given)
        add_rgb_to_yuv(src_rgb_mode, "RGBX", src_rgb_mode, channel_order)
    if len(missing)>0:
        log("RGB 2 YUV: trying to find alternatives for: %s", missing)
        #now look for rgb byte order workarounds (doing the byteswapping ourselves):
        for src_rgb_mode, _ in missing:
            if src_rgb_mode in found_rgb:
                #we already have an alternative channel_order for this rgb mode
                #ie: RGBx and RGBA both map to "RGBX" or "RGBA"
                log("%s already found", src_rgb_mode)
                continue
            #we want a mode which is supported and has the same component channels
            for _, upload_rgb_mode, channel_order, _ in RGB_to_YUV_KERNELS.values():
                if len(upload_rgb_mode)!=len(src_rgb_mode):
                    #skip mode if it has fewer channels (could drop one we need)
                    log("skipping %s (number of channels different from %s)", upload_rgb_mode, src_rgb_mode)
                    continue
                ok = has_same_channels(upload_rgb_mode, src_rgb_mode)
                log("testing %s as byteswap alternative to %s : %s", upload_rgb_mode, src_rgb_mode, ok)
                if not ok:
                    continue
                log("RGB 2 YUV: using upload mode %s to support %s via generated CL kernel byteswapping", upload_rgb_mode, src_rgb_mode)
                #easier than in YUV 2 RGB above, we just need to work out the starting positions of the RGB pixels:
                spos = rgb_mode_to_indexes(src_rgb_mode)     #ie: BGRX -> [2,1,0,3]
                uli = rgb_mode_to_indexes(upload_rgb_mode)   #ie: RGBX -> [0,1,2,3]
                virt_mode = indexes_to_rgb_mode([uli[x] for x in spos])   #ie: [2,1,0,3]
                log("RGB 2 YUV: virtual mode for %s: %s", src_rgb_mode, virt_mode)
                add_rgb_to_yuv(src_rgb_mode, virt_mode, upload_rgb_mode, channel_order)
                break
            if src_rgb_mode not in found_rgb:
                #not matched:
                log("RGB 2 YUV: channel order %s is not supported: we don't have a byteswapping alternative", src_rgb_mode)
                continue

    log("RGB 2 YUV conversions=%s", sorted(RGB_to_YUV_KERNELS.keys()))
    #log("RGB 2 YUV kernels=%s", RGB_to_YUV_KERNELS)
    log("RGB 2 YUV kernels=%s", sorted(list(set([x[0] for x in RGB_to_YUV_KERNELS.values()]))))
    return RGB_to_YUV_KERNELS
def gen_yuv_to_rgb():
    global context,selected_platform
    from xpra.codecs.csc_opencl.opencl_kernels import gen_yuv_to_rgb_kernels, rgb_mode_to_indexes, indexes_to_rgb_mode

    YUV_to_RGB_KERNELS = {}

    if selected_platform and selected_platform.name and selected_platform.name.find("CUDA")>=0 and not NVIDIA_YUV2RGB:
        log.warn("CUDA device detected, YUV to RGB disabled")
        return {}

    #for YUV to RGB support we need to be able to handle the channel_order in WRITE_ONLY mode
    #so we can download the result of the CSC:
    sif = pyopencl.get_supported_image_formats(context, mem_flags.WRITE_ONLY,  pyopencl.mem_object_type.IMAGE2D)
    log("get_supported_image_formats(WRITE_ONLY, IMAGE2D)=%s", sif)
    missing = []
    found_rgb = set()
    def add_yuv_to_rgb(dst_rgb_mode, kernel_rgb_mode, download_rgb_mode, channel_order):
        """ add the kernels converting yuv-to-rgb for the rgb_mode given (and record the channel order)"""
        log("add_yuv_to_rgb%s", (dst_rgb_mode, kernel_rgb_mode, download_rgb_mode, CHANNEL_ORDER_TO_STR.get(channel_order)))
        kernels = gen_yuv_to_rgb_kernels(kernel_rgb_mode)
        for (yuv_mode, krgb_mode), (kname, ksrc) in kernels.items():
            assert krgb_mode==kernel_rgb_mode
            YUV_to_RGB_KERNELS[(yuv_mode, dst_rgb_mode)] = (kname, download_rgb_mode, channel_order, ksrc)
            found_rgb.add(dst_rgb_mode)

    for rgb_mode, channel_order in IN_CHANNEL_ORDER:
        #why do we discard RGBX download mode? because it doesn't work, don't ask me why
        if not has_image_format(sif, channel_order, pyopencl.channel_type.UNSIGNED_INT8) or rgb_mode=="RGBX":
            log("YUV 2 RGB: channel order %s is not supported directly in WRITE_ONLY + UNSIGNED_INT8 mode", CHANNEL_ORDER_TO_STR.get(channel_order))
            missing.append((rgb_mode, channel_order))
            continue
        #it is supported natively, so this is easy:
        #just generate kernels for the "RGB(X)" format OpenCL will deliver the image in
        #and dst_rgb_mode is the same mode we download to
        add_yuv_to_rgb(rgb_mode, "RGBX", rgb_mode, channel_order)

    if len(YUV_to_RGB_KERNELS)>0 and len(missing)>0:
        log("YUV 2 RGB: trying to find alternatives for: %s", missing)
        #now look for rgb byte order workarounds (doing the byteswapping ourselves):
        for dst_rgb_mode, _ in missing:
            if dst_rgb_mode in found_rgb:
                #we already have an alternative channel_order for this rgb mode
                #ie: RGBx and RGBA both map to "RGBX" or "RGBA"
                log("%s already found", dst_rgb_mode)
                continue
            #we want a mode which is supported and has the same component channels
            for _, download_rgb_mode, channel_order, _ in YUV_to_RGB_KERNELS.values():
                if len(download_rgb_mode)!=len(dst_rgb_mode):
                    #skip mode if it has fewer channels (could drop one we need)
                    log("skipping %s (number of channels different from %s)", download_rgb_mode, dst_rgb_mode)
                    continue
                ok = has_same_channels(download_rgb_mode, dst_rgb_mode)
                log("testing %s as byteswap alternative to %s : %s", download_rgb_mode, dst_rgb_mode, ok)
                if not ok:
                    continue
                log("YUV 2 RGB: using download mode %s to support %s via generated CL kernel byteswapping", download_rgb_mode, dst_rgb_mode)
                #now we "just" need to add a kernel which will give us
                #dst_rgb_mode after the ???X image data is downloaded as download_rgb_mode
                #ie: we may want BGRX as output, but are downloading the pixels to RGBX (OpenCL does byteswapping)
                #OR: we want RGBX as output, but are downloading to BGRX..
                #so we need the inverse transform which will come out right
                dli = rgb_mode_to_indexes(download_rgb_mode)    #ie: BGRX -> [2,1,0,3]
                wanti = rgb_mode_to_indexes(dst_rgb_mode)       #ie: RGBX -> [0,1,2,3]
                #for each ending position, figure out where it started from:
                rindex = {} #reverse index
                for i in range(4):
                    rindex[dli.index(i)] = i                    #ie: {2:0, 1:1, 0:2, 3:3}
                log("YUV 2 RGB: reverse map for download mode %s (%s): %s", download_rgb_mode, dli, rindex)
                virt_mode = indexes_to_rgb_mode([rindex[x] for x in wanti])
                log("YUV 2 RGB: virtual mode for %s (%s): %s", dst_rgb_mode, wanti, virt_mode)
                add_yuv_to_rgb(dst_rgb_mode, virt_mode, download_rgb_mode, channel_order)
                break
            if dst_rgb_mode not in found_rgb:
                #not matched:
                log("YUV 2 RGB: channel order %s is not supported: we don't have a byteswapping alternative", dst_rgb_mode)
                continue
    log("YUV 2 RGB conversions=%s", sorted(YUV_to_RGB_KERNELS.keys()))
    #log("YUV 2 RGB kernels=%s", YUV_to_RGB_KERNELS)
    log("YUV 2 RGB kernels=%s", sorted(list(set([x[0] for x in YUV_to_RGB_KERNELS.values()]))))
    return YUV_to_RGB_KERNELS