Example #1
0
    def draw_region(self, x, y, width, height, coding, img_data, rowstride,
                    packet_sequence, options, callbacks):
        """ Note: this runs from the draw thread (not UI thread) """
        backing = self._backing
        if not backing:
            log("draw_region: window %s has no backing, gone?", self._id)
            from xpra.client.window_backing_base import fire_paint_callbacks
            fire_paint_callbacks(callbacks, -1, "no backing")
            return

        def after_draw_refresh(success, message=""):
            plog(
                "after_draw_refresh(%s, %s) %sx%s at %sx%s encoding=%s, options=%s",
                success, message, width, height, x, y, coding, options)
            if success <= 0:
                return
            backing = self._backing
            if backing and backing.draw_needs_refresh:
                if REPAINT_ALL == "1" or self._client.xscale != 1 or self._client.yscale != 1:
                    rw, rh = self.get_size()
                    rx, ry = 0, 0
                else:
                    rx, ry, rw, rh = self._client.srect(x, y, width, height)
                if self.window_offset:
                    rx += self.window_offset[0]
                    ry += self.window_offset[1]
                self.idle_add(self.queue_draw, rx, ry, rw, rh)

        #only register this callback if we actually need it:
        if backing.draw_needs_refresh:
            callbacks.append(after_draw_refresh)
        backing.draw_region(x, y, width, height, coding, img_data, rowstride,
                            options, callbacks)
Example #2
0
 def paint_png(self, img_data, x, y, width, height, rowstride, options, callbacks):
     """ must be called from UI thread """
     if self._backing is None:
         fire_paint_callbacks(callbacks, False)
         return
     buf = data_to_buffer(img_data)
     self.do_paint_png(buf, x, y, width, height, rowstride, options, callbacks)
Example #3
0
 def do_paint_png(self, buf, x, y, width, height, rowstride, options, callbacks):
     surf = cairo.ImageSurface.create_from_png(buf)
     gc = cairo.Context(self._backing)
     gc.set_source_surface(surf)
     gc.paint()
     surf.finish()
     fire_paint_callbacks(callbacks, True)
Example #4
0
 def paint_pixbuf_gdk(self, coding, img_data, x, y, width, height, options,
                      callbacks):
     """ must be called from UI thread """
     loader = gdk.PixbufLoader(coding)
     loader.write(img_data, len(img_data))
     loader.close()
     pixbuf = loader.get_pixbuf()
     if not pixbuf:
         log.error("failed %s pixbuf=%s data len=%s" %
                   (coding, pixbuf, len(img_data)))
         fire_paint_callbacks(callbacks, False)
         return False
     raw_data = pixbuf.get_pixels()
     rowstride = pixbuf.get_rowstride()
     img_data = self.process_delta(raw_data, width, height, rowstride,
                                   options)
     n = pixbuf.get_n_channels()
     if n == 3:
         self.do_paint_rgb24(img_data, x, y, width, height, rowstride,
                             options, callbacks)
     else:
         assert n == 4, "invalid number of channels: %s" % n
         self.do_paint_rgb32(img_data, x, y, width, height, rowstride,
                             options, callbacks)
     return False
Example #5
0
 def paint_png(self, img_data, x, y, width, height, rowstride, options, callbacks):
     """ must be called from UI thread """
     if self._backing is None:
         fire_paint_callbacks(callbacks, False)
         return
     buf = data_to_buffer(img_data)
     self.do_paint_png(buf, x, y, width, height, rowstride, options, callbacks)
Example #6
0
    def draw_region(self, x, y, width, height, coding, img_data, rowstride,
                    packet_sequence, options, callbacks):
        """ Note: this runs from the draw thread (not UI thread) """
        backing = self._backing
        if not backing:
            log("draw_region: window %s has no backing, gone?", self._id)
            from xpra.client.window_backing_base import fire_paint_callbacks
            fire_paint_callbacks(callbacks, False)
            return

        def after_draw_refresh(success):
            plog(
                "after_draw_refresh(%s) %sx%s at %sx%s encoding=%s, options=%s",
                success, width, height, x, y, coding, options)
            if not success:
                return
            backing = self._backing
            if backing and backing.draw_needs_refresh:
                self.queue_draw(x, y, width, height)

        #only register this callback if we actually need it:
        if backing.draw_needs_refresh:
            callbacks.append(after_draw_refresh)
        self._backing.draw_region(x, y, width, height, coding, img_data,
                                  rowstride, options, callbacks)
