In the case that __DRI_ATTRIB_FLOAT_BIT is set in the dri config, set
EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT in the egl config. Add a field to the
platform driver visual to indicate if it has components that are in floating
point form.
Signed-off-by: Kevin Strasser <kevin.strasser@intel.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Change dri2_add_config to take arrays of shifts and sizes, and compare with
those set in the dri config. Convert all platform driver masks
to shifts and sizes.
In order to handle older drivers, where shift attributes aren't available,
we fall back to the mask attributes and compute the shifts with ffs.
Signed-off-by: Kevin Strasser <kevin.strasser@intel.com>
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
If we're hitting the swrast fallback path here, it's probably because
we stumbled across a KMS-only device (such as the ASpeed that some of
our CI runners have) that will then return a NULL driver_name. Don't
crash in that case.
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
We get a getDrawableInfo() call in the MakeCurrent path, which
platform_device was handling correctly by returning the pbuffer's
width/height but platform_surfaceless segfaulted for. Reuse
platform_device's implementation.
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
Use the DRI2 interface callback to pass the damage rects to
the driver.
Signed-off-by: Harish Krupo <harishkrupo@gmail.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Reviewed-by: Qiang Yu <yuq825@gmail.com>
Tested-by: Qiang Yu <yuq825@gmail.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
The intension of the KHR_partial_update was not to send the damage back
to the platform but to send the damage to the driver to ensure that the
following rendering could be restricted to those regions.
This patch removes the set_damage_region from the egl_dri vtbl and all
the platfrom_*.c files.
Then upcomming patches add a new dri2 interface for the drivers to
implement
Signed-off-by: Harish Krupo <harishkrupo@gmail.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Acked-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Reviewed-by: Qiang Yu <yuq825@gmail.com>
Tested-by: Qiang Yu <yuq825@gmail.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Move the Weston os_create_anonymous_file code from egl/wayland into util,
add support for Linux memfd and FreeBSD SHM_ANON,
use that code in anv/aubinator instead of explicit memfd calls for portability.
Acked-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
>From the EGL_KHR_create_context spec:
"* If OpenGL 3.1 is requested, the context returned may implement
any of the following versions:
* Version 3.1. The GL_ARB_compatibility extension may or may
not be implemented, as determined by the implementation.
* The core profile of version 3.2 or greater."
Fixes CTS tests:
dEQP-EGL.functional.create_context_ext.gl_31.rgb888_depth_stencil
dEQP-EGL.functional.create_context_ext.robust_gl_31.rgb888_depth_stencil
dEQP-EGL.functional.create_context_ext.gl_31.rgb888_depth_no_stencil
dEQP-EGL.functional.create_context_ext.robust_gl_31.rgb888_depth_no_stencil
dEQP-EGL.functional.create_context_ext.gl_31.rgba8888_depth_no_stencil
dEQP-EGL.functional.create_context_ext.gl_31.rgb888_no_depth_no_stencil
dEQP-EGL.functional.create_context_ext.robust_gl_31.rgba8888_depth_no_stencil
dEQP-EGL.functional.create_context_ext.robust_gl_31.rgb888_no_depth_no_stencil
dEQP-EGL.functional.create_context_ext.gl_31.rgba8888_no_depth_no_stencil
dEQP-EGL.functional.create_context_ext.robust_gl_31.rgba8888_no_depth_no_stencil
dEQP-EGL.functional.create_context_ext.gl_31.rgba8888_depth_stencil
dEQP-EGL.functional.create_context_ext.robust_gl_31.rgba8888_depth_stencil
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Currently, if we error out before gbm_dri is set (say due to a different
name of the backing GBM implementation, or otherwise) the tear down will
trigger a NULL ptr deref and crash out.
Move the gbm_dri initialization as early as possible.
v2: Drop check in dri2_teardowm_drm (Eric)
Reported-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Cc: Christian Gmeiner <christian.gmeiner@gmail.com>
Cc: mesa-stable@lists.freedesktop.org
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
MAYBE_UNUSED is going away, so let's replace legitimate uses of it with
UNUSED, which the former aliased to so far anyway.
Signed-off-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
This fixes eglExportDMABUFImageQueryMESA() so it will report the
modififers of the underlying image. Without this information,
re-importing will likely be broken as it is rare these days that no
modifiers are used.
Reviewed-by: Eric Engestrom <eric@engestrom.ch>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Fixes: 8f7338f284 ("egl: add initial EGL_MESA_image_dma_buf_export v2.4")
Glamor in xorg-server 1.20 cannot expose 16bpp pixmaps when running in
the usual 24bpp mode. This meant our 565 pbuffer configs would
ultimately fail to create a backing pixmap, leading to crashes.
To hack around this, make a 16bpp pixmap and try and export it.
If it works, expose the configs. Otherwise, just skip them.
This also disables them on DRI2. These configs were only added to pass
conformance requirements, and I doubt anybody cares about testing out
565 pbuffer visuals on DRI2-only drivers.
v2: Don't leak the fds (caught by Eric Anholt)
v3: Don't free(fds), it's not malloc'd
Fixes: dacb11a585 ("egl: Add a 565 pbuffer-only EGL config under X11.")
Reviewed-by: Eric Anholt <eric@anholt.net>
In commit dacb11a585, Eric found the first
matching 565 pbuffer config, and stopped. Our double-buffered configs
come first in the list, so we added that, making a pbuffer-only config
that claimed to be double buffered. This doesn't make sense, since
pixmaps/pbuffers are fundamentally not double buffered.
When using that config, every call to eglCreatePbufferSurface would fail
with EGL_BAD_MATCH. The call chain looks like this:
- eglCreatePbufferSurface
- dri3_create_pbuffer_surface
- dri3_create_surface
- dri2_get_dri_config
which eventually does:
const bool double_buffer = surface_type == EGL_WINDOW_BIT;
and then fails to find a matching config, because it ends up looking
for a single-buffered config - and there aren't any.
To fix this, make the 565 pbuffer config single-buffered. This fixes
at least 51 dEQP-EGL.* tests.
Fixes: dacb11a585 ("egl: Add a 565 pbuffer-only EGL config under X11.")
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
pbuffer configs cause a million of these warnings to trigger, but
when using pixmaps or buffers, there is only one surface, so this
warning doesn't make much sense. Retain it for window surfaces for now.
Fixes: dacb11a585 ("egl: Add a 565 pbuffer-only EGL config under X11.")
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
color_buffers[] is currently hard coded to 3 for android which fails
in droid_window_dequeue_buffer when ANativeWindow creates color_buffers
>3 while querying buffer age during dEQP partial_update tests on chromeOS.
The patch removes static color_buffers[], queries for MIN_UNDEQUEUED_BUFFERS,
sets native window buffer count and allocates the correct number of
color_buffers as per android.
Fixes dEQP-EGL.functional.partial_update* tests on chromebooks with
enabling EGL_KHR_partial_update.
v2: update comment instead of removing (Eric Engestrom)
v3: change static array to dynamic allocated color_buffers
querying MIN_UNDEQUEUED_BUFFERS (Chia-I Wu olv@chromium.org)
Fixes: 2acc69da8c "EGL/Android: Add EGL_EXT_buffer_age extension"
Signed-off-by: Nataraj Deshpande <nataraj.deshpande@intel.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Reviewed-by: Chia-I Wu <olvaffe@gmail.com>
We can hit multi-fd EGL_NATIVE_BUFFER_ANDROID case when the native
android buffer is YUV. So we need to handle that.
Currently this went unnoticed because, even though we have two or
three fd's for YUV native android buffers, they all reference the
same backing buffer. But we really shouldn't rely on that.
Signed-off-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: Eric Engestrom <eric@engestrom.ch>
Reviewed-by: Kristian H. Kristensen <hoegsberg@google.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
Currently only 7 formats are supported, but we don't want the 16 limit
(it's an `unsigned`) to hit us by surprise :]
Let's use bitset.h's BITSET magic to allow us to have any number of
formats, with a static assert to make sure we don't forget to update it.
Signed-off-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
In the call arguments to dri2_create_drawable decouple loaderPrivate
from dri2_surf. For all callers of dri2_create_drawable the two
pointers are the same with the exception of the gbm backed platform.
Let the calling code of dri2_create_drawable decide what
loaderPrivate shall be.
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Signed-off-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
Commit 2282ec0a refactored drawable creation across various platforms
into a new dri2_create_drawable helper function.
The GBM code in platform_drm.c code passed in dri2_surf->gbm_surf as the
loaderPrivate, while most other backends passed in dri2_surf directly.
To try and handle this, the patch checked if dri2_surf->gbm_surf was
non-NULL, and if so, presumed that the caller is the DRM platform and
we should use the dri2_surf->gbm_surf pointer.
This worked for most platforms, which calloc their dri2_surf structure,
zeroing the data. Unfortunately, platform_x11.c used malloc, leaving
most of the dri2_surf as garbage. In particular, dri2_surf->gbm_surf
was often non-NULL, causing dri2_create_drawable to try and use it,
passing a garbage pointer to the createNewDrawable hook, usually leading
to a SIGBUS or SIGSEGV when trying to dereference that bad pointer.
Since most callers calloc the data, make platform_x11.c follow suit.
Fixes crashes with i915_dri.so when running dEQP-GLES2.
Reviewed-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
This new 'platform' is added by default with no guards.
It is effectively a copy of the surfaceless one, with updated function
names and brand new probe function.
Due to the reuse, some of the ifdef HAVE_SURFACELESS_PLATFORM guards
have been dropped.
A worthy mention are the changes in _egFindDisplay, since the original
and dup'd fd are required, we make use of the plat_opt argument.
Note that no hacks for eglGetDisplay are added - the API works only with
the eglGetPlatformDisplay* API.
v2:
- s/_eglCompareDeviceDisplay/_eglSameDeviceDisplay/ (Eric)
- let ^^ return bool (Eric)
- fixup meson build, move files() further up (Eric)
- copy from plat. surfaceless w/o the visual cleanups
- close and free when destroying the dpy
- sprinkle a few _eglDeviceSupports
- split fd handling into separate function
- use directly the render node if no FD is given (Mathias)
v3:
- s/dpy/disp/g
- drop swap_buffers* callbacks
- drop loader_set_logger()
- drop local define
- re-introduce _eglGetDRMDeviceRenderNode()
- EGL_WARN on ForceSoftware with HW device - continue using the HW device
- bail out for "EGL_MESA_device_software" until it's fixed
- wire-up the Android build
v4:
- use new style _eglFindDisplay()
- split hw vs sw code paths
- don't close the internal fd (already handled in FiniDisplay())
- make swrast work (bit hacky bit will do for now)
- Android for real, drop autotools
- Correct HW + LIBGL_ALWAYS_SOFTWARE check
- use the dri2_create_drawable() helper
v5:
- enhance comment around fd checks (Mathias)
- rebase for dri2_init_surface() changes
Cc: Mathias Fröhlich <Mathias.Froehlich@gmx.net>
Acked-by: Marek Olšák <marek.olsak@amd.com> (v4)
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Signed-off-by: Marek Olšák <marek.olsak@amd.com>
Wrap the loader->createNewDrawable() dance into a helper and use it
throughout the codebase.
This addresses a cases like surfaceless (SL) on swrast (SL on kms_swrast
is fine) where we'd attempt using the wrong driver and crash out.
v2: fixup quirky GBM (Mathias)
v3: fixup GBM for real (Marek)
Cc: mesa-stable@lists.freedesktop.org
Cc: Mathias Fröhlich <Mathias.Froehlich@web.de>
Reviewed-by: Mathias Fröhlich <Mathias.Froehlich@web.de> (v1)
Reviewed-by: Marek Olšák <marek.olsak@amd.com> (v1)
Signed-off-by: Emil Velikov <emil.velikov@collabora.com> (v2)
Signed-off-by: Marek Olšák <marek.olsak@amd.com> (v2)
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
At the moment the user will pass the screen number via attribs, yet we
would throw that away. Reason being that the int *screen passed to
xcb_connect() is output only.
v2 (Emil):
- split from a larger patch
- use xcb_connect() returned screen, as fallback
- use helper function only as needed
Reviewed-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Signed-off-by: Marek Olšák <marek.olsak@amd.com>
Whenever a buffer is allocated, e.g. by the first draw call or EGL call after a
buffer swap, make sure the size is up to date. Prior to this commit, we
failed to do so when querying the buffer age, or swapping buffers
without any prior EGL call or draw call.
Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Each platform stores this in a different place:
- platform_drm uses dri2_surf->gbm_surf->base
- platform_android uses dri2_surf->window
- platform_wayland uses dri2_surf->wl_win
- platform_x11 uses dri2_surf->drawable
- platform_x11_dri3 uses dri3_surf->loader_drawable.drawable
- haiku doesn't even store it!
We need access to the native surface since the specification asks us
to refuse creating a new surface if there's already an EGLSurface
associated with native_surface.
An alternative to this patch would be to create a new
API.GetNativeWindow callback that each platform would have to
implement. While that's something we can definitely do, I prefer
this approach.
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
One special case, `src/util/xmlpool/.gitignore` is not entirely deleted,
as `xmlpool.pot` still gets generated (eg. by `ninja xmlpool-pot`).
Signed-off-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
Sometimes there is no X11 platform.
Signed-off-by: Kristian H. Kristensen <hoegsberg@google.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
For formats with multiple planes, application will pass a num_planes
sized fds array which should be initialized properly in case fds amount
utilized by the driver is less than the number of planes.
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
kms_swrast can work with primary nodes out of the box, but also
with rendernodes if the build environment specifies the
EGL_FORCE_RENDERNODE flag.
Suggested-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Now the init logic fallbacks to or forces software rendering.
v2: simplify flow (@eric)
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Load the kms_swrast driver when specified.
Doesn't work with drm_gralloc.
v2: remove unneeded line (@eric)
v3: Remove swrast_loader_extensions (@evelikov)
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
This way, we can use primary nodes with kms_swrast too.
Also fix up some whitespace issues.
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Makes things easier to follow.
Suggested-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
1) Removes a forward declaration.
2) Makes next patch easier.
Suggested-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
The CTS requires a 565-no-depth-no-stencil (meaning d/s not-required, not
not-present) config for ES 3.0, but at depth 24 of X11 we wouldn't do so.
We can satisfy that bad requirement using a pbuffer-only visual with
whatever other buffers the driver happens to have given us.
I've tried to raise this as an absurd requirement with Khronos and made no
progress.
v2: Make sure it's single sample, no depth, no stencil. Comment typo fix
Reviewed-by: Adam Jackson <ajax@redhat.com>
indexConfigAttrib iterates over every index in the dri driver, possibly
exceeding __DRI_ATTRIB_MAX. In other words, if the dri driver has newer
attributes libEGL will end up reading from uninitialized memory through
dri2_to_egl_attribute_map[].
Signed-off-by: Kevin Strasser <kevin.strasser@intel.com>
Cc: mesa-stable@lists.freedesktop.org
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
virtio-gpu fallbacks to software rendering when 3D features
are unavailable since 6c5ab, and kms_swrast is more
feature complete than swrast.
v2: Add comment (Emil)
Reviewed-by: Eric Engestrom <eric@engestrom.ch>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
VGEM and kms_swrast were introduced to work with one another.
All we do is CPU rendering to dumb buffers. There is no reason to carve
out GPU memory, increasing the memory pressure on a device that could
make a better use of it.
Note:
- The original code did not work out of the box, since the dumb buffer
ioctls are not exposed to render nodes.
- This requires libdrm commit 3df8a7f0 ("xf86drm: fallback to MODALIAS
for OF less platform devices")
- The non-kms, swrast is unaffected by this change.
v2:
- elaborate what and how is/isn't working (Eric)
- simplify driver_name handling (Eric)
v3:
- move node_type outside of the loop (Eric)
- kill no longer needed DRM_RENDER_DEV_NAME define
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
This provides for a more comprehensive iteration and slightly more
straight-forward codebase.
v2:
- s/dpy/disp/
- keep original 64 devices (Eric)
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Mathias Fröhlich <Mathias.Froehlich@web.de>
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
Make the code a bit easier to read.
As a bonus point this makes it obvious that we forgot to call
_eglAddDevice() for the device - do so.
v2:
- s/dpy/disp/ (Eric)
- free(driver_name) on dri2_load_driver_swrast() failure (Eric)
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Mathias Fröhlich <Mathias.Froehlich@web.de> (v1)
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
In addition to adding this format to the dri_interface header,
add an entry in the android and wayland backends as well.
Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
It's the current maximum supported by the kernel. Stay consistent with
the rest of Mesa and use the same number.
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
The difference between the three functions is the list of mandatory
driver extensions. Pass that as an argument to the common helper.
Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Reviewed-by: Eric Engestrom <eric.engestrom@intel.com>
Fullscreening and unfullscreening a totem window while playing a video
sometimes results in the video subsurface not changing size along. This
is also reproducible with epiphany.
If a surface gets resized while we have an active back buffer for it, the
resized dimensions won't get neither immediately applied on the resize
callback, nor correctly synchronized on update_buffers(), as the
(now stale) surface size and currently attached buffer size still do match.
There's actually 2 things to synchronize here, first the surface query
size might not be updated yet to the wl_egl_window's (i.e. resize_callback
happened while there is a back buffer), and second the wayland buffers
would need dropping if new surface size differs with the currently attached
buffer. These are done in separate steps now.
https://bugzilla.redhat.com/show_bug.cgi?id=1650929https://bugs.freedesktop.org/show_bug.cgi?id=109594
Fixes: a9fb331ea7 ("wayland/egl: update surface size on window resize")
Signed-off-by: Carlos Garnacho <carlosg@gnome.org>
Reviewed-by: Juan A. Suarez <jasuarez@igalia.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Tested-by: Bastien Nocera <hadess@hadess.net>
Tested-by: Denys Kostin <denys.kostin@globallogic.com>
There was an issue recently caused by the system header being included
by mistake, so let's just get rid of this include path and always
explicitly #include "drm-uapi/FOO.h"
Signed-off-by: Eric Engestrom <eric.engestrom@intel.com>
Reviewed-by: Kristian H. Kristensen <hoegsberg@chromium.org>
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
Signed-off-by: Lin Johnson <johnson.lin@intel.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
`EGLDisplay` variables (the opaque Khronos type) have mostly been
consistently called `dpy`, as this is the name used in the Khronos
specs.
However, `_EGLDisplay` variables (our internal struct) have been
randomly called `dpy` when there was no local variable clash with
`EGLDisplay`s, and `disp` otherwise.
Let's be consistent and use `dpy` for the Khronos type, and `disp`
for our struct.
Signed-off-by: Eric Engestrom <eric.engestrom@intel.com>
Acked-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Anholt <eric@anholt.net>