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