Example #7
0
 def paint_pixbuf_gdk(self, coding, img_data, x, y, width, height, options, callbacks):
     """ must be called from UI thread """
     if coding.startswith("png"):
         coding = "png"
     else:
         assert coding=="jpeg"
     loader = gdk.PixbufLoader(coding)
     loader.write(img_data, len(img_data))
     loader.close()
     pixbuf = loader.get_pixbuf()
     if not pixbuf:
         msg = "failed to load a pixbuf from %i bytes of %s data" % (len(img_data), coding)
         log.error("Error: %s", msg)
         fire_paint_callbacks(callbacks, False, msg)
         return  False
     raw_data = pixbuf.get_pixels()
     rowstride = pixbuf.get_rowstride()
     img_data = self.process_delta(raw_data, width, height, rowstride, options)
     n = pixbuf.get_n_channels()
     if n==3:
         self.do_paint_rgb24(img_data, x, y, width, height, rowstride, options, callbacks)
     else:
         assert n==4, "invalid number of channels: %s" % n
         self.do_paint_rgb32(img_data, x, y, width, height, rowstride, options, callbacks)
     return False
Example #8
0
 def do_paint_png(self, buf, x, y, width, height, rowstride, options, callbacks):
     surf = cairo.ImageSurface.create_from_png(buf)
     gc = cairo.Context(self._backing)
     gc.set_source_surface(surf)
     gc.paint()
     surf.finish()
     fire_paint_callbacks(callbacks, True)
Example #9
0
 def do_paint_scroll(self, scrolls, callbacks):
     old_backing = self._backing
     self.do_init_new_backing_instance()
     self.copy_backing(old_backing)
     gc = self._backing.new_gc()
     for sx, sy, sw, sh, xdelta, ydelta in scrolls:
         self._backing.draw_drawable(gc, old_backing, sx, sy, sx + xdelta,
                                     sy + ydelta, sw, sh)
     fire_paint_callbacks(callbacks)
Example #10
0
 def do_paint_scroll(self, scrolls, callbacks):
     old_backing = self._backing
     w, h = self.size
     ww, wh = self.render_size
     self.init(ww, wh, w, h)
     gc = gdk_cairo_context(cairo.Context(self._backing))
     gc.set_operator(cairo.OPERATOR_SOURCE)
     for sx, sy, sw, sh, xdelta, ydelta in scrolls:
         gc.set_source_surface(old_backing, xdelta, ydelta)
         gc.rectangle(sx + xdelta, sy + ydelta, sw, sh)
         gc.fill()
     fire_paint_callbacks(callbacks)
Example #11
0
 def paint_pixbuf_gdk(self, coding, img_data, x, y, width, height, options, callbacks):
     """ must be called from UI thread """
     loader = gdk.PixbufLoader(coding)
     loader.write(img_data, len(img_data))
     loader.close()
     pixbuf = loader.get_pixbuf()
     if not pixbuf:
         log.error("failed %s pixbuf=%s data len=%s" % (coding, pixbuf, len(img_data)))
         fire_paint_callbacks(callbacks, False)
         return  False
     raw_data = pixbuf.get_pixels()
     rowstride = pixbuf.get_rowstride()
     img_data = self.process_delta(raw_data, width, height, rowstride, options)
     self.do_paint_rgb24(img_data, x, y, width, height, rowstride, options, callbacks)
     return False
    def do_paint_rgb(self, rgb_format, img_data, x, y, width, height, rowstride, options, callbacks):
        log("%s.do_paint_rgb(%s, %s bytes, x=%d, y=%d, width=%d, height=%d, rowstride=%d, options=%s)", self, rgb_format, len(img_data), x, y, width, height, rowstride, options)
        context = self.gl_context()
        if not context:
            log("%s._do_paint_rgb(..) no context!", self)
            fire_paint_callbacks(callbacks, False, "no opengl context")
            return
        if not options.get("paint", True):
            fire_paint_callbacks(callbacks)
            return

        try:
            upload, img_data = self.pixels_for_upload(img_data)

            with context:
                self.gl_init()
                self.set_rgb_paint_state()

                #convert it to a GL constant:
                pformat = PIXEL_FORMAT_TO_CONSTANT.get(rgb_format.decode())
                assert pformat is not None, "could not find pixel format for %s" % rgb_format

                self.gl_marker("%s update at (%d,%d) size %dx%d (%s bytes), using GL %s format=%s",
                               rgb_format, x, y, width, height, len(img_data), upload, CONSTANT_TO_PIXEL_FORMAT.get(pformat))

                # Upload data as temporary RGB texture
                glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_RGB])
                self.set_alignment(width, rowstride, rgb_format)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
                set_texture_level()
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
                glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, self.texture_pixel_format, width, height, 0, pformat, GL_UNSIGNED_BYTE, img_data)

                # Draw textured RGB quad at the right coordinates
                glBegin(GL_QUADS)
                glTexCoord2i(0, 0)
                glVertex2i(x, y)
                glTexCoord2i(0, height)
                glVertex2i(x, y+height)
                glTexCoord2i(width, height)
                glVertex2i(x+width, y+height)
                glTexCoord2i(width, 0)
                glVertex2i(x+width, y)
                glEnd()

                self.paint_box(options.get("encoding"), options.get("delta", -1)>=0, x, y, width, height)

                # Present update to screen
                self.present_fbo(x, y, width, height, options.get("flush", 0))
                # present_fbo has reset state already
            fire_paint_callbacks(callbacks)
        except Exception as e:
            log("Error in %s paint of %i bytes, options=%s)", rgb_format, len(img_data), options)
            fire_paint_callbacks(callbacks, False, "OpenGL %s paint error: %s" % (rgb_format, e))
