Author: Lars Wassermann <[email protected]>
Branch:
Changeset: r498:a7da58655da8
Date: 2013-07-15 20:27 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/a7da58655da8/
Log: readded RPython BitBlt code
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -92,6 +92,12 @@
def fillin(self, space, g_self):
raise NotImplementedError()
+ def getword(self, n0):
+ raise NotImplementedError()
+
+ def setword(self, n0, r_uint_value):
+ raise NotImplementedError()
+
def invariant(self):
return True
@@ -594,6 +600,14 @@
from spyvm.shadow import ObserveeShadow
return self.as_special_get_shadow(space, ObserveeShadow)
+ 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 has_shadow(self):
return self._shadow is not None
diff --git a/spyvm/primitives.py b/spyvm/primitives.py
--- a/spyvm/primitives.py
+++ b/spyvm/primitives.py
@@ -609,20 +609,48 @@
combinationRule =
interp.space.unwrap_positive_32bit_int(w_rcvr.fetch(interp.space, 3))
if combinationRule > 41:
raise PrimitiveFailedError
+
+ space = interp.space
+ import time
- space = interp.space
+ start = time.time()
+ print "blitting"
+
+ # See BlueBook p.356ff
+ s_bitblt = w_rcvr.as_bitblt_get_shadow(space)
+ s_bitblt.sync_cache()
+ 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()
try:
- s_frame._sendSelfSelector(interp.image.w_simulateCopyBits, 0, interp)
- except Return:
- w_dest_form = w_rcvr.fetch(space, 0)
- if w_dest_form.is_same_object(space.objtable['w_display']):
- w_bitmap = w_dest_form.fetch(space, 0)
- assert isinstance(w_bitmap, model.W_DisplayBitmap)
- w_bitmap.flush_to_screen()
+ s_bitblt.copy_loop()
+ except IndexError:
+ raise PrimitiveFailedError()
- # in case we return normally, we have to restore the removed w_rcvr
+ w_dest_form = w_rcvr.fetch(space, 0)
+ if w_dest_form.is_same_object(space.objtable['w_display']):
+ w_bitmap = w_dest_form.fetch(space, 0)
+ assert isinstance(w_bitmap, model.W_DisplayBitmap)
+ w_bitmap.flush_to_screen()
+
+ print "blitting finshed after %d ms" % int((time.time() - start) * 1000)
return w_rcvr
+ # try:
+ # s_frame._sendSelfSelector(interp.image.w_simulateCopyBits, 0, interp)
+ # except Return:
+ # w_dest_form = w_rcvr.fetch(space, 0)
+ # if w_dest_form.is_same_object(space.objtable['w_display']):
+ # w_bitmap = w_dest_form.fetch(space, 0)
+ # assert isinstance(w_bitmap, model.W_DisplayBitmap)
+ # w_bitmap.flush_to_screen()
+
+ # # in case we return normally, we have to restore the removed w_rcvr
+ # return w_rcvr
+
@expose_primitive(BE_CURSOR)
def func(interp, s_frame, argcount):
if not (0 <= argcount <= 1):
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -1113,3 +1113,288 @@
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(1)]
+ for i in xrange(WordSize):
+ RightMasks.append(rarithmetic.r_uint((2 ** (i + 2)) - 1))
+ AllOnes = rarithmetic.r_uint((2 ** WordSize) - 1)
+
+ def sync_cache(self):
+ try:
+ w_form = self.fetch(0)
+ assert isinstance(w_form, model.W_PointersObject)
+ s_form = w_form.as_form_get_shadow(self.space)
+ assert isinstance(s_form, FormShadow)
+ self.dest_form = s_form
+ except error.PrimitiveFailedError, e:
+ w_self = self.w_self()
+ assert isinstance(w_self, model.W_PointersObject)
+ w_self._shadow = None
+ raise e
+ w_source_form = self.fetch(1)
+ if w_source_form is self.space.w_nil:
+ self.source_form = None
+ else:
+ try:
+ w_form = w_source_form
+ assert isinstance(w_form, model.W_PointersObject)
+ s_form = w_form.as_form_get_shadow(self.space)
+ assert isinstance(s_form, FormShadow)
+ self.source_form = s_form
+ except error.PrimitiveFailedError, e:
+ w_self = self.w_self()
+ assert isinstance(w_self, model.W_PointersObject)
+ 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:
+ assert isinstance(w_halftone_form, model.W_PointersObject)
+ w_bits = w_halftone_form.as_form_get_shadow(self.space).w_bits
+ assert isinstance(w_bits, model.W_WordsObject)
+ self.halftone_bits = w_bits.words
+ 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_y >= 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.source_form is None:
+ return
+ 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.w_bits
+ self.dest_raster = (self.dest_form.width - 1) // BitBltShadow.WordSize
+ 1
+ if self.source_form is not None:
+ self.source_bits = self.source_form.w_bits
+ self.source_raster = (self.source_form.width - 1) //
BitBltShadow.WordSize + 1
+ else:
+ self.source_bits = None
+ self.source_raster = 0
+ # Halftone form is set during synchronization
+ 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 = rarithmetic.r_uint(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 is not None and
+ 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
+ assert isinstance(self.mask2, rarithmetic.r_uint)
+ self.mask1, self.mask2 = self.mask2, self.mask1
+
+ def calculate_offsets(self):
+ self.preload = (self.source_form is not None and (
+ 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):
+ space = self.space
+ no_skew_mask = ~self.skew_mask
+ for i in xrange(self.h):
+ if self.halftone_bits:
+ halftone_word = self.halftone_bits[self.dy %
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.getword(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):
+ if self.source_form is not None:
+ prev_word = prev_word & self.skew_mask
+ try:
+ this_word = self.source_bits.getword(self.source_index)
+ except IndexError:
+ this_word = self.source_bits.getword(0)
+ skew_word = prev_word | (this_word & no_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.getword(self.dest_index)
+ ))
+ __new = (
+ (merge_mask & merge_word) |
+ (~merge_mask & self.dest_bits.getword(self.dest_index))
+ )
+ self.dest_bits.setword(self.dest_index, __new)
+ self.source_index = self.source_index + self.h_dir
+ self.dest_index = self.dest_index + self.h_dir
+ if word == (self.n_words - 1):
+ 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
+
+ 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
+ else:
+ raise error.PrimitiveFailedError()
+
+
+class FormShadow(AbstractCachingShadow):
+ _attrs_ = ["w_bits", "width", "height", "depth", "offset_x", "offset_y"]
+
+ def sync_cache(self):
+ self.w_bits = self.fetch(0)
+ if not (isinstance(self.w_bits, model.W_WordsObject) or
isinstance(self.w_bits, model.W_DisplayBitmap)):
+ w_self = self.w_self()
+ assert isinstance(w_self, model.W_PointersObject)
+ 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)
+ assert isinstance(w_offset, model.W_PointersObject)
+ 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):
+ # w_bits = self.w_bits
+ # if isinstance(w_bits, model.W_WordsObject):
+ # pass
+ # elif isinstance(w_bits, model.W_DisplayBitmap):
+ # w_bits.update_from_buffer()
+ # else:
+ # w_self = self.w_self()
+ # assert isinstance(w_self, model.W_PointersObject)
+ # w_self._shadow = None
+ # raise error.PrimitiveFailedError
\ No newline at end of file
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit