[pypy-commit] lang-smalltalk bitblt: remove python BitBlt logic, add W_DisplayBitmap as model for the bitmap on the display object

timfel noreply at buildbot.pypy.org
Sat Mar 16 13:35:40 CET 2013


Author: Tim Felgentreff <timfelgentreff at gmail.com>
Branch: bitblt
Changeset: r187:dbecef62dc1b
Date: 2013-03-16 12:24 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/dbecef62dc1b/

Log:	remove python BitBlt logic, add W_DisplayBitmap as model for the
	bitmap on the display object

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -75,9 +75,8 @@
                 s_new_context = p.s_new_context
 
     def c_loop(self, s_context):
-        # if self.max_stack_depth - self.remaining_stack_depth < 10:
-        #     padding = ' ' * (self.max_stack_depth - self.remaining_stack_depth)
-        #     print padding + s_context.short_str()
+        # padding = ' ' * (self.max_stack_depth - self.remaining_stack_depth)
+        # print padding + s_context.short_str()
         old_pc = 0
         while True:
             pc = s_context._pc
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -22,6 +22,8 @@
 from rpython.rlib.rarithmetic import intmask, r_uint
 from rpython.tool.pairtype import extendabletype
 from rpython.rlib.objectmodel import instantiate
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rsdl import RSDL, RSDL_helper
 
 class W_Object(object):
     """Root of Squeak model, abstract."""
@@ -421,15 +423,6 @@
     def has_shadow(self):
         return self._shadow is not None
 
-    def as_bitblt_get_shadow(self, space):
-        from spyvm.shadow import BitBltShadow
-        return self.as_special_get_shadow(space, BitBltShadow)
-
-    def as_form_get_shadow(self, space):
-        from spyvm.shadow import FormShadow
-        return self.as_special_get_shadow(space, FormShadow)
-
-
     def become(self, w_other):
         if not isinstance(w_other, W_PointersObject):
             return False
@@ -532,6 +525,94 @@
         w_result.words = list(self.words)
         return w_result
 
+class VersionTag():
+    pass
+
+NATIVE_DEPTH = 32
+class W_DisplayBitmap(W_AbstractObjectWithClassReference):
+
+    _attrs_ = ['pixelbuffer', '_depth', '_size']
+
+    def __init__(self, w_class, size, depth):
+        W_AbstractObjectWithClassReference.__init__(self, w_class)
+        assert depth == 1 # XXX: Only support B/W for now
+        bytelen = NATIVE_DEPTH / depth * size * 4
+        self.pixelbuffer = lltype.malloc(rffi.VOIDP.TO, bytelen, flavor='raw')
+        self._depth = depth
+        self._size = size
+        self.mutate()
+
+    def __del__(self):
+        lltype.free(self.pixelbuffer, flavor='raw')
+
+    def mutate(self):
+        self.version = VersionTag()
+
+    def at0(self, space, index0):
+        return self._at0_pure(space, index0, self.version)
+
+    @jit.elidable
+    def _at0_pure(self, space, index0, version):
+        val = self.getword(index0)
+        print "Get: [%d] => %d" % (index0, val)
+        return space.wrap_uint(val)
+
+    def atput0(self, space, index0, w_value):
+        word = space.unwrap_uint(w_value)
+        print "Set: [%d] => %d" % (index0, word)
+        self.setword(index0, word)
+        self.mutate()
+
+    # XXX: Only supports 1-bit to 32-bit conversion for now
+    @jit.unroll_safe
+    def getword(self, n):
+        pixel_per_word = NATIVE_DEPTH / self._depth
+        word = r_uint(0)
+        pos = n * pixel_per_word * 4
+        for i in xrange(32):
+            red = self.pixelbuffer[pos]
+            if red == '\0': # Black
+                word &= 1
+            word <<= 1
+            pos += 4
+        return word
+
+    @jit.unroll_safe
+    def setword(self, n, word):
+        pixel_per_word = NATIVE_DEPTH / self._depth
+        word = r_uint(0)
+        pos = n * pixel_per_word * 4
+        mask = 1
+        mask <<= 31
+        for i in xrange(32):
+            bit = mask & word
+            if bit == 0: # white
+                self.pixelbuffer[pos]     = '\xff'
+                self.pixelbuffer[pos + 1] = '\xff'
+                self.pixelbuffer[pos + 2] = '\xff'
+            else:
+                self.pixelbuffer[pos]     = '\0'
+                self.pixelbuffer[pos + 1] = '\0'
+                self.pixelbuffer[pos + 2] = '\0'
+            self.pixelbuffer[pos + 3] = '\xff'
+            mask >>= 1
+            pos += 4
+
+    def size(self):
+        return self._size
+
+    def invariant(self):
+        return False
+
+    def clone(self, space):
+        w_result = W_WordsObject(self.w_class, self._size)
+        n = 0
+        while n < self._size:
+            w_result.words[n] = self.getword(n)
+            n += 1
+        return w_result
+
+
 # XXX Shouldn't compiledmethod have class reference for subclassed compiled
 # methods?
 class W_CompiledMethod(W_AbstractObjectWithIdentityHash):