Example #13
0
 def draw_region(self, x, y, width, height, coding, img_data, rowstride,
                 _packet_sequence, options, callbacks):
     """ Note: this runs from the draw thread (not UI thread) """
     backing = self._backing
     if not backing:
         log("draw_region: window %s has no backing, gone?", self._id)
         from xpra.client.window_backing_base import fire_paint_callbacks
         fire_paint_callbacks(callbacks, -1, "no backing")
         return
     #only register this callback if we actually need it:
     if backing.draw_needs_refresh:
         if not backing.repaint_all:
             self.pending_refresh.append((x, y, width, height))
         if options.intget("flush", 0) == 0:
             callbacks.append(self.after_draw_refresh)
     backing.draw_region(x, y, width, height, coding, img_data, rowstride,
                         options, callbacks)
Example #14
0
 def do_paint_scroll(self, scrolls, callbacks):
     old_backing = self._backing
     gc = self.create_surface()
     if not gc:
         fire_paint_callbacks(callbacks, False, message="no context")
         return
     gc.set_operator(OPERATOR_SOURCE)
     for sx, sy, sw, sh, xdelta, ydelta in scrolls:
         gc.set_source_surface(old_backing, xdelta, ydelta)
         x = sx + xdelta
         y = sy + ydelta
         gc.rectangle(x, y, sw, sh)
         gc.fill()
         if self.paint_box_line_width > 0:
             self.cairo_paint_box(gc, "scroll", x, y, sw, sh)
     del gc
     self._backing.flush()
     fire_paint_callbacks(callbacks)
Example #15
0
 def do_paint_rgb24(self, img_data, x, y, width, height, rowstride, options, callbacks):
     """ must be called from UI thread """
     if DRAW_DEBUG:
         log.info("cairo_paint_rgb24(..,%s,%s,%s,%s,%s,%s,%s)", x, y, width, height, rowstride, options, callbacks)
     if self._backing is None:
         fire_paint_callbacks(callbacks, False)
         return  False
     assert PIL, "cannot paint without PIL!"
     if rowstride==0:
         rowstride = width * 3
     im = PIL.Image.frombuffer("RGB", (width, height), img_data, "raw", "RGB", rowstride)
     buf = BytesIOClass()
     im.save(buf, "PNG")
     data = buf.getvalue()
     buf.close()
     img_data = BytesIOClass(data)
     self.do_paint_png(img_data, x, y, width, height, rowstride, options, callbacks)
     return  False
Example #16
0
 def draw_region(self, x, y, width, height, coding, img_data, rowstride, packet_sequence, options, callbacks):
     """ Note: this runs from the draw thread (not UI thread) """
     backing = self._backing
     if not backing:
         log("draw_region: window %s has no backing, gone?", self._id)
         from xpra.client.window_backing_base import fire_paint_callbacks
         fire_paint_callbacks(callbacks, False)
         return
     def after_draw_refresh(success):
         plog("after_draw_refresh(%s) %sx%s at %sx%s encoding=%s, options=%s", success, width, height, x, y, coding, options)
         if not success:
             return
         backing = self._backing
         if backing and backing.draw_needs_refresh:
             self.queue_draw(x, y, width, height)
     #only register this callback if we actually need it:
     if backing.draw_needs_refresh:
         callbacks.append(after_draw_refresh)
     self._backing.draw_region(x, y, width, height, coding, img_data, rowstride, options, callbacks)
Example #17
0
 def do_paint_rgb24(self, img_data, x, y, width, height, rowstride, options, callbacks):
     """ must be called from UI thread """
     if DRAW_DEBUG:
         log.info("cairo_paint_rgb24(..,%s,%s,%s,%s,%s,%s,%s)", x, y, width, height, rowstride, options, callbacks)
     if self._backing is None:
         fire_paint_callbacks(callbacks, False)
         return  False
     PIL = get_codec("PIL")
     assert PIL, "cannot paint without PIL!"
     if rowstride==0:
         rowstride = width * 3
     im = PIL.Image.frombuffer("RGB", (width, height), img_data, "raw", "RGB", rowstride)
     buf = BytesIOClass()
     im.save(buf, "PNG")
     data = buf.getvalue()
     buf.close()
     img_data = BytesIOClass(data)
     self.do_paint_png(img_data, x, y, width, height, rowstride, options, callbacks)
     return  False
