[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