| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
| |
Only used indirectly when checking dirty.st != 0
v2: also update st_cb_compute.c
Reviewed-by: Ilia Mirkin <[email protected]>
|
|
|
|
|
| |
Signed-off-by: Ilia Mirkin <[email protected]>
Reviewed-by: Nicolai Hähnle <[email protected]>
|
|
|
|
|
| |
Signed-off-by: Ilia Mirkin <[email protected]>
Reviewed-by: Nicolai Hähnle <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
intel_alloc_private_renderbuffer_storage did:
rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
Unfortunately, internalFormat was usually an unsized format (such as
GL_DEPTH_COMPONENT). In OpenGL ES, _mesa_base_fbo_format() refuses to
accept unsized formats, and returns 0 rather than a real base format.
This meant that we ended up with a completely bogus rb->_BaseFormat for
window system buffers on OpenGL ES. All other renderbuffer allocation
functions in intel_fbo.c instead use the mesa_format, and do:
rb->_BaseFormat = _mesa_get_format_base_format(...);
We can do likewise, using rb->Format. This appears to work just fine.
dEQP-GLES3.functional.state_query.fbo.framebuffer_attachment_x_size_initial
failed, as it tried to perform a GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE query
on the window system depth buffer. That query relies on a proper
rb->_BaseFormat being set, so it broke because rb->_BaseFormat was 0 due
to the above bug.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94458
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Iago Toral Quiroga <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
According to the GL 4.4 core specification, section 2.2.2 ("Data
Conversions For State Query Commands"):
"If a command returning integer data is called, such as GetIntegerv or
GetInteger64v, a boolean value of TRUE or FALSE is interpreted as one
or zero, respectively. A floating-point value is rounded to the nearest
integer, unless the value is an RGBA color component, a DepthRange
value, or a depth buffer clear value. In these cases, the query command
converts the floating-point value to an integer according to the INT
entry of table 18.2; a value not in [−1, 1] converts to an undefined
value."
The INT entry of table 18.2 shows that b = 32, meaning the expectation
is to convert it to a 32-bit integer value.
Fixes:
dEQP-GLES3.functional.state_query.floats.blend_color_getinteger64
dEQP-GLES3.functional.state_query.floats.color_clear_value_getinteger64
dEQP-GLES3.functional.state_query.floats.depth_clear_value_getinteger64
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94456
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
| |
Signed-off-by: Emil Velikov <[email protected]>
|
|
|
|
| |
Signed-off-by: Emil Velikov <[email protected]>
|
|
|
|
| |
Signed-off-by: Emil Velikov <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The reason is that the shader image atoms call st_finalize_texture, which
may set ST_NEW_FRAMEBUFFER.
This fixes an assertion triggered by a subtest of piglit's
arb_shader_image_load_store-invalid.
v2: add comment explaining order constraints (suggested by Ilia)
Reviewed-by: Ilia Mirkin <[email protected]>
Reviewed-by: Marek Olšák <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
For Haswell, we need to initialize the SLM index in the state
register. This can be copied out of the CS header dword 0.
v2:
* Use UW move to avoid changing upper 16-bits of sr0.1 (mattst88)
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94081
Fixes: piglit arb_compute_shader/execution/shared-atomics.shader_test
Signed-off-by: Jordan Justen <[email protected]>
Cc: "11.2" <[email protected]>
Tested-by: Ilia Mirkin <[email protected]> (v1)
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
|
|
|
| |
If the local workgroup size is sufficiently large, then the SIMD8
program can't be used. In this case we can skip generating the SIMD8
program. For complex programs this can save a significant amount of
time.
Signed-off-by: Jordan Justen <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
For fragment shaders, we can always use a SIMD8 program. Therefore, if
we detect spilling with a SIMD16 program, then it is better to skip
generating a SIMD16 program to only rely on a SIMD8 program.
Unfortunately, this doesn't work for compute shaders. For a compute
shader, we may be required to use SIMD16 if the local workgroup size
is bigger than a certain size. For example, on gen7, if the local
workgroup size is larger than 512, then a SIMD16 program is required.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=93840
Signed-off-by: Jordan Justen <[email protected]>
Cc: "11.2" <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The ES 3.0+ specifications contain the exact same text as the OpenGL
specification, which says that we should return GL_INVALID_OPERATION.
ES 2.0 contains different text saying we should return GL_INVALID_ENUM.
Previously, Mesa chose the error code based on API (GL vs. ES).
This patch makes ES 3.0+ follow the GL behavior. ES 2 remains as is.
Fixes dEQP-GLES3.functional.fbo.api.attachment_query_empty_fbo.
However, breaks the dEQP-GLES2 variant of the same test for drivers
which silently promote to ES 3.0. This can be worked around by
exporting MESA_GLES_VERSION_OVERRIDE=2.0, but is a bug in dEQP-GLES2.
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Ian Romanick <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The dEQP-GLES3.functional.fbo.completeness.renderable.texture.
{color0,depth,stencil}.{red,rg}_unsigned_byte tests appear to expect
GL_RED/GL_RG and GL_UNSIGNED_BYTE to map to GL_R8/GL_RG8, rather than
returning an INVALID_OPERATION error.
This makes perfect sense. However, RED and RG are strangely missing
from the ES 3.0/3.1/3.2 spec's "Effective internal format corresponding
to external format and type" tables. It may be worth filing a spec bug.
Fixes the 6 dEQP tests mentioned above.
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Alejandro Piñeiro <[email protected]>
|
|
|
|
|
|
|
| |
"using namespace brw::surface_access" is already present at the
top of the source file.
Reviewed-by: Iago Toral Quiroga <[email protected]>
|
|
|
|
| |
Reviewed-by: Vinson Lee <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
Only enable it when we compile the state tracker as well.
Signed-off-by: Christian König <[email protected]>
Reviewed-by: Ilia Mirkin <[email protected]>
|
|
|
|
|
|
|
| |
Now that brw_vec4_visitor::emit_untyped_atomic was removed, there is no need
to explicitly set it.
Reviewed-by: Francisco Jerez <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
brw_vec4_visitor
surface_access emit_untyped_read and emit_untyped_atomic provides the same
functionality.
v2: surface parameter of emit_untyped_atomic is a const, no need to
specify default predicate on emit_untyped_atomic, use retype
(Francisco Jerez).
Reviewed-by: Francisco Jerez <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
| |
If the src is invalid, so src size is zero, the src_sz passed to emit
send should be zero too, instead of a default 1 if we are in a simd4x2
case. This can happens if using emit_untyped_atomic for an atomic
dec/inc.
v2: use the proper src_sz when calling emit_send, instead of just
avoid loading src at emit_send if BAD_FILE (Francisco Jerez)
Reviewed-by: Francisco Jerez <[email protected]>
|
|
|
|
|
|
|
| |
This is not API facing, so just use bool.
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If glGenerateMipmap was called with a bogus target, then it would
pass that to _mesa_get_current_tex_object(), which would raise a
_mesa_problem() telling people to file bugs. We'd then do the
proper error checking, raise an error, and bail.
Doing the check first avoids the _mesa_problem(). The DSA variant
doesn't take a target parameter, so we leave the target validation
exactly as it was in that case.
Fixes one dEQP GLES2 test:
dEQP-GLES2.functional.negative_api.texture.generatemipmap.invalid_target.
v2: Rebase on Antia's recent patch to this area.
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Brian Paul <[email protected]> [v1]
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
|
|
|
| |
In the rather unusual case of Bind + Delete, we need to make sure that
we unbind the current tf object.
Fixes dEQP-GLES3.functional.lifetime.delete_bound.transform_feedback
Signed-off-by: Ilia Mirkin <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This simplifies the code that iterates over the per-component values
found in the matching copy_entry struct and checks whether the
register regions that were copied to each component are similar enough
to be treated as a single (reswizzled) value which can be propagated
into the current instruction.
Aside from being scattered between opt_copy_propagation(),
try_copy_propagate(), and try_constant_propagate(), what I found
terribly confusing about the preexisting logic was that
opt_copy_propagation() tried to reorder the array of values according
to the swizzle of the instruction source, which meant one would have
had to invert the reordering applied at the top level in order to find
out which component to take from each value (we were just taking the
i-th component from the i-th value, which is not correct in general).
The saturate mask was also being swizzled incorrectly.
This consolidates the logic for matching multiple components of a
copy_entry into a single function which returns the result as a
regular src_reg on success, as if the copy had been performed with a
single MOV instruction copying all components of the src_reg into the
destination.
Fixes several ARB_vertex_program MOV test-cases from:
https://cgit.freedesktop.org/~kwg/piglit/log/?h=arb_program
Acked-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
| |
It cannot get any better.
Reviewed-by: Iago Toral Quiroga <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
| |
Reviewed-by: Iago Toral Quiroga <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Scalar immediates used to be handled correctly by swizzle() (as the
identity) but since commit 58fa9d47b536403c4e3ca5d6a2495691338388fd it
will corrupt the contents of the immediate. Vector immediates were
never handled correctly, but we had ad-hoc code to swizzle VF
immediates in the vec4 copy propagation pass. This takes care of
swizzling V and UV in addition.
v2: Don't implement swizzling of V/UV immediates (Matt). If you need
to swizzle an integer vector immediate in the future apply the
following diff to go back to v1:
--- a/src/mesa/drivers/dri/i965/brw_eu.c
+++ b/src/mesa/drivers/dri/i965/brw_eu.c
@@ -119,11 +119,10 @@ brw_swap_cmod(uint32_t cmod)
static unsigned
imm_shift(enum brw_reg_type type, unsigned i)
{
- assert(type != BRW_REGISTER_TYPE_UV && type != BRW_REGISTER_TYPE_V &&
- "Not implemented.");
-
if (type == BRW_REGISTER_TYPE_VF)
return 8 * (i & 3);
+ else if (type == BRW_REGISTER_TYPE_UV || type == BRW_REGISTER_TYPE_V)
+ return 4 * (i & 7);
else
return 0;
}
Reviewed-by: Iago Toral Quiroga <[email protected]>
|
|
|
|
|
|
|
|
| |
And replace brw_swizzle1() with brw_swizzle(). Seems slightly cleaner
and will allow reusing brw_swizzle() in the vec4 back-end more easily.
Reviewed-by: Iago Toral Quiroga <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
| |
The OES extensions clarify this behaviour to differentiate between
per-sample invocation and per-sample interpolation. Using sampleid/pos
will force per-sample invocation but not per-sample interpolation.
See https://www.khronos.org/bugzilla/show_bug.cgi?id=1462
Signed-off-by: Ilia Mirkin <[email protected]>
Reviewed-by: Marek Olšák <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Since commit 922be4eab, the expectation is that the query result
contains the correct value. Unfortunately swrast does not distinguish
between GL_SAMPLES_PASSED and GL_ANY_SAMPLES_PASSED. As a result, we
must fix up the query result in a post-draw fixup.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94274
Signed-off-by: Ilia Mirkin <[email protected]>
Tested-by: Vinson Lee <[email protected]>
Reviewed-by: Brian Paul <[email protected]>
Cc: "11.2" <[email protected]>
|
|
|
|
| |
Reviewed-by: Eduardo Lima Mitev <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When BaseLevel > 0, we magnify the dimensions to fill out the size of
miplevels [0..BaseLevel). In particular, this was magnifying depth,
thinking that the depth doubles at each level. This is perfectly
reasonable for 3D textures, but dead wrong for array textures.
Changing the depth != 1 condition to a target == GL_TEXTURE_3D check
should make this only happen in the appropriate cases.
Fixes about 32 dEQP tests:
- dEQP-GLES31.functional.texture.gather.*.level_{1,2}
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Matt Turner <[email protected]>
Cc: [email protected]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
opt_vector_float() transforms several scalar MOV operations to a single
vectorial MOV.
This is done when those MOV covers all the components of the destination
register. So something like:
mov vgrf3.0.xy:D, 0D
mov vgrf3.0.w:D, 1065353216D
mov vgrf3.0.z:D, 0D
is transformed in:
mov vgrf3.0:F, [0F, 0F, 0F, 1F]
But there are cases where not all the components are written. For
example, in:
mov vgrf2.0.x:D, 1073741824D
mov vgrf3.0.xy:D, 0D
mov vgrf3.0.w:D, 1065353216D
mov vgrf4.0.xy:D, 1065353216D
mov vgrf4.0.w:D, 0D
mov vgrf6.0:UD, u4.xyzw:UD
Nor vgrf3 nor vgrf4 .z components are written, so the optimization is
not applied.
But it could be applied anyway with the components covered, using a
writemask to select the ones written. So we could transform it in:
mov vgrf2.0.x:D, 1073741824D
mov vgrf3.0.xyw:F, [0F, 0F, 0F, 1F]
mov vgrf4.0.xyw:F, [1F, 1F, 0F, 0F]
mov vgrf6.0:UD, u4.xyzw:UD
This commit does precisely that: opportunistically apply
opt_vector_float() when possible.
total instructions in shared programs: 7124660 -> 7114784 (-0.14%)
instructions in affected programs: 443078 -> 433202 (-2.23%)
helped: 4998
HURT: 0
total cycles in shared programs: 64757760 -> 64728016 (-0.05%)
cycles in affected programs: 1401686 -> 1371942 (-2.12%)
helped: 3243
HURT: 38
v2: change vectorize_mov() signature (Matt).
v3: take in account predicates (Juan).
v4 [mattst88]: Update shader-db numbers. Fix some whitespace issues.
Reviewed-by: Matt Turner <[email protected]>
Signed-off-by: Juan A. Suarez Romero <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
instructions in affected programs: 31535 -> 29966 (-4.98%)
helped: 23
cycles in affected programs: 272648 -> 266022 (-2.43%)
helped: 14
HURT: 1
The patch decreases the number of instructions in the two Unigine
programs by:
#1721: 4374 -> 4155 instructions (-5.01%)
#1706: 3582 -> 3363 instructions (-6.11%)
Reviewed-by: Kenneth Graunke <[email protected]>
Reviewed-by: Iago Toral Quiroga <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
dEQP-GLES31.functional.fbo.no_attachments.maximums.{all,height,size,width}
started hitting assertion failures when emitting SURFACE_STATE, after
commit e8fd60e7891c7 where Samuel increased the maximum viewport size to
32768, from 16384.
MaxFramebufferWidth/Height were being set to the maximum viewport size,
but are actually limited by the SURFACE_STATE width/height field range,
which is 16384 on Gen7+ (where ARB_framebuffer_no_attachments is
exposed). So, reduce these to 16384 explicitly.
Fixes assert fails in the above mentioned dEQP tests. (Those tests
still fail, however.)
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Samuel Iglesias Gonsálvez <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
From section 6.2 ("State Tables") of the GL 2.1 specification
(the text also appears in the GL 3.0 and ES 3.1 specifications):
"However, state variables for which IsEnabled is listed as the query
command can also be obtained using GetBooleanv, GetIntegerv, GetFloatv,
and GetDoublev."
GL_DEBUG_OUTPUT, GL_DEBUG_OUTPUT_SYNCHRONOUS, and GL_FRAGMENT_SHADER_ATI
were missing from the glGet*() functions. All other IsEnabled() pnames
look to be present, as far as I can tell.
Fixes 8 dEQP-GLES31.functional.debug.state_query subtests:
debug_output[_synchronous]_get{boolean,float,integer,integer64}.
Cc: [email protected]
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Ilia Mirkin <[email protected]>
Reviewed-by: Emil Velikov <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
dEQP-GLES31.functional.debug.state_query.debug_group_stack_depth_*
tries to call glGet on GL_DEBUG_GROUP_STACK_DEPTH right away, before
doing any other debug setup. This should return 1.
However, because ctx->Debug wasn't allocated, we bailed and returned 0.
This patch removes the open-coded locking and switches the two glGet
functions to use _mesa_lock_debug_state(), which takes care of
allocating and initializing that state on the first time. It also
conveniently takes care of unlocking on failure for us, so we don't
need to handle that in every caller.
Fixes dEQP-GLES31.functional.debug.state_query.debug_group_stack_depth_
{getboolean,getfloat,getinteger,getinteger64}.
Cc: [email protected]
Signed-off-by: Kenneth Graunke <[email protected]>
Reviewed-by: Ilia Mirkin <[email protected]>
Reviewed-by: Timothy Arceri <[email protected]>
Reviewed-by: Emil Velikov <[email protected]>
|
|
|
|
| |
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This pname is tricky. The spec states that an internal format should be
returned, that is compatible with the passed internal format, and has
at least the same precision. There is no clear API to resolve this.
The closest we have (and what other drivers (i.e, NVidia proprietary) do,
is to return the same internal format given as parameter. But we validate
first that the passed internal format is supported by i965.
To check for support, we have the TextureFormatSupported map'. But
this map expects a 'mesa_format', which takes a format+typen. So, we must
first "come up" with a generic type that is suited for this internal format,
then get a mesa_format, and then do the validation.
The cleanest solution here is to add a method that does exactly what
the spec wants: a driver's preferred internal format from a given
internal format. But at this point we lack a clear view of what
defines this preference, and also there seems to be no API for it.
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
|
|
|
|
| |
_mesa_format_from_format_and_type() is currently not considering DEPTH and
STENCIL formats, which are not array formats and are not handled anywhere.
This patch adds cases for common combinations of DEPTH/STENCIL format and
types.
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
| |
These basically reuse the default implementation of GL_READ_PIXELS_TYPE.
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
| |
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
|
|
| |
We call the driver to provide its preferred type, but also provide a
default implementation that selects a generic type based on the passed
internal format.
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
| |
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
|
| |
This is supported since very early version of OpenGL, but we still call the
driver to give it the opportunity to report caveat or no support.
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It discards out the targets and internalformats that explicitly
mention (per-spec) that doesn't support filter types other than
NEAREST or NEAREST_MIPMAP_NEAREST. Those are:
* Texture buffers target
* Multisample targets
* Any integer internalformat
For the case of multisample targets, it was used the existing method
_mesa_target_allows_setting_sampler_parameter. This would scalate
better in the future if new targets appear that doesn't allow to
set sampler parameters.
We consider RENDERBUFFER to support LINEAR filters, because although
it doesn't support this filter for sampling, you can set LINEAR
on a blit operation using glBlitFramebuffer.
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
| |
In order to allow to be used on ARB_internalformat_query2 implementation.
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
From the ARB_internalformat_query2 specification:
"- FRAMEBUFFER_RENDERABLE: The support for rendering to the resource via
framebuffer attachment is returned in <params>.
- FRAMEBUFFER_RENDERABLE_LAYERED: The support for layered rendering to
the resource via framebuffer attachment is returned in <params>.
- FRAMEBUFFER_BLEND: The support for rendering to the resource
via framebuffer attachment when blending is enabled is returned in
<params>."
For all of them,
"Possible values returned are FULL_SUPPORT, CAVEAT_SUPPORT, or NONE.
If the resource is unsupported, NONE is returned."
Reviewed-by: Dave Airlie <[email protected]>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
From the ARB_internalformat_query2 specification:
"- TEXTURE_SHADOW: The support for using the resource with shadow samplers
is written to <params>.
- TEXTURE_GATHER: The support for using the resource with texture gather
operations is written to <params>.
- TEXTURE_GATHER_SHADOW: The support for using resource with texture gather
operations with shadow samplers is written to <params>."
For all of them,
"Possible values returned are FULL_SUPPORT, CAVEAT_SUPPORT, or NONE.
If the resource or operation is not supported, NONE is returned."
Reviewed-by: Dave Airlie <[email protected]>
|