Example #18
0
 def ui_paint_image():
     if not self._backing:
         fire_paint_callbacks(callbacks, False)
         return
     try:
         if coding.startswith("png"):
             reader = BytesIOClass(img_data)
             img = cairo.ImageSurface.create_from_png(reader)
             success = self.cairo_paint_surface(img, x, y)
         else:
             assert coding == "jpeg"
             pbl = PixbufLoader()
             pbl.write(img_data)
             pbl.close()
             pixbuf = pbl.get_pixbuf()
             del pbl
             success = self.cairo_paint_pixbuf(pixbuf, x, y)
     except:
         log.error("cairo error during paint", exc_info=True)
         success = False
     fire_paint_callbacks(callbacks, success)
Example #19
0
 def ui_paint_image():
     if not self._backing:
         fire_paint_callbacks(callbacks, False)
         return
     try:
         if coding.startswith("png"):
             reader = BytesIOClass(img_data)
             img = cairo.ImageSurface.create_from_png(reader)
             success = self.cairo_paint_surface(img, x, y)
         else:
             assert coding == "jpeg"
             pbl = PixbufLoader()
             pbl.write(img_data)
             pbl.close()
             pixbuf = pbl.get_pixbuf()
             del pbl
             success = self.cairo_paint_pixbuf(pixbuf, x, y)
     except:
         log.error("cairo error during paint", exc_info=True)
         success = False
     fire_paint_callbacks(callbacks, success)
Example #20
0
    def gl_paint_planar(self, flush, encoding, img, x, y, enc_width, enc_height, width, height, callbacks):
        #this function runs in the UI thread, no video_decoder lock held
        log("gl_paint_planar%s", (flush, encoding, img, x, y, enc_width, enc_height, width, height, callbacks))
        try:
            pixel_format = img.get_pixel_format()
            assert pixel_format in ("YUV420P", "YUV422P", "YUV444P", "GBRP"), "sorry the GL backing does not handle pixel format '%s' yet!" % (pixel_format)

            context = self.gl_context()
            if not context:
                log("%s._do_paint_rgb(..) no context!", self)
                fire_paint_callbacks(callbacks, False, "failed to get a gl context")
                return
            with context:
                self.gl_init()
                self.update_planar_textures(x, y, enc_width, enc_height, img, pixel_format, scaling=(enc_width!=width or enc_height!=height))
                img.free()

                # Update FBO texture
                x_scale, y_scale = 1, 1
                if width!=enc_width or height!=enc_height:
                    x_scale = float(width)/enc_width
                    y_scale = float(height)/enc_height
                self.render_planar_update(x, y, enc_width, enc_height, x_scale, y_scale)
                self.paint_box(encoding, False, x, y, width, height)
                # Present it on screen
                self.present_fbo(x, y, width, height, flush)
            fire_paint_callbacks(callbacks, True)
            return
        except GLError as e:
            message = "gl_paint_planar error: %r" % e
        except Exception as e:
            message = "gl_paint_planar error: %s" % e
        log.error("%s.gl_paint_planar(..) error: %s", self, e, exc_info=True)
        fire_paint_callbacks(callbacks, False, message)
    def gl_paint_planar(self, flush, encoding, img, x, y, enc_width, enc_height, width, height, callbacks):
        #this function runs in the UI thread, no video_decoder lock held
        log("gl_paint_planar%s", (flush, encoding, img, x, y, enc_width, enc_height, width, height, callbacks))
        try:
            pixel_format = img.get_pixel_format()
            assert pixel_format in ("YUV420P", "YUV422P", "YUV444P", "GBRP"), "sorry the GL backing does not handle pixel format '%s' yet!" % (pixel_format)

            context = self.gl_context()
            if not context:
                log("%s._do_paint_rgb(..) no context!", self)
                fire_paint_callbacks(callbacks, False, "failed to get a gl context")
                return
            with context:
                self.gl_init()
                self.update_planar_textures(x, y, enc_width, enc_height, img, pixel_format, scaling=(enc_width!=width or enc_height!=height))

                # Update FBO texture
                x_scale, y_scale = 1, 1
                if width!=enc_width or height!=enc_height:
                    x_scale = float(width)/enc_width
                    y_scale = float(height)/enc_height
                self.render_planar_update(x, y, enc_width, enc_height, x_scale, y_scale)
                self.paint_box(encoding, False, x, y, width, height)
                # Present it on screen
                self.present_fbo(x, y, width, height, flush)
            img.free()
            fire_paint_callbacks(callbacks, True)
            return
        except GLError as e:
            message = "OpenGL %s paint error: %r" % (encoding, e)
        except Exception as e:
            message = "OpenGL %s paint error: %s" % (encoding, e)
        log.error("%s.gl_paint_planar(..) error: %s", self, e, exc_info=True)
        fire_paint_callbacks(callbacks, False, message)
Example #22
0
 def paint_pixbuf_gdk(self, coding, img_data, x, y, width, height, options, callbacks):
     """ must be called from UI thread """
     if coding.startswith("png"):
         coding = "png"
     loader = gdk.PixbufLoader(coding)
     loader.write(img_data, len(img_data))
     loader.close()
     pixbuf = loader.get_pixbuf()
     if not pixbuf:
         log.error("failed %s pixbuf=%s data len=%s" % (coding, pixbuf, len(img_data)))
         fire_paint_callbacks(callbacks, False)
         return False
     raw_data = pixbuf.get_pixels()
     rowstride = pixbuf.get_rowstride()
     img_data = self.process_delta(raw_data, width, height, rowstride, options)
     n = pixbuf.get_n_channels()
     if n == 3:
         self.do_paint_rgb24(img_data, x, y, width, height, rowstride, options, callbacks)
     else:
         assert n == 4, "invalid number of channels: %s" % n
         self.do_paint_rgb32(img_data, x, y, width, height, rowstride, options, callbacks)
     return False
Example #23
0
 def draw_region(self, x, y, width, height, coding, img_data, rowstride, packet_sequence, options, callbacks):
     """ Note: this runs from the draw thread (not UI thread) """
     backing = self._backing
     if not backing:
         log("draw_region: window %s has no backing, gone?", self._id)
         from xpra.client.window_backing_base import fire_paint_callbacks
         fire_paint_callbacks(callbacks, -1, "no backing")
         return
     def after_draw_refresh(success, message=""):
         plog("after_draw_refresh(%s, %s) %sx%s at %sx%s encoding=%s, options=%s", success, message, width, height, x, y, coding, options)
         if success<=0:
             return
         backing = self._backing
         if backing and backing.draw_needs_refresh:
             if REPAINT_ALL=="1" or self._client.xscale!=1 or self._client.yscale!=1:
                 w, h = self.get_size()
                 self.queue_draw(0, 0, w, h)
             else:
                 self.queue_draw(*self._client.srect(x, y, width, height))
     #only register this callback if we actually need it:
     if backing.draw_needs_refresh:
         callbacks.append(after_draw_refresh)
     backing.draw_region(x, y, width, height, coding, img_data, rowstride, options, callbacks)
Example #24
0
    def do_paint_rgb(self, rgb_format, img_data, x, y, width, height,
                     rowstride, options, callbacks):
        log(
            "%s.do_paint_rgb(%s, %s bytes, x=%d, y=%d, width=%d, height=%d, rowstride=%d, options=%s)",
            self, rgb_format, len(img_data), x, y, width, height, rowstride,
            options)
        context = self.gl_context()
        if not context:
            log("%s._do_paint_rgb(..) no context!", self)
            fire_paint_callbacks(callbacks, False, "no opengl context")
            return
        if not options.get("paint", True):
            fire_paint_callbacks(callbacks)
            return

        try:
            upload, img_data = self.pixels_for_upload(img_data)

            with context:
                self.gl_init()
                self.set_rgb_paint_state()

                #convert it to a GL constant:
                pformat = PIXEL_FORMAT_TO_CONSTANT.get(rgb_format.decode())
                assert pformat is not None, "could not find pixel format for %s" % rgb_format

                bytes_per_pixel = len(rgb_format)  #ie: BGRX -> 4
                # Compute alignment and row length
                row_length = 0
                alignment = 1
                for a in [2, 4, 8]:
                    # Check if we are a-aligned - ! (var & 0x1) means 2-aligned or better, 0x3 - 4-aligned and so on
                    if (rowstride & a - 1) == 0:
                        alignment = a
                # If number of extra bytes is greater than the alignment value,
                # then we also have to set row_length
                # Otherwise it remains at 0 (= width implicitely)
                if (rowstride - width * bytes_per_pixel) >= alignment:
                    row_length = width + (
                        rowstride - width * bytes_per_pixel) // bytes_per_pixel

                self.gl_marker(
                    "%s update at (%d,%d) size %dx%d (%s bytes), stride=%d, row length %d, alignment %d, using GL %s format=%s",
                    rgb_format, x, y, width, height, len(img_data), rowstride,
                    row_length, alignment, upload,
                    CONSTANT_TO_PIXEL_FORMAT.get(pformat))

                # Upload data as temporary RGB texture
                glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_RGB])
                glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length)
                glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
                                GL_TEXTURE_MAG_FILTER, GL_NEAREST)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
                                GL_TEXTURE_MIN_FILTER, GL_NEAREST)
                set_texture_level()
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S,
                                GL_CLAMP_TO_BORDER)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T,
                                GL_CLAMP_TO_BORDER)
                glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,
                             self.texture_pixel_format, width, height, 0,
                             pformat, GL_UNSIGNED_BYTE, img_data)

                # Draw textured RGB quad at the right coordinates
                glBegin(GL_QUADS)
                glTexCoord2i(0, 0)
                glVertex2i(x, y)
                glTexCoord2i(0, height)
                glVertex2i(x, y + height)
                glTexCoord2i(width, height)
                glVertex2i(x + width, y + height)
                glTexCoord2i(width, 0)
                glVertex2i(x + width, y)
                glEnd()

                self.paint_box(options.get("encoding"),
                               options.get("delta", -1) >= 0, x, y, width,
                               height)

                # Present update to screen
                self.present_fbo(x, y, width, height, options.get("flush", 0))
                # present_fbo has reset state already
            fire_paint_callbacks(callbacks)
        except Exception as e:
            log("Error in %s paint of %i bytes, options=%s)", rgb_format,
                len(img_data), options)
            fire_paint_callbacks(callbacks, False,
                                 "opengl %s paint error: %s" % (rgb_format, e))
