From 1a6f840d078a19321b85a867db09b55c1f03ae73 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Sun, 12 Jul 2020 07:14:45 +0000 Subject: [PATCH] #2828 / 1462: we are better off using r210-RGB to paint with opengl because GBRP10 would need bit shifting to GBRP16 in order to be used with opengl 'SHORT' upload format - which takes up more space than r210 anyway git-svn-id: https://xpra.org/svn/Xpra/trunk@26960 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- src/xpra/client/gl/gl_window_backing_base.py | 19 ++-- .../csc_cython/colorspace_converter.pyx | 90 +++++++++++++++++-- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/xpra/client/gl/gl_window_backing_base.py b/src/xpra/client/gl/gl_window_backing_base.py index 7e8759fa42..9a1493a560 100644 --- a/src/xpra/client/gl/gl_window_backing_base.py +++ b/src/xpra/client/gl/gl_window_backing_base.py @@ -21,7 +21,6 @@ GL_DONT_CARE, GL_TRUE, GL_DEPTH_TEST, GL_SCISSOR_TEST, GL_LIGHTING, GL_DITHER, GL_RGB, GL_RGBA, GL_BGR, GL_BGRA, GL_RGBA8, GL_RGB8, GL_RGB10_A2, GL_RGB565, GL_RGB5_A1, GL_RGBA4, GL_RGBA16, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_SHORT_5_6_5, - GL_UNPACK_SWAP_BYTES, GL_BLEND, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_TEXTURE_MAX_LEVEL, GL_TEXTURE_BASE_LEVEL, GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST, @@ -124,7 +123,7 @@ "YUV422P" : GL_UNSIGNED_BYTE, "YUV444P" : GL_UNSIGNED_BYTE, "GBRP" : GL_UNSIGNED_BYTE, - "GBRP10" : GL_UNSIGNED_SHORT, + "GBRP16" : GL_UNSIGNED_SHORT, } CONSTANT_TO_PIXEL_FORMAT = { GL_BGR : "BGR", @@ -303,11 +302,11 @@ def init_formats(self): if self.bit_depth>32: self.internal_format = GL_RGBA16 self.RGB_MODES.append("r210") - self.RGB_MODES.append("GBRP10") + #self.RGB_MODES.append("GBRP16") elif self.bit_depth==30: self.internal_format = GL_RGB10_A2 self.RGB_MODES.append("r210") - self.RGB_MODES.append("GBRP10") + #self.RGB_MODES.append("GBRP16") elif 0> 10 bgr48[i+2] = (v&0x3ff00000) >> 20 - i = i + 3 + i += 3 r210 = (( r210) + src_stride) +cdef inline void gbrp10_to_r210_copy(uintptr_t r210, uintptr_t[3] gbrp10, + unsigned int width, unsigned int height, + unsigned int src_stride, unsigned int dst_stride) nogil: + cdef unsigned int x, y + cdef unsigned short *b + cdef unsigned short *g + cdef unsigned short *r + cdef unsigned int *dst + for y in range(height): + dst = (r210 + y*dst_stride) + g = (( gbrp10[0]) + y*src_stride) + b = (( gbrp10[1]) + y*src_stride) + r = (( gbrp10[2]) + y*src_stride) + for x in range(width): + dst[x] = (b[x] & 0x3ff) + ((g[x] & 0x3ff)<<10) + ((r[x] & 0x3ff)<<20) + cdef class ColorspaceConverter: cdef unsigned int src_width @@ -248,6 +268,9 @@ cdef class ColorspaceConverter: self.dst_sizes[i] = 0 self.offsets[i] = 0 + def assert_no_scaling(): + assert src_width==dst_width and src_height==dst_height, "scaling is not supported for %s to %s" % (src_format, dst_format) + if src_format in ("BGRX", "RGBX", "RGB", "BGR", "r210") and dst_format=="YUV420P": self.dst_strides[0] = roundup(self.dst_width, STRIDE_ROUNDUP) self.dst_strides[1] = roundup(self.dst_width/2, STRIDE_ROUNDUP) @@ -273,12 +296,17 @@ cdef class ColorspaceConverter: assert src_format=="r210" self.convert_image_function = self.r210_to_YUV420P elif src_format=="r210" and dst_format=="BGR48": + assert_no_scaling() self.dst_strides[0] = roundup(self.dst_width*6, STRIDE_ROUNDUP) self.dst_sizes[0] = self.dst_strides[0] * self.dst_height self.buffer_size = self.dst_sizes[0]+self.dst_strides[0] self.convert_image_function = self.r210_to_BGR48 - assert src_width==dst_width - assert src_height==dst_height + elif src_format=="GBRP10" and dst_format=="r210": + assert_no_scaling() + self.dst_strides[0] = roundup(self.dst_width*4, STRIDE_ROUNDUP) + self.dst_sizes[0] = self.dst_strides[0] * self.dst_height + self.buffer_size = self.dst_sizes[0]+self.dst_strides[0] + self.convert_image_function = self.GBRP10_to_r210 elif src_format=="YUV420P" and dst_format in ("RGBX", "BGRX", "RGB", "BGR"): #3 or 4 bytes per pixel: self.dst_strides[0] = roundup(self.dst_width*len(dst_format), STRIDE_ROUNDUP) @@ -425,7 +453,7 @@ cdef class ColorspaceConverter: pixels = image.get_pixels() assert pixels, "failed to get pixels from %s" % image input_stride = image.get_rowstride() - log("do_RGB_to_YUV420P(%s, %i, %i, %i, %i) input=%s, strides=%s" % (image, Bpp, Rindex, Gindex, Bindex, len(pixels), input_stride)) + log("do_RGB_to_YUV420P(%s, %i, %i, %i, %i) input=%s, strides=%s", image, Bpp, Rindex, Gindex, Bindex, len(pixels), input_stride) assert object_as_buffer(pixels, &input_image, &pic_buf_len)==0 #allocate output buffer: @@ -542,7 +570,7 @@ cdef class ColorspaceConverter: pixels = image.get_pixels() assert pixels, "failed to get pixels from %s" % image input_stride = image.get_rowstride() - log("r210_to_BGR48(%s) input=%s, strides=%s" % (image, len(pixels), input_stride)) + log("r210_to_BGR48(%s) input=%s, strides=%s", image, len(pixels), input_stride) cdef Py_ssize_t pic_buf_len = 0 cdef const unsigned int *r210 @@ -564,7 +592,7 @@ cdef class ColorspaceConverter: bgr48_buffer = memory_as_pybuffer( bgr48, self.dst_sizes[0], True) cdef double elapsed = time.time()-start - log("%s took %.1fms", self, 1000.0*elapsed) + log("r210_to_BGR48 took %.1fms", 1000.0*elapsed) self.time += elapsed self.frames += 1 out_image = CythonImageWrapper(0, 0, self.dst_width, self.dst_height, bgr48_buffer, "BGR48", 48, dst_stride, ImageWrapper.PACKED) @@ -572,6 +600,54 @@ cdef class ColorspaceConverter: return out_image + def GBRP10_to_r210(self, image): + cdef double start = time.time() + assert image.get_planes()==ImageWrapper.PLANAR_3, "invalid input format: %s planes" % image.get_planes() + assert image.get_width()>=self.src_width, "invalid image width: %s (minimum is %s)" % (image.get_width(), self.src_width) + assert image.get_height()>=self.src_height, "invalid image height: %s (minimum is %s)" % (image.get_height(), self.src_height) + pixels = image.get_pixels() + assert pixels, "failed to get pixels from %s" % image + + input_strides = image.get_rowstride() + cdef unsigned int w = self.src_width + cdef unsigned int h = self.src_height + cdef unsigned int src_stride = input_strides[0] + cdef unsigned int dst_stride = self.dst_strides[0] + assert input_strides[1]==src_stride and input_strides[2]==src_stride, "mismatch in rowstrides: %s" % (input_strides,) + assert src_stride>=w*2 + assert dst_stride>=w*4 + assert self.dst_sizes[0]>=dst_stride*h + + cdef Py_ssize_t pic_buf_len[3] + cdef uintptr_t gbrp10[3] + cdef unsigned int i + for i in range(3): + assert object_as_buffer(pixels[i], &gbrp10[i], &pic_buf_len[i])==0 + assert pic_buf_len[i]>=src_stride*h, "input plane '%s' is too small: %i bytes" % ("GBR"[i], pic_buf_len[i]) + + #allocate output buffer: + cdef unsigned int *r210 = memalign(self.dst_sizes[0]) + + if image.is_thread_safe(): + with nogil: + gbrp10_to_r210_copy( r210, gbrp10, + w, h, + src_stride, dst_stride) + else: + gbrp10_to_r210_copy( r210, gbrp10, + w, h, + src_stride, dst_stride) + + r210_buffer = memory_as_pybuffer( r210, self.dst_sizes[0], True) + cdef double elapsed = time.time()-start + log("GBRP10_to_r210 took %.1fms", 1000.0*elapsed) + self.time += elapsed + self.frames += 1 + out_image = CythonImageWrapper(0, 0, self.dst_width, self.dst_height, r210_buffer, "r210", 30, dst_stride, ImageWrapper.PACKED) + out_image.cython_buffer = r210 + return out_image + + def YUV420P_to_RGBX(self, image): return self.do_YUV420P_to_RGB(image, 4, RGBX_R, RGBX_G, RGBX_B, RGBX_X)