Merge misc. tweaks from private repository

This commit is contained in:
Jon Leech 2016-04-07 03:57:43 -07:00
commit f7b6b67dae
12 changed files with 174 additions and 48 deletions

View File

@ -359,3 +359,97 @@ Other Commits:
* Fix ref page build to generate .3 targets in the right output
directory.
-----------------------------------------------------
Change log for April 1, 2016 Vulkan 1.0.8 spec update:
* Bump API patch number and header version number to 8 for this
update.
Github Issues:
* Specify in the validity language for flink:vkBeginCommandBuffer that
pname:commandBuffer mustnot: currently be pending execution (public
issue 96).
* Describe depth comparison using the correct temporary variable names
in the <<textures-depth-compare-operation,Depth Compare Operation>>
section (public issue 100).
* Clarify the order of descriptor update operations in the
flink:vkUpdateDescriptorSets command (public issue 115).
* Specify in the VK_KHR_swapchain extension that
flink:vkAcquireNextImageKHR's pname:semaphore and pname:fence
parameters cannot both be sname:VK_NULL_HANDLE (partly addresses,
but does not fully close, public issue 117 / internal issue 246).
* Change reference to the "lifetime" of a Vulkan command to
"duration", and define the "duration" term (public issue 135).
* Added valid usage language for slink:VkImageLayout to require both
pname:height and pname:depth to be 1 for 1D images and pname:depth
to be 1 for 2D images (public issue 137).
* Fix SPIR-V example code in the
<<descriptorsets-inputattachment,Input Attachment>> section to
properly decorate the code:InputAttachmentIndex (public issue 139).
* Fix reference to nonexistent pname:imageInfo in the description of
flink:VkWriteDescriptorSet to refer to pname:pImageInfo (public
issue 140).
Internal Issues:
* Link to the fixed-function vertex chapter from the drawing chapter
(internal issue #110)
* Fix typo in slink:VkImageCreateInfo validity language:
ptext:maxExtent.sampleCounts -> pname:sampleCounts (internal issue
249).
* Explain why the non-core token etext:VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
is used in the example in the
<<synchronization-semaphores,Semaphores>> section (internal issue
251).
* Attempt to clarify in the VK_KHR_android_surface extension's
<<platformQuerySupport_android,Android Platform Support>> section
that there is no Android-specific WSI query, and why (internal issue
252).
Other Commits:
* Add missing language about ename:VK_INCOMPLETE being returned from
array queries when the passed array is too short, in the
VK_KHR_display, VK_KHR_swapchain, and VK_KHR_surface extensions.
-----------------------------------------------------
Change log for April 8, 2016 Vulkan 1.0.9 spec update:
* Bump API patch number and header version number to 9 for this
update.
Github Issues:
* Fix memory type preorder definition and clarify example list and source
code for slink:VkMemoryRequirements and slink:VkMemoryHeap (public issue
26).
* Ensure slink:VkAllocationCallbacks are properly defined (public issue
73).
* Clarify the WSI extension language by switching from the fuzzier
"ownership" language to more-consistent "acquire" language (public issue
117).
* Add language allowing allocation and freeing of memory scoped to the
duration of any API command in the <<memory-allocation,Memory
Allocation>> section (public issue 136).
* Clarify the explicit location assignment always overrides the inherited
location in the <<interfaces-iointerfaces-locations,Location
Assignment>> section, even for the first member of a block (public issue
141).
* Fixed references to
slink:VkCommandBufferInheritanceInfo::pname:pipelineStatistics (public
issue 158).
* Fix name of slink:VkBufferCopy::pname:size field in validity language
for flink:vkCmdCopyBuffer (public issue 162).
Internal Issues:
* Update GL_KHR_vulkan_glsl specification to clarify disallowance of
spec-const arrays in initializers (internal issue 248).
* Clarify <<interfaces-iointerfaces-matching,Interface Matching>> section
to state that user-defined variable interface must match too (internal
issue 250).

View File

@ -33,8 +33,8 @@ Status
Version
Last Modified Date: 7-Mar-2016
Revision: 28
Last Modified Date: 5-Apr-2016
Revision: 29
Number
@ -823,9 +823,9 @@ Changes to Chapter 4 of the OpenGL Shading Language Specification
int e[aSize + 2]; // different type than a, b, c, or d
"Types containing arrays sized with a specialization constant cannot be
compared, assigned as aggregates, or used in initializers. They can,
however, be passed as arguments to functions having formal parameters of
the same type.
compared, assigned as aggregates, declared with an initializer, or used
as an initializer. They can, however, be passed as arguments to
functions having formal parameters of the same type.
"Arrays inside a block may be sized with a specialization constant, but
the block will have a static layout. Changing the specialized size will
@ -1154,6 +1154,8 @@ Revision History
Rev. Date Author Changes
---- ----------- ------- --------------------------------------------
29 5-Apr-2016 JohnK Clarify disallowance of spec-const arrays in
initializers
28 7-Mar-2016 JohnK Make push_constants not have sets
27 28-Feb-2016 JohnK Make the default by origin_upper_left
26 17-Feb-2016 JohnK Expand specialized array semantics

View File

@ -126,7 +126,7 @@ INCLUDES := $(wildcard protos/*.txt structs/*.txt flags/*.txt enums/*.txt funcpo
COMMONDOCS := $(CHAPTERS) $(INCLUDES)
# A generated included file with the spec version, date, and git commit
SPECVERSION = specversion.txt
SPECREVISION = 1.0.8
SPECREVISION = 1.0.9
SPECREMARK =
# Spec targets

View File

@ -96,6 +96,9 @@ interface block must: match exactly, as described above. At an interface
involving the fragment shader inputs, the presence or absence of any
built-in output does not affect the interface matching.
At an interface between two shader stages, the user-defined variable
interface must: match exactly, as described above.
Any input value to a shader stage is well-defined as long as the preceding
stages writes to a matching output, as described above.
@ -157,10 +160,11 @@ types, mustnot: themselves have code:Location decorations.
If the structure type is a code:Block but without a code:Location, then
each of its members must: have a code:Location decoration. If it is a
code:Block with a code:Location decoration, then its first member is
assigned to the location specified for the code:Block, any member with
its own code:Location decoration is assigned that location, and each
remaining member is assigned the location after the
code:Block with a code:Location decoration, then its members are
assigned consecutive locations in declaration order, starting from the
first member which is initially assigned the location specified for the
code:Block. Any member with its own code:Location decoration is assigned
that location. Each remaining member is assigned the location after the
immediately preceding member in declaration order.
The locations consumed by block and structure members are determined

View File

@ -272,6 +272,8 @@ situations:
* Host memory scoped to the lifetime of a sname:VkDevice or
sname:VkInstance may: be allocated from any API command.
* Host memory scoped to the duration of a command may: be allocated from
any API command.
* Host memory scoped to the lifetime of a sname:VkPipelineCache may: only
be allocated from:
** fname:vkCreatePipelineCache
@ -299,6 +301,8 @@ pname:pfnFree may: be called in the following situations:
* Host memory scoped to the lifetime of a sname:VkDevice or
sname:VkInstance may: be freed from any API command.
* Host memory scoped to the duration of a command must: be freed by any
API command which allocates such memory.
* Host memory scoped to the lifetime of a sname:VkPipelineCache may: be
freed from fname:vkDestroyPipelineCache.
* Host memory scoped to the lifetime of a sname:VkDescriptorPool may: be
@ -386,13 +390,12 @@ include::../enums/VkMemoryHeapFlagBits.txt[]
include::../validity/structs/VkMemoryHeap.txt[]
At least one heap must: include ename:VK_MEMORY_HEAP_DEVICE_LOCAL_BIT in
pname:flags. If there are multiple heaps that all have similar performance
characteristics, they may: all include ename:VK_MEMORY_HEAP_DEVICE_LOCAL_BIT.
In a unified memory architecture (UMA) system, there is often only a single
memory heap which is considered to be equally ``local'' to the host and to
the device. If there is only one heap, that heap must: be marked as
ename:VK_MEMORY_HEAP_DEVICE_LOCAL_BIT. If there are multiple heaps that all
have similar performance characteristics, they may: all be marked as
ename:VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, but at least one will be device
local.
memory heap which is considered to be equally ``local'' to the host and to the
device, and such an implementation must: advertise the heap as device-local.
The definition of sname:VkMemoryType is:
@ -441,22 +444,24 @@ Each memory type returned by flink:vkGetPhysicalDeviceMemoryProperties must:
have its pname:propertyFlags set to one of the following values:
* 0
* ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
* ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_CACHED_BIT
* ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_CACHED_BIT | ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
* ename:VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
* ename:VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
* ename:VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_CACHED_BIT
* ename:VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_CACHED_BIT | ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
* ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
* ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_CACHED_BIT
* ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | ename:VK_MEMORY_PROPERTY_HOST_CACHED_BIT | ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
* ename:VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | ename:VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT
It is guaranteed that there is at least one memory type that has its
pname:propertyFlags with the ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT bit
set and the ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit set.
There must: be at least one memory type with both the
ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT and
ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bits set in its pname:propertyFlags.
There must: be at least one memory type with the
ename:VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT bit set in its pname:propertyFlags.
The memory types are sorted according to a partial order which serves to aid
The memory types are sorted according to a preorder which serves to aid
in easily selecting an appropriate memory type. Given two memory types X and
Y, the partial order defines latexmath:[$X \leq Y$] if:
Y, the preorder defines latexmath:[$X \leq Y$] if:
* the memory property bits set for X are a subset of the memory property
bits set for Y. Or,
@ -465,26 +470,44 @@ Y, the partial order defines latexmath:[$X \leq Y$] if:
performance (as determined in an implementation-specific manner).
Memory types are ordered in the list such that X is assigned a lesser
pname:memoryTypeIndex than Y if latexmath:[$X \leq Y$] according to the
partial order. Note that the list of all allowed memory property flag
combinations above satisfies this partial order, but other orders would as
pname:memoryTypeIndex than Y if latexmath:[$X \leq Y \land \neg(Y \leq X)$] according to the
preorder. Note that the list of all allowed memory property flag
combinations above satisfies this preorder, but other orders would as
well. The goal of this ordering is to enable applications to use a simple
search loop in selecting the proper memory type, along the lines of:
[source,{basebackend@docbook:c++:cpp}]
---------------------------------------------------
// Searching for the best match for "properties"
for (i = 0; i < memoryTypeCount; ++i)
if ((memoryTypes[i].propertyFlags & properties) == properties)
return i;
// Find a memory type in "memoryTypeBits" that includes all of "properties"
int32_t FindProperties(uint32_t memoryTypeBits, VkMemoryPropertyFlags properties)
{
for (int32_t i = 0; i < memoryTypeCount; ++i)
{
if ((memoryTypeBits & (1 << i)) &&
((memoryTypes[i].propertyFlags & properties) == properties))
return i;
}
return -1;
}
// Try to find an optimal memory type, or if it does not exist
// find any compatible memory type
VkMemoryRequirements memoryRequirements;
vkGetImageMemoryRequirements(device, image, &memoryRequirements);
int32_t memoryType = FindProperties(memoryRequirements.memoryTypeBits, optimalProperties);
if (memoryType == -1)
memoryType = FindProperties(memoryRequirements.memoryTypeBits, requiredProperties);
---------------------------------------------------
This loop will find the first entry that has all bits requested in
The loop will find the first supported memory type that has all bits requested in
code:properties set. If there is no exact match, it will find a closest
match (i.e. a memory type with the fewest additional bits set), which has
some additional bits set but which are not detrimental to the behaviors
requested by code:properties. If there are multiple heaps with the same
properties, it will choose the most performant memory.
requested by code:properties. The application can: first search for the optimal
properties, e.g. a memory type that is device-local or supports coherent cached
accesses, as appropriate for the intended usage, and if such a memory type is
not present can: fallback to searching for a less optimal but guaranteed set of
properties such as "0" or "host-visible and coherent".
A {apiname} device operates on data in device memory via memory objects that
are represented in the API by a sname:VkDeviceMemory handle. Memory objects

View File

@ -137,8 +137,8 @@ primary command buffer, and the
enabled, it can: execute secondary command buffers during the query
operation. For a secondary command buffer to be executed while a query is
active, it must: set the pname:occlusionQueryEnable, pname:queryFlags,
and/or pname:pipelineStatistics members of slink:VkCommandBufferBeginInfo to
conservative values, as described in the <<commandbuffers-recording, Command
and/or pname:pipelineStatistics members of slink:VkCommandBufferInheritanceInfo
to conservative values, as described in the <<commandbuffers-recording, Command
Buffer Recording>> section. A query must: either begin and end inside the
same subpass of a render pass instance, or must: both begin and end outside
of a render pass instance (i.e. contain entire render pass instances).

View File

@ -952,6 +952,9 @@ flink:vkGetImageMemoryRequirements:
ename:VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT bit and the
ename:VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit set. In other words,
mappable coherent memory can: always be attached to these objects.
* The pname:memoryTypeBits member always contains at least one bit set
corresponding to a sname:VkMemoryType with a pname:propertyFlags that has
the ename:VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT bit set.
* The pname:memoryTypeBits member is identical for all sname:VkBuffer
objects created with the same value for the pname:flags and pname:usage
members in the sname:VkBufferCreateInfo structure passed to

View File

@ -16,11 +16,11 @@ endif::doctype-manpage[]
* This command must: only be called outside of a render pass instance
* pname:regionCount must: be greater than `0`
* Each of pname:commandBuffer, pname:srcBuffer and pname:dstBuffer must: have been created, allocated or retrieved from the same sname:VkDevice
* The pname:copySize member of a given element of pname:pRegions must: be greater than `0`
* The pname:size member of a given element of pname:pRegions must: be greater than `0`
* The pname:srcOffset member of a given element of pname:pRegions must: be less than the size of pname:srcBuffer
* The pname:dstOffset member of a given element of pname:pRegions must: be less than the size of pname:dstBuffer
* The pname:copySize member of a given element of pname:pRegions must: be less than or equal to the size of pname:srcBuffer minus pname:srcOffset
* The pname:copySize member of a given element of pname:pRegions must: be less than or equal to the size of pname:dstBuffer minus pname:dstOffset
* The pname:size member of a given element of pname:pRegions must: be less than or equal to the size of pname:srcBuffer minus pname:srcOffset
* The pname:size member of a given element of pname:pRegions must: be less than or equal to the size of pname:dstBuffer minus pname:dstOffset
* The union of the source regions, and the union of the destination regions, specified by the elements of pname:pRegions, mustnot: overlap in memory
* pname:srcBuffer must: have been created with ename:VK_BUFFER_USAGE_TRANSFER_SRC_BIT usage flag
* pname:dstBuffer must: have been created with ename:VK_BUFFER_USAGE_TRANSFER_DST_BIT usage flag

View File

@ -27,7 +27,7 @@ endif::doctype-manpage[]
* If the <<features-features-inheritedQueries,inherited queries>> feature is not enabled, pname:commandBuffer mustnot: have any queries <<queries-operation-active,active>>
* If pname:commandBuffer has a ename:VK_QUERY_TYPE_OCCLUSION query <<queries-operation-active,active>>, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferBeginInfo::pname:occlusionQueryEnable set to ename:VK_TRUE
* If pname:commandBuffer has a ename:VK_QUERY_TYPE_OCCLUSION query <<queries-operation-active,active>>, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferBeginInfo::pname:queryFlags having all bits set that are set for the query
* If pname:commandBuffer has a ename:VK_QUERY_TYPE_PIPELINE_STATISTICS query <<queries-operation-active,active>>, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferBeginInfo::pname:pipelineStatistics having all bits set that are set in the sname:VkQueryPool the query uses
* If pname:commandBuffer has a ename:VK_QUERY_TYPE_PIPELINE_STATISTICS query <<queries-operation-active,active>>, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferInheritanceInfo::pname:pipelineStatistics having all bits set that are set in the sname:VkQueryPool the query uses
* Any given element of pname:pCommandBuffers mustnot: begin any query types that are <<queries-operation-active,active>> in pname:commandBuffer
ifndef::doctype-manpage[]
********************************************************************************

View File

@ -10,7 +10,7 @@ endif::doctype-manpage[]
* pname:pfnAllocation must: be a pointer to a valid user-defined PFN_vkAllocationFunction
* pname:pfnReallocation must: be a pointer to a valid user-defined PFN_vkReallocationFunction
* pname:pfnFree must: be a pointer to a valid user-defined PFN_vkFreeFunction
* If either of pname:pfnInternalAllocatione or pname:pfnInternalFree is not `NULL`, both must: be valid callbacks
* If either of pname:pfnInternalAllocation or pname:pfnInternalFree is not `NULL`, both must: be valid callbacks
ifndef::doctype-manpage[]
********************************************************************************
endif::doctype-manpage[]

View File

@ -101,7 +101,7 @@ maintained in the master branch of the Khronos Vulkan Github project.
<type category="define">// Vulkan 1.0 version number
#define <name>VK_API_VERSION_1_0</name> <type>VK_MAKE_VERSION</type>(1, 0, 0)</type> <!-- The patch version here should never be set to anything other than 0 -->
<type category="define">// Version of this file
#define <name>VK_HEADER_VERSION</name> 8</type>
#define <name>VK_HEADER_VERSION</name> 9</type>
<type category="define">
#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
@ -476,7 +476,7 @@ maintained in the master branch of the Khronos Vulkan Github project.
<usage>pname:pfnAllocation must: be a pointer to a valid user-defined PFN_vkAllocationFunction</usage>
<usage>pname:pfnReallocation must: be a pointer to a valid user-defined PFN_vkReallocationFunction</usage>
<usage>pname:pfnFree must: be a pointer to a valid user-defined PFN_vkFreeFunction</usage>
<usage>If either of pname:pfnInternalAllocatione or pname:pfnInternalFree is not `NULL`, both must: be valid callbacks</usage>
<usage>If either of pname:pfnInternalAllocation or pname:pfnInternalFree is not `NULL`, both must: be valid callbacks</usage>
</validity>
</type>
<type category="struct" name="VkDeviceQueueCreateInfo">
@ -4058,11 +4058,11 @@ maintained in the master branch of the Khronos Vulkan Github project.
<param><type>uint32_t</type> <name>regionCount</name></param>
<param len="regionCount">const <type>VkBufferCopy</type>* <name>pRegions</name></param>
<validity>
<usage>The pname:copySize member of a given element of pname:pRegions must: be greater than `0`</usage>
<usage>The pname:size member of a given element of pname:pRegions must: be greater than `0`</usage>
<usage>The pname:srcOffset member of a given element of pname:pRegions must: be less than the size of pname:srcBuffer</usage>
<usage>The pname:dstOffset member of a given element of pname:pRegions must: be less than the size of pname:dstBuffer</usage>
<usage>The pname:copySize member of a given element of pname:pRegions must: be less than or equal to the size of pname:srcBuffer minus pname:srcOffset</usage>
<usage>The pname:copySize member of a given element of pname:pRegions must: be less than or equal to the size of pname:dstBuffer minus pname:dstOffset</usage>
<usage>The pname:size member of a given element of pname:pRegions must: be less than or equal to the size of pname:srcBuffer minus pname:srcOffset</usage>
<usage>The pname:size member of a given element of pname:pRegions must: be less than or equal to the size of pname:dstBuffer minus pname:dstOffset</usage>
<usage>The union of the source regions, and the union of the destination regions, specified by the elements of pname:pRegions, mustnot: overlap in memory</usage>
<usage>pname:srcBuffer must: have been created with ename:VK_BUFFER_USAGE_TRANSFER_SRC_BIT usage flag</usage>
<usage>pname:dstBuffer must: have been created with ename:VK_BUFFER_USAGE_TRANSFER_DST_BIT usage flag</usage>
@ -4453,7 +4453,7 @@ maintained in the master branch of the Khronos Vulkan Github project.
<usage>If the &lt;&lt;features-features-inheritedQueries,inherited queries&gt;&gt; feature is not enabled, pname:commandBuffer mustnot: have any queries &lt;&lt;queries-operation-active,active&gt;&gt;</usage>
<usage>If pname:commandBuffer has a ename:VK_QUERY_TYPE_OCCLUSION query &lt;&lt;queries-operation-active,active&gt;&gt;, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferBeginInfo::pname:occlusionQueryEnable set to ename:VK_TRUE</usage>
<usage>If pname:commandBuffer has a ename:VK_QUERY_TYPE_OCCLUSION query &lt;&lt;queries-operation-active,active&gt;&gt;, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferBeginInfo::pname:queryFlags having all bits set that are set for the query</usage>
<usage>If pname:commandBuffer has a ename:VK_QUERY_TYPE_PIPELINE_STATISTICS query &lt;&lt;queries-operation-active,active&gt;&gt;, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferBeginInfo::pname:pipelineStatistics having all bits set that are set in the sname:VkQueryPool the query uses</usage>
<usage>If pname:commandBuffer has a ename:VK_QUERY_TYPE_PIPELINE_STATISTICS query &lt;&lt;queries-operation-active,active&gt;&gt;, then each element of pname:pCommandBuffers must: have been recorded with sname:VkCommandBufferInheritanceInfo::pname:pipelineStatistics having all bits set that are set in the sname:VkQueryPool the query uses</usage>
<usage>Any given element of pname:pCommandBuffers mustnot: begin any query types that are &lt;&lt;queries-operation-active,active&gt;&gt; in pname:commandBuffer</usage>
</validity>
</command>

View File

@ -50,7 +50,7 @@ extern "C" {
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
#define VK_HEADER_VERSION 8
#define VK_HEADER_VERSION 9
#define VK_NULL_HANDLE 0