Example #25
0
 def do_paint_scroll(self, x, y, w, h, scrolls, options, callbacks):
     gc = self._backing.new_gc()
     for sx,sy,sw,sh,xdelta,ydelta in scrolls:
         self._backing.draw_drawable(gc, self._backing, sx, sy, sx+xdelta, sy+ydelta, sw, sh)
     fire_paint_callbacks(callbacks)
Example #26
0
 def do_paint_scroll(self, x, y, w, h, scrolls, options, callbacks):
     gc = self._backing.new_gc()
     for sx,sy,sw,sh,xdelta,ydelta in scrolls:
         self._backing.draw_drawable(gc, self._backing, sx, sy, sx+xdelta, sy+ydelta, sw, sh)
     fire_paint_callbacks(callbacks)
Example #27
0
    def do_scroll_paints(self, scrolls, flush=0, callbacks=[]):
        log("do_scroll_paints%s", (scrolls, flush))
        context = self.gl_context()
        if not context:
            log.warn("Warning: cannot paint scroll, no OpenGL context!")
            return
        def fail(msg):
            log.error("Error: %s", msg)
            fire_paint_callbacks(callbacks, False, msg)
        with context:
            bw, bh = self.size
            self.set_rgb_paint_state()
            #paste from offscreen to tmp with delta offset:
            glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO])
            glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0)
            glReadBuffer(GL_COLOR_ATTACHMENT0)

            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.tmp_fbo)
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO])
            glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO], 0)
            glDrawBuffer(GL_COLOR_ATTACHMENT1)

            #copy current fbo:
            glBlitFramebuffer(0, 0, bw, bh,
                              0, 0, bw, bh,
                              GL_COLOR_BUFFER_BIT, GL_NEAREST)

            for x,y,w,h,xdelta,ydelta in scrolls:
                if abs(xdelta)>=bw:
                    fail("invalid xdelta value: %i" % xdelta)
                    continue
                if abs(ydelta)>=bh:
                    fail("invalid ydelta value: %i" % ydelta)
                    continue
                if ydelta==0 and xdelta==0:
                    fail("scroll has no delta!")
                    continue
                if w<=0 or h<=0:
                    fail("invalid scroll area size: %ix%i" % (w, h))
                    continue
                #these should be errors,
                #but desktop-scaling can cause a mismatch between the backing size
                #and the real window size server-side.. so we clamp the dimensions instead
                if x+w>bw:
                    w = bw-x
                if y+h>bh:
                    h = bh-y
                if x+w+xdelta>bw:
                    w = bw-x-xdelta
                    if w<=0:
                        continue        #nothing left!
                if y+h+ydelta>bh:
                    h = bh-y-ydelta
                    if h<=0:
                        continue        #nothing left!
                if x+xdelta<0:
                    fail("horizontal scroll by %i: rectangle %s overflows the backing buffer size %s" % (xdelta, (x, y, w, h), self.size))
                    continue
                if y+ydelta<0:
                    fail("vertical scroll by %i: rectangle %s overflows the backing buffer size %s" % (ydelta, (x, y, w, h), self.size))
                    continue
                #opengl buffer is upside down, so we must invert Y coordinates: bh-(..)
                glBlitFramebuffer(x, bh-y, x+w, bh-(y+h),
                                  x+xdelta, bh-(y+ydelta), x+w+xdelta, bh-(y+h+ydelta),
                                  GL_COLOR_BUFFER_BIT, GL_NEAREST)
                glFlush()

            #now swap references to tmp and offscreen so tmp becomes the new offscreen:
            tmp = self.offscreen_fbo
            self.offscreen_fbo = self.tmp_fbo
            self.tmp_fbo = tmp
            tmp = self.textures[TEX_FBO]
            self.textures[TEX_FBO] = self.textures[TEX_TMP_FBO]
            self.textures[TEX_TMP_FBO] = tmp

            #restore normal paint state:
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0)
            glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.offscreen_fbo)
            glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo)

            self.unset_rgb_paint_state()
            self.paint_box("scroll", True, x+xdelta, y+ydelta, x+w+xdelta, y+h+ydelta)
            self.present_fbo(0, 0, bw, bh, flush)
            fire_paint_callbacks(callbacks, True)