diff --git a/spyvm/objspace.py b/spyvm/objspace.py
--- a/spyvm/objspace.py
+++ b/spyvm/objspace.py
@@ -11,7 +11,6 @@
         self.make_bootstrap_classes()
         self.make_bootstrap_objects()
         self._display = [None]
-        self.w_simulateCopyBits = [None]
 
     def make_bootstrap_classes(self):
         def define_core_cls(name, w_superclass, w_metaclass):
@@ -291,10 +290,6 @@
 
     def set_display(self, interp, obj):
         self._display[0] = obj
-        self.w_simulateCopyBits[0] = interp.perform(interp.space.wrap_string("simulateCopyBits"), "asSymbol")
-
-    def w_copyBitsSymbol(self):
-        return self.w_simulateCopyBits[0]
 
     def display(self):
         return self._display[0]
diff --git a/spyvm/primitives.py b/spyvm/primitives.py
--- a/spyvm/primitives.py
+++ b/spyvm/primitives.py
@@ -546,39 +546,19 @@
 
 @expose_primitive(BITBLT_COPY_BITS, unwrap_spec=[object])
 def func(interp, s_frame, w_rcvr):
-    import time
-
     if not isinstance(w_rcvr, model.W_PointersObject) or w_rcvr.size() < 15:
         raise PrimitiveFailedError
 
+    import time
     start = time.time()
     print "blitting"
-    # interp.perform(w_rcvr, "simulateCopyBits")
 
-    w_display = interp.space.objtable['w_display']
+    interp.perform(w_rcvr, "simulateCopyBits")
 
-    # See BlueBook p.356ff
-    s_bitblt = w_rcvr.as_bitblt_get_shadow(interp.space)
-    s_bitblt.clip_range()
-    if s_bitblt.w < 0 or s_bitblt.h < 0:
-        return w_rcvr # null range
-    s_bitblt.compute_masks()
-    s_bitblt.check_overlap()
-    s_bitblt.calculate_offsets()
-    start_index = s_bitblt.dest_index
-    if s_bitblt.dest_form.w_self().is_same_object(w_display):
-        s_bitblt.copy_loop(interp.space.display())
-    else:
-        bits = s_bitblt.copy_loop()    
-    end_index = s_bitblt.dest_index
-
-    # w_dest_form = w_rcvr.fetch(interp.space, 0)
-    # if w_dest_form.is_same_object(w_display):
-    #     # w_bits = w_dest_form.fetch(interp.space, 0)
-    #     # assert isinstance(w_bits, model.W_WordsObject)
-    #     # bits = w_bits.words
-    #     # print bits
-    #     interp.space.display().blit_bits(bits, start_index, end_index) # TODO: draw only as necessary
+    w_dest_form = w_rcvr.fetch(interp.space, 0)
+    if w_dest_form.is_same_object(interp.space.objtable['w_display']):
+        import pdb; pdb.set_trace()
+        interp.space.display().blit()
 
     print "blitting finshed after %d ms" % int((time.time() - start) * 1000)
     return w_rcvr
@@ -594,15 +574,26 @@
     if not isinstance(w_rcvr, model.W_PointersObject) or w_rcvr.size() < 4:
         raise PrimitiveFailedError
     # the fields required are bits (a pointer to a Bitmap), width, height, depth
-    interp.space.objtable['w_display'] = w_rcvr
 
     # XXX: TODO get the initial image TODO: figure out whether we
     # should decide the width an report it in the other SCREEN_SIZE
-    w = interp.space.unwrap_int(w_rcvr.fetch(interp.space, 1))
-    h = interp.space.unwrap_int(w_rcvr.fetch(interp.space, 2))
-    d = interp.space.unwrap_int(w_rcvr.fetch(interp.space, 3))
-    interp.space.set_display(interp, display.SDLDisplay(w, h, d))
+    w_bitmap = w_rcvr.fetch(interp.space, 0)
+    assert isinstance(w_bitmap, model.W_WordsObject) or isinstance(w_bitmap, model.W_DisplayBitmap)
+    width = interp.space.unwrap_int(w_rcvr.fetch(interp.space, 1))
+    height = interp.space.unwrap_int(w_rcvr.fetch(interp.space, 2))
+    depth = interp.space.unwrap_int(w_rcvr.fetch(interp.space, 3))
 
