Name
EXT_framebuffer_sRGB
Name Strings
GL_EXT_framebuffer_sRGB
GLX_EXT_framebuffer_sRGB
WGL_EXT_framebuffer_sRGB
Contributors
Alex Eddy, Apple
Chris Niederauer, Apple
Herb (Charles) Kuta, Quantum3D
Jeremy Sandmel, Apple
Jesse Hall, NVIDIA
From the EXT_texture_sRGB specification...
Alain Bouchard, Matrox
Brian Paul, Tungsten Graphics
Daniel Vogel, Epic Games
Eric Werness, NVIDIA
Kiril Vidimce, Pixar
Mark J. Kilgard, NVIDIA
Pat Brown, NVIDIA
Yanjun Zhang, S3 Graphics
Contact
Mark J. Kilgard, NVIDIA Corporation (mjk 'at' nvidia.com)
Status
Complete.
Version
Date: September 17, 2010
Revision: 4
Number
337
Dependencies
OpenGL 1.1 required
This extension is written against the OpenGL 2.0 (September 7,
2004) specification.
WGL_EXT_extensions_string is required for WGL support.
WGL_EXT_pixel_format is required for WGL support.
ARB_color_buffer_float interacts with this extension.
EXT_framebuffer_object interacts with this extension.
EXT_texture_sRGB interacts with this extension.
ARB_draw_buffers interacts with this extension.
Overview
Conventionally, OpenGL assumes framebuffer color components are stored
in a linear color space. In particular, framebuffer blending is a
linear operation.
The sRGB color space is based on typical (non-linear) monitor
characteristics expected in a dimly lit office. It has been
standardized by the International Electrotechnical Commission (IEC)
as IEC 61966-2-1. The sRGB color space roughly corresponds to 2.2
gamma correction.
This extension adds a framebuffer capability for sRGB framebuffer
update and blending. When blending is disabled but the new sRGB
updated mode is enabled (assume the framebuffer supports the
capability), high-precision linear color component values for red,
green, and blue generated by fragment coloring are encoded for sRGB
prior to being written into the framebuffer. When blending is enabled
along with the new sRGB update mode, red, green, and blue framebuffer
color components are treated as sRGB values that are converted to
linear color values, blended with the high-precision color values
generated by fragment coloring, and then the blend result is encoded
for sRGB just prior to being written into the framebuffer.
The primary motivation for this extension is that it allows OpenGL
applications to render into a framebuffer that is scanned to a monitor
configured to assume framebuffer color values are sRGB encoded.
This assumption is roughly true of most PC monitors with default
gamma correction. This allows applications to achieve faithful
color reproduction for OpenGL rendering without adjusting the
monitor's gamma correction.
New Procedures and Functions
None
New Tokens
Accepted by the parameter of glXChooseVisual, and by
the parameter of glXGetConfig:
GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2
Accepted by the parameter of
wglGetPixelFormatAttribivEXT, wglGetPixelFormatAttribfvEXT, and
the and of wglChoosePixelFormatEXT:
WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9
Accepted by the parameter of Enable, Disable, and IsEnabled,
and by the parameter of GetBooleanv, GetIntegerv, GetFloatv,
and GetDoublev:
FRAMEBUFFER_SRGB_EXT 0x8DB9
Accepted by the parameter of GetBooleanv, GetIntegerv,
GetFloatv, and GetDoublev:
FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
Additions to Chapter 2 of the 2.0 Specification (OpenGL Operation)
None
Additions to Chapter 3 of the 2.0 Specification (Rasterization)
None
Additions to Chapter 4 of the 2.0 Specification (Per-Fragment Operations
and the Frame Buffer)
-- Section 4.1.8 "Blending"
DELETE the following sentence from section 4.1.8 (Blending) because
it is moved to the new "sRGB Conversion" section:
"Each of these floating-point values is clamped to [0,1] and
converted back to a fixed-point value in the manner described in
section 2.14.9."
If ARB_color_buffer_float is supported, the following paragraph
is modified to eliminate the fixed-point clamping and conversion
because this behavior is moved to the new "sRGB Conversion" section.
"If the color buffer is fixed-point, the components of the source
and destination values and blend factors are clamped to [0, 1]
prior to evaluating the blend equation, the components of the
blending result are clamped to [0,1] and converted to fixed-
point values in the manner described in section 2.14.9. If the
color buffer is floating-point, no clamping occurs. The
resulting four values are sent to the next operation."
The modified ARB_color_buffer_float paragraph should read:
"If the color buffer is fixed-point, the components of the source
and destination values and blend factors are clamped to [0, 1]
prior to evaluating the blend equation. If the color buffer is
floating-point, no clamping occurs. The resulting four values are
sent to the next operation."
Replace the following sentence:
"Destination (framebuffer) components are taken to be fixed-point
values represented according to the scheme in section 2.14.9 (Final
Color Processing), as are source (fragment) components."
with the following sentences:
"Destination (framebuffer) components are taken to be fixed-point
values represented according to the scheme in section 2.14.9 (Final
Color Processing). If FRAMEBUFFER_SRGB_EXT is enabled and the boolean
FRAMEBUFFER_SRGB_CAPABLE_EXT state for the drawable is true, the R,
G, and B destination color values (after conversion from fixed-point
to floating-point) are considered to be encoded for the sRGB color
space and hence need to be linearized prior to their use in blending.
Each R, G, and B component is linearized by some approximation of
the following:
{ cs / 12.92, cs <= 0.04045
cl = {
{ ((cs + 0.055)/1.055)^2.4, cs > 0.04045
where cs is the component value prior to linearization and cl is
the result. Otherwise if FRAMEBUFFER_SRGB_EXT is disabled, or the
drawable is not sRGB capable, or the value corresponds to the A
component, then cs = cl for such components. The corresponding cs
values for R, G, B, and A are recombined as the destination color
used subsequently by blending."
ADD new section 4.1.X "sRGB Conversion" after section 4.1.8 (Blending)
and before section 4.1.9 (Dithering). With this new section added,
understand the "next operation" referred to in the section 4.1.8
(Blending) to now be "sRGB Conversion" (instead of "Dithering").
"If FRAMEBUFFER_SRGB_EXT is enabled and the boolean
FRAMEBUFFER_SRGB_CAPABLE_EXT state for the drawable is true, the R,
G, and B values after blending are converted into the non-linear
sRGB color space by some approximation of the following:
{ 0.0, 0 <= cl
{ 12.92 * c, 0 < cl < 0.0031308
cs = { 1.055 * cl^0.41666 - 0.055, 0.0031308 <= cl < 1
{ 1.0, cl >= 1
where cl is the R, G, or B element and cs is the result
(effectively converted into an sRGB color space). Otherwise if
FRAMEBUFFER_SRGB_EXT is disabled, or the drawable is not sRGB
capable, or the value corresponds to the A element, then cs = cl
for such elements.
The resulting cs values form a new RGBA color value. If the color
buffer is fixed-point, the components of this RGBA color value are
clamped to [0,1] and then converted to a fixed-point value in the
manner described in section 2.14.9. The resulting four values are
sent to the subsequent dithering operation."
-- Section 4.1.10 "Logical Operation"
Add this pargraph after the first paragraph in the section:
"Logical operation has no effect on an sRGB destination color buffer
(i.e., the boolean FRAMEBUFFER_SRGB_CAPABLE_EXT state for the
drawable is true) when FRAMEBUFFER_SRGB_EXT is enabled; however,
if the logical operation is enabled, blending is still disabled."
If ARB_color_buffer_float is supported, that specification's paragraph
(upon which the above paragraph is modeled) would be modified to
read:
"Logical operation has no effect on a floating-point destination
color buffer or sRGB destination color buffer (i.e., the boolean
FRAMEBUFFER_SRGB_CAPABLE_EXT state for the drawable is true) when
FRAMEBUFFER_SRGB_EXT is enabled; however, if the logical operation
is enabled, blending is still disabled."
-- Section 4.2.3 "Clearing the Buffers"
Change the first full sentence after the ClearColor prototype to
read:
"Each of the specified components is clamped to [0,1]."
(removing the "converted to fixed-point..." phrase because this
technically happens prior to sRGB conversion and/or dithering during
a Clear rather than at the time of the ClearColor call.)
Change the first sentence in the second to last paragraph of the
section to read:
"When Clear is called, the only per-fragment operations that are
applied (if enabled) are the pixel ownership test, the scissor test,
sRGB conversion, and dithering. The resulting color value (possibly
sRGB converted and/or dithered) is converted to fixed-point according
to the rules of section 2.14.19."
-- Section 4.2.4 "The Accumulation Buffer"
Change the fifth sentence of the second pargraph (describing ACCUM) to read:
"Each component, considered as a fixed-point value in
[0,1] (see section 2.14.9) is converted to floating-point;
special rules apply if the color buffer is sRGB-capable.
Specifically, if FRAMEBUFFER_SRGB_EXT is enabled and the boolean
FRAMEBUFFER_SRGB_CAPABLE_EXT state for the drawable is true, the R, G,
and B destination color values (after conversion from fixed-point to
floating-point) are considered to be encoded for the sRGB color space
and hence need to be linearized prior to their use for accumulation.
This conversion uses the formula to compute cl from cs is section
4.1.8."
Change the second to last sentence of the fourth paragraph (describing
RETURN) to read:
"The resulting color value is placed in the buffers currently
enabled for color writing as if it were a fragment produced from
rasterization, except that the only per-fragment operations that are
applied (if enabled) are the pixel ownership test, the scissor test
(section 4.1.2), sRGB conversion (section 4.2.X), and dithering
(section 4.1.9)."
Additions to Chapter 5 of the 2.0 Specification (Special Functions)
None
Additions to Chapter 6 of the 2.0 Specification (State and State Requests)
None
Additions to the OpenGL Shading Language specification
None
Additions to the GLX Specification
None
Dependencies on ARB_color_buffer_float
If ARB_color_buffer_float is not supported, ignore the edits to
ARB_color_buffer_float language.
Dependencies on EXT_texture_sRGB and EXT_framebuffer_object
If EXT_texture_sRGB and EXT_framebuffer_object are both supported, the
implementation should set FRAMEBUFFER_SRGB_CAPABLE_EXT to false when
rendering to a color texture that is not one of the EXT_texture_sRGB
introduced internal formats. An implementation can determine whether
or not it will set FRAMEBUFFER_SRGB_CAPABLE_EXT to true for the
EXT_texture_sRGB introduced internal formats. Implementations are
encouraged to allow sRGB update and blending when rendering to sRGB
textures using EXT_framebuffer_object but this is not required.
In any case, FRAMEBUFFER_SRGB_CAPABLE_EXT should indicate whether
or not sRGB update and blending is supported.
Dependencies on ARB_draw_buffers, EXT_texture_sRGB, and EXT_framebuffer_object
If ARB_draw_buffers, EXT_texture_sRGB, and EXT_framebuffer_object
are supported and an application attempts to render to a set
of color buffers where some but not all of the color buffers
are FRAMEBUFFER_SRGB_CAPABLE_EXT individually, the query of
FRAMEBUFFER_SRGB_CAPABLE_EXT should return true.
However sRGB update and blending only apply to the color buffers
that are actually sRGB-capable.
GLX Protocol
None.
Errors
Relaxation of INVALID_ENUM errors
---------------------------------
Enable, Disable, IsEnabled, GetBooleanv, GetIntegerv, GetFloatv,
and GetDoublev now accept the new token as allowed in the "New
Tokens" section.
New State
Add to table 6.20 (Pixel Operations)
Get Value Type Get Command Initial Value Description Sec. Attribute
-------------------- ---- ----------- ------------- --------------- ----- -------------------
FRAMEBUFFER_SRGB_EXT B IsEnabled False sRGB update and 4.1.X color-buffer/enable
blending enable
Add to table 6.33 (Implementation Dependent Values)
Get Value Type Get Command Initial Value Description Sec. Attribute
---------------------------- ---- ----------- ------------- -------------------- ----- ---------
FRAMEBUFFER_SRGB_CAPABLE_EXT B GetIntegerv - true if drawable 4.1.X -
supports sRGB update
and blending
New Implementation Dependent State
None
Issues
1) What should this extension be called?
RESOLVED: EXT_framebuffer_sRGB.
The "EXT_framebuffer" part indicates the extension is in
the framebuffer domain and "sRGB" indicates the extension is
adding a set of sRGB formats. This mimics the naming of the
EXT_texture_sRGB extension that adds sRGB texture formats.
The mixed-case spelling of sRGB is the established usage so
"_sRGB" is preferred to "_srgb". The "s" stands for standard
(color space).
For token names, we use "SRGB" since token names are uniformly
capitalized.
2) Should alpha be sRGB encoded?
RESOLVED: No. Alpha remains linear.
A rationale for this resolution is found in Alvy Ray's "Should
Alpha Be Nonlinear If RGB Is?" Tech Memo 17 (December 14, 1998).
See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
3) Should the ability to support sRGB framebuffer update and blending
be an attribute of the framebuffer?
RESOLVED: Yes. It should be a capability of some pixel formats
(mostly likely just RGB8 and RGBA8) that says sRGB blending can
be enabled.
This allows an implementation to simply mark the existing RGB8
and RGBA8 pixel formats as supporting sRGB blending and then
just provide the functionality for sRGB update and blending for
such formats.
sRGB support for floating-point formats makes little sense
(because floating-point already provide a non-linear distribution
of precision and typically have considerably more precision
than 8-bit fixed-point framebuffer components allow) and would
be expensive to support.
Requiring sRGB support for all fixed-point buffers means that
support for 16-bit components or very small 5-bit or 6-bit
components would require special sRGB conversion hardware.
Typically sRGB is well-suited for 8-bit fixed-point components
so we do not want this extension to require expensive tables
for other component sizes that are unlikely to ever be used.
Implementations could support sRGB conversion for any color
framebuffer format but implementations are not required to
(honestly nor are implementations like to support sRGB on anything
but 8-bit fixed-point color formats).
4) Should there be an enable for sRGB update and blending?
RESOLVED: Yes, and it is disabled by default. The enable only
applies if the framebuffer's underlying pixel format is capable
of sRGB update and blending. Otherwise, the enable is silently
ignored (similar to how the multisample enables are ignored when
the pixel format lacks multisample supports).
5) How is sRGB blending done?
RESOLVED: Blending is a linear operation so should be performed
on values in linear spaces. sRGB-encoded values are in a
non-linear space so sRGB blending should convert sRGB-encoded
values from the framebuffer to linear values, blend, and then
sRGB-encode the result to store it in the framebuffer.
The destination color RGB components are each converted
from sRGB to a linear value. Blending is then performed.
The source color and constant color are simply assumed to be
treated as linear color components. Then the result of blending
is converted to an sRGB encoding and stored in the framebuffer.
6) What happens if GL_FRAMEBUFFER_SRGB_EXT is enabled (and
GL_FRAMEBUFFER_SRGB_CAPABLE_EXT is true for the drawable) but
GL_BLEND is not enabled?
RESOLVED: The color result from fragment coloring (the source
color) is converted to an sRGB encoding and stored in the
framebuffer.
7) How are multiple render targets handled?
RESOLVED: Render targets that are not
GL_FRAMEBUFFER_SRGB_CAPABLE_EXT ignore the state of the
GL_FRAMEBUFFER_SRGB_EXT enable for sRGB update and blending.
So only the render targets that are sRGB-capable perform sRGB
blending and update when GL_FRAMEBUFFER_SRGB_EXT is enabled.
8) Should sRGB framebuffer support affect the pixel path?
RESOLVED: No.
sRGB conversion only applies to color reads for blending and
color writes. Color reads for glReadPixels, glCopyPixels,
or glAccum have no sRGB conversion applied.
For pixel path operations, an application could use pixel maps
or color tables to perform an sRGB-to-linear conversion with
these lookup tables.
9) Can luminance (single color component) framebuffer formats
support sRGB blending?
RESOLVED: Yes, if an implementation chooses to advertise such
a format and set the sRGB attribute for the format too.
Implementations are not obliged to provide such formats.
10) Should all component sizes be supported for sRGB components or
just 8-bit?
RESOLVED: This is at the implementation's discretion since
the implementation decides what pixel formats such support sRGB
update and blending.
It likely implementations will only provide sRGB-capable
framebuffer configurations for configurations with 8-bit
components.
11) What must be specified as far as how do you convert to and from
sRGB and linear RGB color spaces?
RESOLVED: The specification language needs to only supply the
linear RGB to sRGB conversion (see section 4.9.X above).
The sRGB to linear RGB conversion is documented in the
EXT_texture_sRGB specification.
For completeness, the accepted linear RGB to sRGB conversion
(the inverse of the function specified in section 3.8.x) is as
follows:
Given a linear RGB component, cl, convert it to an sRGB component,
cs, in the range [0,1], with this pseudo-code:
if (isnan(cl)) {
/* Map IEEE-754 Not-a-number to zero. */
cs = 0.0;
} else if (cl > 1.0) {
cs = 1.0;
} else if (cl < 0.0) {
cs = 0.0;
} else if (cl < 0.0031308) {
cs = 12.92 * cl;
} else {
cs = 1.055 * pow(cl, 0.41666) - 0.055;
}
The NaN behavior in the pseudo-code is recommended but not
specified in the actual specification language.
sRGB components are typically stored as unsigned 8-bit
fixed-point values. If cs is computed with the above
pseudo-code, cs can be converted to a [0,255] integer with this
formula:
csi = floor(255.0 * cs + 0.5)
12) Does this extension guarantee images rendered with sRGB textures
will "look good" when output to a device supporting an sRGB
color space?
RESOLVED: No.
Whether the displayed framebuffer is displayed to a monitor that
faithfully reproduces the sRGB color space is beyond the scope
of this extension. This involves the gamma correction and color
calibration of the physical display device.
13) How does this extension interact with EXT_framebuffer_object?
RESOLVED: When rendering to a color texture, an application
can query GL_FRAMEBUFFER_SRGB_CAPABLE_EXT to determine if the
color texture image is capable of sRGB rendering.
This boolean should be false for all texture internal formats
except may be true (but are not required to be true) for the sRGB
internal formats introduced by EXT_texture_sRGB. The expectation
is that implementations of this extension will be able to support
sRGB update and blending of sRGB textures.
14) How is the constant blend color handled for sRGB framebuffers?
RESOLVED: The constant blend color is specified as four
floating-point values. Given that the texture border color can
be specified at such high precision, it is always treated as a
linear RGBA value.
15) How does glCopyTex[Sub]Image work with sRGB? Suppose we're
rendering to a floating point pbuffer or framebuffer object and
do CopyTexImage. Are the linear framebuffer values converted
to sRGB during the copy?
RESOLVED: No, linear framebuffer values will NOT be automatically
converted to the sRGB encoding during the copy. If such a
conversion is desired, as explained in issue 12, the red, green,
and blue pixel map functionality can be used to implement a
linear-to-sRGB encoding translation.
16) Should this extension explicitly specify the particular
sRGB-to-linear and linear-to-sRGB conversions it uses?
RESOLVED: The conversions are explicitly specified but
allowance for approximations is provided. The expectation is
that the implementation is likely to use a table to implement the
conversions the conversion is necessarily then an approximation.
17) How does this extension interact with multisampling?
RESOLVED: There are no explicit interactions. However, arguably
if the color samples for multisampling are sRGB encoded, the
samples should be linearized before being "resolved" for display
and then recoverted to sRGB if the output device expects sRGB
encoded color components.
This is really a video scan-out issue and beyond the scope
of this extension which is focused on the rendering issues.
However some implementation advice is provided:
The implementation sufficiently aware of the gamma correction
configured for the display device could decide to perform an
sRGB-correct multisample resolve. Whether this occurs or not
could be determined by a control panel setting or inferred by
the application's use of this extension.
18) Why is the sRGB framebuffer GL_FRAMEBUFFER_SRGB_EXT enable
disabled by default?
RESOLVED: This extension could have a boolean
sRGB-versus-non-sRGB pixel format configuration mode that
determined whether or not sRGB framebuffer update and blending
occurs. The problem with this approach is 1) it creates may more
pixel formation configurations because sRGB and non-sRGB versions
of lots of existing configurations must be advertised, and 2)
applicaitons unaware of sRGB might unknowingly select an sRGB
configuration and then generate over-bright rendering.
It seems more appropriate to have a capability for sRGB
framebuffer update and blending that is disabled by default.
This allows existing RGB8 and RGBA8 framebuffer configurations
to be marked as sRGB capable (so no additional configurations
need be enumerated). Applications that desire sRGB rendering
should identify an sRGB-capable framebuffer configuration and
then enable sRGB rendering.
This is different from how EXT_texture_sRGB handles sRGB support
for texture formats. In the EXT_texture_sRGB extension, textures
are either sRGB or non-sRGB and there is no texture parameter
to switch textures between the two modes. This makes sense for
EXT_texture_sRGB because it allows implementations to fake sRGB
textures with higher-precision linear textures that simply convert
sRGB-encoded texels to sufficiently precise linear RGB values.
Texture formats also don't have the problem enumerated pixel
format descriptions have where a naive application could stumble
upon an sRGB-capable pixel format. sRGB textures require
explicit use of one of the new EXT_texture_sRGB-introduced
internal formats.
19) How does sRGB and this extension interact with digital video
output standards, in particular DVI?
RESOLVED: The DVI 1.0 specification recommends "as a default
position that digital moniotrs of all types support a color
transfer function similar to analog CRT monitors (gamma=2.2)
which makes up the majority of the compute display market." This
means DVI output devices should benefit from blending in the
sRGB color space just like analog monitors.
20) How does an sRGB framebuffer interact with glClearColor?
RESOLVED: The R, G, and B color components passed to glClearColor
are assumed to be linear color components.
So when GL_FRAMEBUFFER_SRGB_EXT is enabled and the color buffer
is sRGB-capable, the clear color is converted to a sRGB value
as part of the clear operation.
This behavior is consistent with the behavior of Direct3D 9,
10, and 11.
21) How does an sRGB framebuffer interact querying with
GL_COLOR_CLEAR_VALUE?
RESOLVED: The sRGB conversion of the clear color value
happens during the clear operation so when glGetFloatv for
GL_COLOR_CLEAR_VALUE returns an RGBA value, the RGB components
are the same values last passed to glClearColor (or similar
routines that update the same state such as glClearColorIiEXT
and glClearColorIuiEXT).
22) How does an sRGB framebuffer interact with the accumulation
buffer?
RESOLVED: When the accumulation buffer reads color values from
the color buffer during the GL_ACCUM or GL_LOAD operations,
the color values should be converted from sRGB values to linear
RGB values if GL_FRAMEBUFFER_SRGB_EXT is enabled and the color
buffer is sRGB-capable. Amended language says that the GL_ACCUM
(and implicitly, the GL_LOAD operation defined in terms of
GL_ACCUM) perform an sRGB to linear RGB conversion when color
buffer pixels are accumulated/loaded into the accumulation
buffer.
When the accumulation returns color values to the color
buffer during the GL_RETURN operation, the color values in the
accumulation buffer should be converted from linear RGB values
to sRGB values if GL_FRAMEBUFFER_SRGB_EXT is enabled and the
color buffer is sRGB-capable. The specification accomplishes
this by saying that the sRGB conversion (if enabled) per-fragment
operation applies to the GL_RETURN operation.
No sRGB conversion affects the accumulation buffer alpha
component.
This behavior ensures that the accumulation buffer and its linear
operations are performed on linear color values.
23) How does an sRGB framebuffer interact with GL_LOGIC_OP?
RESOLVED: When GL_LOGIC_OP is enabled and rendering to an
sRGB-capable color buffer with GL_FRAMEBUFFER_SRGB_EXT enabled,
the framebuffer's color representation is no longer fixed-point
so a bit-wise operation such as logic-op is dubious.
This same issue was faced with floating-point color buffers
and the decision there was to ignore the logic operation for
floating-point color components (and ignore blending, if enabled,
too because logic-op's behavior trumps blending).
So sRGB color components should ignore logic-op if enabled.
This resolution is consistent with the ARB_color_buffer_float
specification.
Implementation Notes
Implementations of this extension prior to late 2010 likely do
not implement the correct sRGB conversion for accumulation buffer
operations (the correct specification language was added in September
2010).
Revision History
Rev. Date Author Changes
---- -------- -------- -------------------------------------
4 09/17/10 mjk Add logic-op interaction
3 09/14/10 mjk Add interactions with clear and
accumulation buffer operations
2 08/11/08 mjk Get Command: IsEnabled -> GetInteger
for FRAMEBUFFER_SRGB_CAPABLE_EXT
1 10/21/06 barthold Added revision history
0.4 10/20/06 mjk Added issue 19
0.3 mjk Internal spec development.