Example #28
0
 def fail(msg):
     log.error("Error: %s", msg)
     fire_paint_callbacks(callbacks, False, msg)
 def fail(msg):
     log.error("Error: %s", msg)
     fire_paint_callbacks(callbacks, False, msg)
    def do_scroll_paints(self, scrolls, flush=0, callbacks=[]):
        log("do_scroll_paints%s", (scrolls, flush))
        context = self.gl_context()
        if not context:
            log.warn("Warning: cannot paint scroll, no OpenGL context!")
            return
        def fail(msg):
            log.error("Error: %s", msg)
            fire_paint_callbacks(callbacks, False, msg)
        with context:
            bw, bh = self.size
            self.set_rgb_paint_state()
            #paste from offscreen to tmp with delta offset:
            glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO])
            glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0)
            glReadBuffer(GL_COLOR_ATTACHMENT0)

            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.tmp_fbo)
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO])
            glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_TMP_FBO], 0)
            glDrawBuffer(GL_COLOR_ATTACHMENT1)

            #copy current fbo:
            glBlitFramebuffer(0, 0, bw, bh,
                              0, 0, bw, bh,
                              GL_COLOR_BUFFER_BIT, GL_NEAREST)

            for x,y,w,h,xdelta,ydelta in scrolls:
                if abs(xdelta)>=bw:
                    fail("invalid xdelta value: %i" % xdelta)
                    continue
                if abs(ydelta)>=bh:
                    fail("invalid ydelta value: %i" % ydelta)
                    continue
                if ydelta==0 and xdelta==0:
                    fail("scroll has no delta!")
                    continue
                if w<=0 or h<=0:
                    fail("invalid scroll area size: %ix%i" % (w, h))
                    continue
                #these should be errors,
                #but desktop-scaling can cause a mismatch between the backing size
                #and the real window size server-side.. so we clamp the dimensions instead
                if x+w>bw:
                    w = bw-x
                if y+h>bh:
                    h = bh-y
                if x+w+xdelta>bw:
                    w = bw-x-xdelta
                    if w<=0:
                        continue        #nothing left!
                if y+h+ydelta>bh:
                    h = bh-y-ydelta
                    if h<=0:
                        continue        #nothing left!
                if x+xdelta<0:
                    fail("horizontal scroll by %i: rectangle %s overflows the backing buffer size %s" % (xdelta, (x, y, w, h), self.size))
                    continue
                if y+ydelta<0:
                    fail("vertical scroll by %i: rectangle %s overflows the backing buffer size %s" % (ydelta, (x, y, w, h), self.size))
                    continue
                #opengl buffer is upside down, so we must invert Y coordinates: bh-(..)
                glBlitFramebuffer(x, bh-y, x+w, bh-(y+h),
                                  x+xdelta, bh-(y+ydelta), x+w+xdelta, bh-(y+h+ydelta),
                                  GL_COLOR_BUFFER_BIT, GL_NEAREST)
                glFlush()

            #now swap references to tmp and offscreen so tmp becomes the new offscreen:
            tmp = self.offscreen_fbo
            self.offscreen_fbo = self.tmp_fbo
            self.tmp_fbo = tmp
            tmp = self.textures[TEX_FBO]
            self.textures[TEX_FBO] = self.textures[TEX_TMP_FBO]
            self.textures[TEX_TMP_FBO] = tmp

            #restore normal paint state:
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0)
            glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, self.offscreen_fbo)
            glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo)

            self.unset_rgb_paint_state()
            self.paint_box("scroll", True, x+xdelta, y+ydelta, x+w+xdelta, y+h+ydelta)
            self.present_fbo(0, 0, bw, bh, flush)
            fire_paint_callbacks(callbacks, True)
