summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2014-06-02glamor: Provide render fallbacks for debuggingglamor-serverKeith Packard4-1/+226
These provide a complete set of fallbacks to isolate the glamor render code from the rest of the implementation. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-06-02glamor: Remove stubbed-out glamor_stipple functionKeith Packard2-16/+0
This function isn't used anymore. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-06-02glamor: Remove 'tiling' shader codeKeith Packard4-308/+0
The core rendering paths all use the glamor_program fill functions now Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-06-02glamor: Replace glamor_solid_boxes and glamor_solid with GC using codeKeith Packard6-390/+106
This provides glamor_solid_boxes and glamor_solid using regular GC operations instead of calling directly to underlying rendering functions. This will allow the old rendering code to be removed. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-06-02glamor: Add accelerated stipple supportKeith Packard4-18/+157
This copies the stipple to a 8bpp pixmap and uses that to paint the texture from. v2: Create deep stipple pixmap without GLAMOR_CREATE_FBO_NO_FBO v3: Fix stipple origin sign (matches tiles now). Track changes to original stipple with damage. This isn't required by the X spec, but java appears to depend on it, so we'll just do it. When Glamor switches to 8bpp bitmaps, we'll be able to render directly from them and not need this anymore. v4: Review comments from Eric: * Remove stray whitespace change * Avoid "large" pixmap for stipple by using GLAMOR_CREATE_NO_LARGE * Wrap to 80 columns v5: Don't crash when stipple damage tracker is destroyed The stipple damage tracker is automatically destroyed when the associated stipple pixmap is destroyed. When this happens, just clear the pointer from the GC rather than calling glamor_invalidate_stipple; that function would call DamageUnregister on the now invalid stipple damage pointer and crash. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-06-02glamor: Kludge-around UXA not using glamor_gc_destroyKeith Packard1-0/+14
Glamor now has a bit of work to do in DestroyGC, but UXA has it's own GC funcs which don't (currently) call glamor_gc_destroy. Here's an ugly hack which swaps in a working GCFuncs array at run time. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-06-02glamor: Add glamor_program based 0-width dashed linesKeith Packard10-20/+496
This makes sure the pixelization for dashed lines matches non-dashed lines, while also speeding them up. v2: Switch to glamor_make_current v3: Create dash pattern pixmap without GLAMOR_CREATE_FBO_NO_FBO v4: Adopt suggestions from Eric's review: - Drops power-of-two alignment of our line vertex data, simplifying the code. - Stops reading from the VBO. While on keithp's and my machines the VBO is mapped cached, on many implementations it will be mapped WC, making those reads extremely expensive. - Style fixes (line wrapping, spaces around operators). v5: Adopt suggestions from Markus' review: - Use max when computing zero-width dashed line length. Don't open code max here. - Embed CoordModePrevious into VBO writing for dashed lines Instead of pre-computing the coord mode previous results, just embed this in the loop which fills the vertex buffer. Saves re-writing the request buffer, and shortens the code a bit v6: Export glamor_destroy_gc for UXA UXA needs to call glamor_destroy_gc from its GCFuncs, so export it. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-06-02glamor: Use glamor_program and GL_LINES for 0-width linesKeith Packard6-192/+361
GL lines are nearly X compliant; you just need to fill in the last pixel when the client hasn't requested CapNotLast. v2: switch to glamor_make_current v3: use miPolylines instead of custom glamor fallback path. Wrap code to 80 columns. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-06-02glamor: Use glamor_program for glamor_push_pixelsKeith Packard1-82/+50
This uses the same shaders as glamor_poly_glyph_blt. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-06-02glamor: Add glamor_program based copy accelerationKeith Packard13-789/+763
Paints with textures, using a temporary buffer for overlapping copies Performs CPU to GPU transfers for pixmaps in memory. Accelerates copy plane when both objects are in the GPU. Includes copy_window acceleration too. v2: Use NV_texture_barrier for non-overlapping copies within the same drawable v3: Switch to glamor_make_current v4: Do overlap check on the bounding box of the region rather than on individual boxes v5: Use Eric Anholt's re-written comments which provide a more accurate description of the code v6: Use floating point uniform for copy plane bit multiplier. This avoids an int to float conversion in the copy plane fragment shader. Use round() instead of adding 0.5 in copy plane. round() and +0.5 end up generating equivalent code, and performance measurements confirm that they are the same speed. Round() is a bit clearer though, so we'll use it. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Eric Anholt <eric@anholt.net> Reviewed-by: Markus Wick <markus@selfnet.de>
2014-05-23glamor: Directly reference the private key recordsKeith Packard2-15/+14
There's no reason to use a pointer here, it just wastes time. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-23glamor: Replace fallback preparation codeKeith Packard9-190/+335
These offer a simpler and more efficient means for temporarily transitioning to CPU-accessible memory for fallback implementations. v2: Do not attempt fallbacks with GLAMOR_DRM_ONLY pixmaps glamor cannot transfer pixels for GLAMOR_DRM_ONLY pixmaps using glReadPixels and glTexSubImage2D, and so there's no way to perform fallback operations with these pixmaps. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22mi: Draw multiple lines in one FillSpans call in miZeroLineKeith Packard1-8/+8
miZeroLine allocates enough space to draw a line spanning the entire width/height of the target drawable. When drawing multiple shorter lines, this leaves most of the space in that buffer unfilled. Let multiple lines be drawn into the buffer if there is plenty of space. Speeds up glamor fallback zero-width lines: Before 6000000 trep @ 0.0020 msec (508000.0/sec): 1-pixel line 6000000 trep @ 0.0020 msec (492000.0/sec): 10-pixel line 6000000 trep @ 0.0023 msec (427000.0/sec): 100-pixel line 4000000 trep @ 0.0035 msec (282000.0/sec): 500-pixel line After: 600000000 trep @ 0.0000 msec (43400000.0/sec): 1-pixel line 140000000 trep @ 0.0001 msec (13000000.0/sec): 10-pixel line 16000000 trep @ 0.0008 msec (1300000.0/sec): 100-pixel line 4000000 trep @ 0.0038 msec (261000.0/sec): 500-pixel line (500 pixel lines do not change in performance because the buffer can only one one of them.) Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22mi: Draw all points/spans for miZeroPolyArc at once if possibleKeith Packard1-6/+34
Drawing all of the spans in one driver call is a considerable performance improvement, which we can do unless the arcs are double-dashed, in which case overlapping dashes should draw the latter arc contents. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22mi: Fill spans for multiple arcs in miPolyFillArcKeith Packard1-79/+67
This allocates span data for multiple arcs and draws the whole set in one call, rather than doing them one at a time. For modern hardware, this is a significant performance improvement. v2: Limit the number of spans per buffer to 4M to avoid integer overflow in computing the malloc size. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22mi: Make miPolyArc draw fast zero-width when possibleKeith Packard3-2/+16
Instead of forcing drivers to figure out when to call miZeroPolyArc, have miPolyArc call that when possible. This involved renaming the existing miPolyArc call to miWideArc and creating a new miPolyArc wrapper function as miZeroPolyArc falls back to miWideArc when the arc is too large to be drawn with the zero-width code (ellipses larger than 800x800). Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22mi: Create miPolylines as a general-purpose line drawing functionKeith Packard2-0/+26
Instead of requiring all drivers to figure out which mi function to call for each of the four cases, create a single wrapper in mi that handles them correctly. Now drivers can simply use miPolylines in all cases. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22ephyr: Deal with non-root visual for windowKeith Packard1-10/+21
glx will sometimes select a non-root visual, deal with that by creating a suitable colormap and using that instead of attempting to use the default colormap. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22glx: Require at least one True/DirectColor visualAdam Jackson1-0/+21
Mesa no longer supports rendering to anything less. GLX 1.2 requires that the server advertise at least one GLX visual. GLX 1.3 and 1.4 are more subtle: they require at least one fbconfig capable of window rendering, and _also_ require that window-capable fbconfigs have a non-zero value for the GLX_VISUAL_ID. In either case we should refuse to init GLX if there's not at least one GL-capable visual on at least one screen. Signed-off-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22shadowfb: Fix initializationAdam Jackson1-11/+15
This has to run at initial CreateWindow time, at CreateScreenResources the root window doesn't actually exist yet. Tested-by: Michael Thayer <michael.thayer@oracle.com> Signed-off-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Michael Thayer <michael.thayer@oracle.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22glxproxy: Fix memory leak on error path in CreateGLXPixmap (#50281) (v2)Adam Jackson1-0/+2
v2: Fix another path spotted by keithp Signed-off-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Jasper St. Pierre <jstpierre@mecheye.net> Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22dmx: Fix memory leak in dmxBELoadFont (#50281)Adam Jackson1-1/+1
Signed-off-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Jasper St. Pierre <jstpierre@mecheye.net> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22dri2: Fix detection of wrong prime_id in GetScreenPrime.Michal Srb1-4/+2
Checking the iterating variable ("slave") against null can not detect if the xorg_list_for_each_entry finished without break being invoked - slave variable will be always non-null. This caused segfault whenever someone tried to use DRI_PRIME with incorrect id while having at least one render offloading slave configured. Restructurize the GetScreenPrime to work as expected. Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-22ARC: Add support for ARC architectureAlexey Brodkin3-3/+17
Xorg server could be built for and run on Synopsys DesignWare ARC cores. These changes are required for successful building and execution of the server. Both little-endian and big-endian flavors of ARC cores are supported. Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com> Acked-by: Adam Jackson <ajax@redhat.com> Reviewed-by: Egbert Eich <eich@freedesktop.org> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-12rrcrtc: brackets are hard, lets go shopping.Dave Airlie1-3/+4
Slaving two outputs on a secondary GPU to a primary GPU testing picked this up, in that we'd try to resize to the totally the wrong thing, then as usual segfault in the rotation code. Signed-off-by: Dave Airlie <airlied@redhat.com> Reviewed-by: Aaron Plattner <aplattner@nvidia.com>
2014-05-12glamor: Don't forget to check whether we can fall back in polysegment.Eric Anholt1-3/+8
Part of the _nf contract is that glamor will only return FALSE if glamor has checked that UXA can actually map the pixmaps (UXA only allocates the BO itself in the screen pixmap and DRI2 cases, and can't map it otherwise). Fixes server segfaults zooming in and out of libreoffice spreadsheets. Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-12xfree86: fix warnings after MatchSeat patchLaércio de Sousa1-12/+12
This patch fixes some compile warnings that arise after commit 7070ebeebaca1b51f8a2801989120784a1c374ae (xfree86: add new key MatchSeat to xorg.conf sections "Device", "Screen", and "ServerLayout") available at git repository git://people.freedesktop.org/~whot/xserver for-keith Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-12glamor: Stop disabling asserts by default.Eric Anholt1-3/+0
Disabling asserts is something the user gets to manage. Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-05-08Xi: don't copy a DeviceEvent into an InternalEventPeter Hutterer1-8/+8
==26141== Invalid read of size 8 ==26141== at 0x58FAEA: DeliverEmulatedMotionEvent (exevents.c:1484) An InternalEvent is bigger than a DeviceEvent, thus copying one to the other reads past the allocated boundary. Shouldn't have any real effect since we shouldn't access anything past the DeviceEvent boundary if the event type is correct. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Keith Packard <keithp@keithp.com>
2014-05-08mi: start calculating the sprite trace from the first child of rootPeter Hutterer1-1/+1
Introduced in 73698d41e41ce76bef2d9a90b46ac0c24ae148dd "Make XYToWindow a screen function" Moving the code into miwindow.c changed the start of the loop from RootWindow()->firstChild to DeepestSpriteWindow(). This function is only supposed to be called from miXYToWindow which resets spriteTraceGood to 1, thus DeepestSpriteWindow() is always the root window anyway. What got dropped was the firstChild as the first window to handle, so we may end up with the root window twice in the sprite trace. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Keith Packard <keithp@keithp.com>
2014-05-08Merge commit 'who/for-keith'Keith Packard14-28/+87
Skipping two unreviewed patches; will mark them reviewed and cherry pick
2014-05-05glamor: Publish change_window_attributes and copy_windowKeith Packard2-5/+3
Because uxa doesn't just use glamor directly, it keeps these two functions from being wrapped so that they get called automatically. Publishing these will allow uxa to call them directly. Signed-off-by: Keith Packard <keithp@keithp.com> Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-05-05glamor: Work around libXfont when it fails to use defaultCharKeith Packard1-10/+24
GetGlyphs is supposed to always return the full list of characters when there is a default character available. However, if an application opens a 16-bit two dimensional font and then draws with 8-bit requests, the bitmapGetGlyphs function in libXfont versions up through 1.4.7 will return zero glyphs if there is no 0th row. While this is a bug in libXfont and should be fixed there, it's easy to protect glamor from it by simply falling through to the case that handles GetGlyphs failures for fonts without a default character. Signed-off-by: Keith Packard <keithp@keithp.com> Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-05-05glamor: Fix uxa-entry point for ImageText16Keith Packard1-1/+1
Was interpreting the incoming chars as 8-bits instead of 16-bits, resulting in the wrong characters being drawn. Signed-off-by: Keith Packard <keithp@keithp.com> Signed-off-by: Eric Anholt <eric@anholt.net> Reviewed-by: Eric Anholt <eric@anholt.net>
2014-05-05systemd-logind: let the logind code decided whether to close an fdPeter Hutterer6-17/+14
We can only request one fd per device from systemd-logind. If a fd is re-used by the same device, releasing the fd from one device doesn't mean we can close it. The systemd code knows when it's really released, so let it close the fd. Test case: xorg.conf section for an input device with hotplugging enabled. evdev detects the duplicate and closes the hotplugged device, which closes the fd. The other instance of evdev thinks the fd is still valid so now you're playing a double lottery. First, which client(s) will get the evdev fd? Second, which requests will be picked up by evdev and which ones will be picked up by the client? You'll never know, but the fun is in finding out. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Hans de Goede <hdegoede@redhat.com>
2014-05-01hw/xfree86: Video Driver ABI version 18.0Keith Packard1-1/+1
With the change in the cursor interface in 4c3932620c29c91dfbbc8eb09c84efcaa7ec873e, we need to bump the video driver ABI number to ensure that drivers are rebuilt to match the new interface. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Aaron Plattner <aplattner@nvidia.com>
2014-05-01xfree86: add short description about MatchSeat key in xorg.conf man pageLaércio de Sousa1-0/+24
Signed-off-by: Laércio de Sousa <lbsousajr@gmail.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-05-01xfree86: add new key MatchSeat to xorg.conf sections "Device", "Screen", and ↵Oleg Samarin6-9/+47
"ServerLayout" This patch introduces a new key MatchSeat in xorg.conf (also applies to any .conf file in xorg.conf.d). It will allow targeting a given "Device", "Screen", and/or "ServerLayout" section to a particular seat only (specified by option "-seat" in X server command line), so that other seats won't be affected. Without this patch, one needs to write a separate xorg.conf.custom file and pass it to X server via "-config" option, if one wants that these settings only apply for the right seat. However, in some cases, this solution is undesirable or even impossible (e.g. when using GDM, which doesn't allow X server command line customization). Example file (/etc/X11/xorg.conf.d/seat1.conf), which would be ignored by X server unless it was started with "-seat seat1" option: Section "Device" Identifier "card0" Driver "nvidia" Option "NoLogo" "True" MatchSeat "seat1" EndSection Signed-off-by: Oleg Samarin <osamarin68@gmail.com> Signed-off-by: Laércio de Sousa <lbsousajr@gmail.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-05-01xfree86: allow fallback to PCI bus probe for graphics devices on non-seat0 X ↵Laércio de Sousa1-2/+2
servers (#66851) Currently non-seat0 X servers only probe platform bus for graphics devices, which is OK for most KMS-compliant drivers. However, for non-KMS drivers (like NVIDIA proprietary ones), graphics devices can't be reached by platform bus probe, resulting in a "No devices detected" error. This patch allows a fallback to PCI bus probe for non-seat0 X servers in case no platform bus graphics device is found. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=66851 Signed-off-by: Laércio de Sousa <lbsousajr@gmail.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-30os: Add -displayfd into -help textRobert Ancell1-0/+1
Add -displayfd into -help text. It was mentioned in the man page but seem to have been missed from the -help text. Signed-off-by: Keith Packard <keithp@keithp.com>
2014-04-30selinux: don't checkout for AVCs on select() EINTRRay Strode1-2/+2
wakeup handlers are called even when select() returns EINTR, and when they're called the passed fd set is undefined. This commit fixes the selinux wakeup handler to avoid checking for AVCs over the netlink socket spuriously. Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Ray Strode <rstrode@redhat.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-04-30dbus: don't dispatch dbus events on select() EINTRRay Strode1-2/+2
wakeup handlers are called even when select() returns EINTR, and when they're called the passed fd set is undefined. This commit fixes the dbus wakeup handler to avoid dispatching into dbus spuriously. Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Ray Strode <rstrode@redhat.com> Signed-off-by: Keith Packard <keithp@keithp.com>
2014-04-29Merge remote-tracking branch 'whot/for-keith'Keith Packard2-11/+0
2014-04-29dix: remove a now-superfluous commentPeter Hutterer1-6/+0
Obsolete since 93945b0a74aa8156a88f52b8ba77f1210042f396 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-29input: Remove invalid bug checks.Michal Srb1-5/+0
Commit 2f1aedcaed8fd99b823d451bf1fb02330c078f67 added several bug checks. Some of them are not correct. Checks in Init(Ptr|String|Bell|Led|Integer)FeedbackClassDeviceStruct verify that no feedback struct was set yet, but that is not required. If any feedback structs are already present, the function will chain them behind the new one. Signed-off-by: Michal Srb <msrb@suse.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2014-04-27xfree86: int10: Fix build on ARMThierry Reding1-1/+0
Commit 7353ec7cb6fc235b03e59e35425201429c83ee72 "xfree86: Switch int10 code to stdint types" uses designated initializers to setup the fields of the X86EMU_pioFuncs. This breaks compilation on ARM, since out{b,w,l}() are redefined using the preprocessor and therefore cause the compiler to complain about non-existent fields being assigned to. It seems like the compiler.h header that contains these redefinitions isn't actually needed in xf86x86emu.c, so the easiest "fix" is to not include it. Signed-off-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Rob Clark <robdclark@gmail.com>
2014-04-27int10: fix build errorRob Clark1-1/+1
Fixes: stub.c:66:1: error: conflicting types for 'xf86int10Addr' In file included from stub.c:14:0: xf86int10.h:72:53: note: previous declaration of 'xf86int10Addr' was here Signed-off-by: Rob Clark <robdclark@gmail.com>
2014-04-27default to stub int10 implementation on armRob Clark1-0/+1
There should be no reason to need a real int10 implementation on arm, and switching to stub is an easy way to fix: xf86x86emu.c: In function 'xf86Int10ExecSetup': xf86x86emu.c:56:9: error: unknown field 'xf_outb' specified in initializer xf86x86emu.c:57:9: error: unknown field 'xf_outw' specified in initializer xf86x86emu.c:58:9: error: unknown field 'xf_outl' specified in initializer which is caused by the following in compiler.h: #define outb xf_outb #define outw xf_outw #define outl xf_outl Signed-off-by: Rob Clark <robdclark@gmail.com> Acked-by: Daniel Stone <daniels@collabora.com>
2014-04-25hw/xfree86: Restore API compatibility for cursor loading functionsKeith Packard6-25/+95
Create load_cursor_image_check, load_cursor_argb_check, LoadCursorImageCheck and LoadCursorARGBCheck that can return failure and use them in preference to the old unchecked variants. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Michael Thayer <michael.thayer@oracle.com>
2014-04-23Add a command line argument for disabling indirect GLX.Eric Anholt3-0/+20
The attack surface for indirect GLX is huge, and it's of no use to most people (if you get an indirect GL context, you're better served by a immediate X error than actually trying to use an indirect GL context and finding out that it doesn't support doing anything you want, slowly). This flag gives you a chance to disable indirect GLX in environments where you just don't need it. I put in both the '+' and '-' arguments right now, so that it's easy to patch the value to change the default policy. Signed-off-by: Eric Anholt <eric@anholt.net> Acked-by: Julien Cristau <jcristau@debian.org> Reviewed-by: Keith Packard <keithp@keithp.com> Signed-off-by: Keith Packard <keithp@keithp.com>