+    w_display_bitmap = model.W_DisplayBitmap(w_bitmap.getclass(interp.space), w_bitmap.size(), depth)
+    for idx, word in enumerate(w_bitmap.words):
+        w_display_bitmap.setword(idx, word)
+    w_rcvr.store(interp.space, 0, w_display_bitmap)
+
+    sdldisplay = display.SDLDisplay(width, height, depth)
+    sdldisplay.set_pixelbuffer(w_display_bitmap.pixelbuffer)
+    sdldisplay.blit()
+    interp.space.set_display(interp, display)
+
+    interp.space.objtable['w_display'] = w_rcvr
     return w_rcvr
 
 @expose_primitive(STRING_REPLACE, unwrap_spec=[object, index1_0, index1_0, object, index1_0])
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -72,7 +72,6 @@
 WEAK_POINTERS = 3
 COMPILED_METHOD = 4
 FLOAT = 5
-DISPLAY_SCREEN = 6
 
 class MethodNotFound(error.SmalltalkException):
     pass
@@ -1056,263 +1055,3 @@
         self.dependent = dependent
 
     def update(self): pass
-
-
-class BitBltShadow(AbstractCachingShadow):
-    _attrs_ = [# From BitBlt
-               "dest_form", "source_form", "halftone_form",
-               "combination_rule", "dest_x", "dest_y", "width",
-               "height", "source_x", "source_y", "clip_x", "clip_y",
-               "clip_width", "clip_height", "color_map",
-               # From BitBltSimulation
-               "w", "h", "sx", "sy", "dx", "dy",
-               "dest_bits", "dest_raster", "source_bits", "source_raster",
-               "halftone_bits", "skew", "mask1", "mask2", "skew_mask",
-               "n_words", "h_dir", "v_dir", "preload", "source_index",
-               "dest_index", "source_delta", "dest_delta"]
-
-    WordSize = 32
-    RightMasks = [rarithmetic.r_uint(0)]
-    for i in xrange(WordSize):
-        RightMasks.append(rarithmetic.r_uint((2 ** (i + 1)) - 1))
-    AllOnes = rarithmetic.r_uint((2 ** WordSize) - 1)
-
-    def sync_cache(self):
-        try:
-            w_form = self.fetch(0).as_form_get_shadow(self.space)
-            assert isinstance(w_form, FormShadow)
-            self.dest_form = w_form
-        except error.PrimitiveFailedError, e:
-            self.w_self()._shadow = None
-            raise e
-        w_source_form = self.fetch(1)
-        if w_source_form is self.space.w_nil:
-            self.source_form = self.dest_form
-        else:
-            try:
-                w_form = w_source_form.as_form_get_shadow(self.space)
-                assert isinstance(w_form, FormShadow)
-                self.source_form = w_form
-            except error.PrimitiveFailedError, e:
-                self.w_self()._shadow = None
-                raise e
-        w_halftone_form = self.fetch(2)
-        if w_halftone_form is not self.space.w_nil:
-            if isinstance(w_halftone_form, model.W_WordsObject):
-                # Already a bitmap
-                self.halftone_bits = w_halftone_form.words
-            else:
-                self.halftone_bits = w_halftone_form.as_form_get_shadow(self.space).bits
-        else:
-            self.halftone_bits = None
-        self.combination_rule = self.space.unwrap_int(self.fetch(3))
-        self.dest_x = self.space.unwrap_int(self.fetch(4)) - 1
-        self.dest_y = self.space.unwrap_int(self.fetch(5)) - 1
-        self.width = self.space.unwrap_int(self.fetch(6))
-        self.height = self.space.unwrap_int(self.fetch(7))
-        self.source_x = self.space.unwrap_int(self.fetch(8)) - 1
-        self.source_y = self.space.unwrap_int(self.fetch(9)) - 1
-        self.clip_x = self.space.unwrap_int(self.fetch(10)) - 1
-        self.clip_y = self.space.unwrap_int(self.fetch(11)) - 1
-        self.clip_width = self.space.unwrap_int(self.fetch(12))
-        self.clip_height = self.space.unwrap_int(self.fetch(13))
-        self.color_map = self.fetch(14)
-
-    def clip_range(self):
-        if self.dest_x >= self.clip_x:
-            self.sx = self.source_x
-            self.dx = self.dest_x
-            self.w = self.width
-        else:
-            self.sx = self.source_x + (self.clip_x - self.dest_x)
-            self.w = self.width - (self.clip_x - self.dest_x)
-            self.dx = self.clip_x
-        if self.dx + self.w > self.clip_x + self.clip_width:
-            self.w = self.w - (self.dx + self.w - (self.clip_x + self.clip_width))
-        if self.dest_x >= self.clip_y:
-            self.sy = self.source_y
-            self.dy = self.dest_y
-            self.h = self.height
-        else:
-            self.sy = self.source_y + self.clip_y - self.dest_y
-            self.h = self.height - (self.clip_y - self.dest_y)
-            self.dy = self.clip_y
-        if self.dy + self.h > self.clip_y + self.clip_height:
-            self.h = self.h - (self.dy + self.h - (self.clip_y + self.clip_height))
-        if self.sx < 0:
-            self.dx = self.dx - self.sx
-            self.w = self.w + self.sx
-            self.sx = 0
-        if self.sx + self.w > self.source_form.width:
-            self.w = self.w - (self.sx + self.w - self.source_form.width)
-        if self.sy < 0:
-            self.dy = self.dy - self.sy
-            self.h = self.h + self.sy
-            self.sy = 0
-        if self.sy + self.h > self.source_form.height:
-            self.h = self.h - (self.sy + self.h - self.source_form.height)
-
-    def compute_masks(self):
-        self.dest_bits = self.dest_form.bits
-        self.dest_raster = (self.dest_form.width - 1) / BitBltShadow.WordSize + 1
-        self.source_bits = self.source_form.bits
-        self.source_raster = (self.source_form.width - 1) / BitBltShadow.WordSize + 1
-        self.skew = (self.sx - self.dx) & (BitBltShadow.WordSize - 1)
-        start_bits = BitBltShadow.WordSize - (self.dx & (BitBltShadow.WordSize - 1))
-        self.mask1 = BitBltShadow.RightMasks[start_bits]
-        end_bits = (BitBltShadow.WordSize - 1) - ((self.dx + self.w - 1) & (BitBltShadow.WordSize - 1))
-        self.mask2 = ~BitBltShadow.RightMasks[end_bits]
-        if self.skew == 0:
-            self.skew_mask = rarithmetic.r_uint(0)
-        else:
-            self.skew_mask = BitBltShadow.RightMasks[BitBltShadow.WordSize - self.skew]
-        if self.w < start_bits:
-            self.mask1 = self.mask1 & self.mask2
-            self.mask2 = 0
-            self.n_words = 1
-        else:
-            self.n_words = (self.w - start_bits - 1) / BitBltShadow.WordSize + 2
-
-    def check_overlap(self):
-        self.h_dir = 1
-        self.v_dir = 1
-        if (self.source_form.w_self().is_same_object(self.dest_form.w_self()) and
-            self.dy >= self.sy):
-            if self.dy > self.sy:
-                self.v_dir = -1
-                self.sy = self.sy + self.h - 1
-                self.dy = self.dy + self.h - 1
-            elif self.dx > self.sx:
-                self.h_dir = -1
-                self.sx = self.sx + self.w - 1
-                self.dx = self.dx + self.w - 1
-                self.skew_mask = ~self.skew_mask
-                self.mask1, self.mask2 = self.mask2, self.mask1
-
-    def calculate_offsets(self):
-        self.preload = (self.skew_mask != 0 and
-                        self.skew <= (self.sx & (BitBltShadow.WordSize - 1)))
-        if self.h_dir < 0:
-            self.preload = not self.preload
-        self.source_index = self.sy * self.source_raster + self.sx / BitBltShadow.WordSize
-        self.dest_index = self.dy * self.dest_raster + self.dx / BitBltShadow.WordSize
-        self.source_delta = ((self.source_raster *
-                             self.v_dir -
-                             (self.n_words + (1 if self.preload else 0))) *
-                             self.h_dir)
-        self.dest_delta = self.dest_raster * self.v_dir - self.n_words * self.h_dir
-
-    def copy_loop(self, dest_surface=None):
-        for i in xrange(self.h):
-            if self.halftone_bits:
-                halftone_word = self.halftone_bits[(self.dy & (BitBltShadow.WordSize - 1)) % len(self.halftone_bits)]
-                self.dy = self.dy + self.v_dir
-            else:
-                halftone_word = BitBltShadow.AllOnes
-            skew_word = halftone_word
-            if self.preload:
-                prev_word = self.source_bits[self.source_index]
-                self.source_index = self.source_index + self.h_dir
-            else:
-                prev_word = 0
-            merge_mask = self.mask1
-            for word in xrange(self.n_words):
-                prev_word = prev_word & self.skew_mask
-                try:
-                    this_word = self.source_bits[self.source_index]
-                except IndexError:
-                    this_word = BitBltShadow.AllOnes
-                skew_word = prev_word | (this_word & ~self.skew_mask)
-                prev_word = this_word
-                skew_word = (self.bit_shift(skew_word, self.skew) |
-                             self.bit_shift(skew_word, self.skew - 16))
-                merge_word = rarithmetic.r_uint(self.merge(
-                    skew_word & halftone_word,
-                    self.dest_bits[self.dest_index]
-                ))
-                __prev = self.dest_bits[self.dest_index]
-                __new = (
-                    (merge_mask & merge_word) |
-                    (~merge_mask & self.dest_bits[self.dest_index])
-                )
-                self.dest_bits[self.dest_index] = __new
-                if dest_surface and __prev != __new:
-                    dest_surface.lock()
-                    dest_surface.draw_word(__new, self.dest_index)
-                    dest_surface.flip()
-                self.source_index = self.source_index + self.h_dir
-                self.dest_index = self.dest_index + self.h_dir
-                if word == (self.n_words - 2):
-                    merge_mask = self.mask2
-                else:
-                    merge_mask = BitBltShadow.AllOnes
-            self.source_index = self.source_index + self.source_delta
-            self.dest_index = self.dest_index + self.dest_delta
-        self.dest_form.replace_bits(self.dest_bits)
-        return self.dest_bits
-
-    def bit_shift(self, target, amount):
-        if amount > 0:
-            return (rarithmetic.r_uint(target) << amount) & BitBltShadow.AllOnes
-        else:
-            return (rarithmetic.r_uint(target) >> -amount) & BitBltShadow.AllOnes
-
-    def merge(self, source_word, dest_word):
-        if self.combination_rule == 0:
-            return 0
-        elif self.combination_rule == 1:
-            return source_word & dest_word
-        elif self.combination_rule == 2:
-            return source_word & ~dest_word
-        elif self.combination_rule == 3:
-            return source_word
-        elif self.combination_rule == 4:
-            return ~source_word & dest_word
-        elif self.combination_rule == 5:
-            return dest_word
-        elif self.combination_rule == 6:
-            return source_word ^ dest_word
-        elif self.combination_rule == 7:
-            return source_word | dest_word
-        elif self.combination_rule == 8:
-            return ~source_word & ~dest_word
-        elif self.combination_rule == 9:
-            return ~source_word ^ dest_word
-        elif self.combination_rule == 10:
-            return ~dest_word
-        elif self.combination_rule == 11:
-            return source_word | ~dest_word
-        elif self.combination_rule == 12:
-            return ~source_word
-        elif self.combination_rule == 13:
-            return ~source_word | dest_word
-        elif self.combination_rule == 14:
-            return ~source_word | ~dest_word
-        elif self.combination_rule == 15:
-            return dest_word & BitBltShadow.AllOnes
-
-
-class FormShadow(AbstractCachingShadow):
-    # _attrs_ = ["bits", "width", "height", "depth", "offset_x", "offset_y"]
-
-    def sync_cache(self):
-        self.w_bits = self.fetch(0)
-        if isinstance(self.w_bits, model.W_WordsObject):
-            self.bits = self.w_bits.words
-        else:
-            self.w_self()._shadow = None
-            raise error.PrimitiveFailedError
-        self.width = self.space.unwrap_int(self.fetch(1))
-        self.height = self.space.unwrap_int(self.fetch(2))
-        self.depth = self.space.unwrap_int(self.fetch(3))
-        w_offset = self.fetch(4)
-        if not w_offset is self.space.w_nil:
-            self.offset_x = self.space.unwrap_int(w_offset._fetch(0)) - 1
-            self.offset_y = self.space.unwrap_int(w_offset._fetch(1)) - 1
-
-    def replace_bits(self, bits):
-        if isinstance(self.w_bits, model.W_WordsObject):
-            self.w_bits.words[:] = bits
-        else:
-            self.w_self()._shadow = None
-            raise error.PrimitiveFailedError


More information about the pypy-commit mailing list