Example #31
0
    def do_paint_rgb(self, rgb_format, img_data, x, y, width, height, rowstride, options, callbacks):
        log("%s.do_paint_rgb(%s, %s bytes, x=%d, y=%d, width=%d, height=%d, rowstride=%d, options=%s)", self, rgb_format, len(img_data), x, y, width, height, rowstride, options)
        context = self.gl_context()
        if not context:
            log("%s._do_paint_rgb(..) no context!", self)
            fire_paint_callbacks(callbacks, False, "no opengl context")
            return
        if not options.get("paint", True):
            fire_paint_callbacks(callbacks)
            return

        try:
            upload, img_data = self.pixels_for_upload(img_data)

            with context:
                self.gl_init()
                self.set_rgb_paint_state()

                #convert it to a GL constant:
                pformat = PIXEL_FORMAT_TO_CONSTANT.get(rgb_format.decode())
                assert pformat is not None, "could not find pixel format for %s" % rgb_format

                bytes_per_pixel = len(rgb_format)       #ie: BGRX -> 4
                # Compute alignment and row length
                row_length = 0
                alignment = 1
                for a in [2, 4, 8]:
                    # Check if we are a-aligned - ! (var & 0x1) means 2-aligned or better, 0x3 - 4-aligned and so on
                    if (rowstride & a-1) == 0:
                        alignment = a
                # If number of extra bytes is greater than the alignment value,
                # then we also have to set row_length
                # Otherwise it remains at 0 (= width implicitely)
                if (rowstride - width * bytes_per_pixel) >= alignment:
                    row_length = width + (rowstride - width * bytes_per_pixel) // bytes_per_pixel

                self.gl_marker("%s update at (%d,%d) size %dx%d (%s bytes), stride=%d, row length %d, alignment %d, using GL %s format=%s",
                               rgb_format, x, y, width, height, len(img_data), rowstride, row_length, alignment, upload, CONSTANT_TO_PIXEL_FORMAT.get(pformat))

                # Upload data as temporary RGB texture
                glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_RGB])
                glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length)
                glPixelStorei(GL_UNPACK_ALIGNMENT, alignment)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
                set_texture_level()
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
                glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
                glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, self.texture_pixel_format, width, height, 0, pformat, GL_UNSIGNED_BYTE, img_data)

                # Draw textured RGB quad at the right coordinates
                glBegin(GL_QUADS)
                glTexCoord2i(0, 0)
                glVertex2i(x, y)
                glTexCoord2i(0, height)
                glVertex2i(x, y+height)
                glTexCoord2i(width, height)
                glVertex2i(x+width, y+height)
                glTexCoord2i(width, 0)
                glVertex2i(x+width, y)
                glEnd()

                self.paint_box(options.get("encoding"), options.get("delta", -1)>=0, x, y, width, height)

                # Present update to screen
                self.present_fbo(x, y, width, height, options.get("flush", 0))
                # present_fbo has reset state already
            fire_paint_callbacks(callbacks)
        except Exception as e:
            log("Error in %s paint of %i bytes, options=%s)", rgb_format, len(img_data), options)
            fire_paint_callbacks(callbacks, False, "OpenGL %s paint error: %s" % (rgb_format, e))
    def do_paint_rgb(self, rgb_format, img_data, x, y, width, height, rowstride, options, callbacks):
        log("%s.do_paint_rgb(%s, %s bytes, x=%d, y=%d, width=%d, height=%d, rowstride=%d, options=%s)",
            self, rgb_format, len(img_data), x, y, width, height, rowstride, options)
        context = self.gl_context()
        if not context:
            log("%s._do_paint_rgb(..) no context!", self)
            fire_paint_callbacks(callbacks, False, "no opengl context")
            return
        if not options.boolget("paint", True):
            fire_paint_callbacks(callbacks)
            return
        try:
            rgb_format = rgb_format.decode()
        except:
            pass
        try:
            upload, img_data = self.pixels_for_upload(img_data)

            with context:
                self.gl_init()

                #convert it to a GL constant:
                pformat = PIXEL_FORMAT_TO_CONSTANT.get(rgb_format)
                assert pformat is not None, "could not find pixel format for %s" % rgb_format
                ptype = PIXEL_FORMAT_TO_DATATYPE.get(rgb_format)
                assert pformat is not None, "could not find pixel type for %s" % rgb_format

                self.gl_marker("%s update at (%d,%d) size %dx%d (%s bytes), using GL %s format=%s / %s to internal format=%s",
                               rgb_format, x, y, width, height, len(img_data), upload, CONSTANT_TO_PIXEL_FORMAT.get(pformat), DATATYPE_TO_STR.get(ptype), INTERNAL_FORMAT_TO_STR.get(self.internal_format))

                # Upload data as temporary RGB texture
                target = GL_TEXTURE_RECTANGLE_ARB
                glEnable(target)
                glBindTexture(target, self.textures[TEX_RGB])
                self.set_alignment(width, rowstride, rgb_format)
                glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
                glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
                glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER)
                glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER)
                glTexImage2D(target, 0, self.internal_format, width, height, 0, pformat, ptype, img_data)

                # Draw textured RGB quad at the right coordinates
                glBegin(GL_QUADS)
                glTexCoord2i(0, 0)
                glVertex2i(x, y)
                glTexCoord2i(0, height)
                glVertex2i(x, y+height)
                glTexCoord2i(width, height)
                glVertex2i(x+width, y+height)
                glTexCoord2i(width, 0)
                glVertex2i(x+width, y)
                glEnd()

                glBindTexture(target, 0)
                glDisable(target)
                self.paint_box(options.strget("encoding"), options.intget("delta", -1)>=0, x, y, width, height)
                fire_paint_callbacks(callbacks)
                # Present update to screen
                self.present_fbo(x, y, width, height, options.intget("flush", 0))
                # present_fbo has reset state already
            return
        except GLError as e:
            message = "OpenGL %s paint failed: %r" % (rgb_format, e)
            log("Error in %s paint of %i bytes, options=%s", rgb_format, len(img_data), options, exc_info=True)
        except Exception as e:
            message = "OpenGL %s paint error: %s" % (rgb_format, e)
            log("Error in %s paint of %i bytes, options=%s", rgb_format, len(img_data), options, exc_info=True)
        fire_paint_callbacks(callbacks, False, message)