-
Notifications
You must be signed in to change notification settings - Fork 327
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement parsing vulkan image formats (#1134)
- Loading branch information
1 parent
4f8d0d3
commit e00ff4e
Showing
5 changed files
with
419 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
# Copyright (C) 2022 Google Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
""" | ||
This module is responsible for testing Vulkan image formats | ||
Examples in this files stems from vk.xml that relesed by Khronos. | ||
Anytime the particular xml updated, test should be checked | ||
if they reflect the new XML | ||
""" | ||
|
||
import xml.etree.ElementTree as ET | ||
|
||
from vulkan_generator.vulkan_parser import formats_parser | ||
from vulkan_generator.vulkan_parser import types | ||
|
||
|
||
def test_vulkan_image_format() -> None: | ||
""""Test an image format""" | ||
|
||
xml = """<?xml version="1.0" encoding="UTF-8"?> | ||
<formats> | ||
<format name="VK_FORMAT_R8_USCALED" class="8-bit" blockSize="1" texelsPerBlock="1"> | ||
<component name="R" bits="8" numericFormat="USCALED"/> | ||
</format> | ||
</formats>""" | ||
|
||
image_format_metadata = formats_parser.parse(ET.fromstring(xml)) | ||
assert "VK_FORMAT_R8_USCALED" in image_format_metadata.formats | ||
|
||
image_format = image_format_metadata.formats["VK_FORMAT_R8_USCALED"] | ||
|
||
assert isinstance(image_format, types.ImageFormat) | ||
assert image_format.name == "VK_FORMAT_R8_USCALED" | ||
assert image_format.format_class == "8-bit" | ||
assert image_format.block_size == 1 | ||
assert image_format.texels_per_block == 1 | ||
|
||
|
||
def test_vulkan_image_format_with_spirv_format() -> None: | ||
""""Test an image format with spirv format""" | ||
|
||
xml = """<?xml version="1.0" encoding="UTF-8"?> | ||
<formats> | ||
<format name="VK_FORMAT_R8_UNORM" class="8-bit" blockSize="1" texelsPerBlock="1"> | ||
<component name="R" bits="8" numericFormat="UNORM"/> | ||
<spirvimageformat name="R8"/> | ||
</format> | ||
</formats>""" | ||
|
||
image_format_metadata = formats_parser.parse(ET.fromstring(xml)) | ||
image_format = image_format_metadata.formats["VK_FORMAT_R8_UNORM"] | ||
assert image_format.spirv_format == "R8" | ||
|
||
|
||
def test_vulkan_image_format_with_packed() -> None: | ||
""""Test an image format with packed""" | ||
|
||
xml = """<?xml version="1.0" encoding="UTF-8"?> | ||
<formats> | ||
<format name="VK_FORMAT_R4G4_UNORM_PACK8" class="8-bit" blockSize="1" texelsPerBlock="1" packed="8"> | ||
<component name="R" bits="4" numericFormat="UNORM"/> | ||
<component name="G" bits="4" numericFormat="UNORM"/> | ||
</format> | ||
</formats>""" | ||
|
||
image_format_metadata = formats_parser.parse(ET.fromstring(xml)) | ||
image_format = image_format_metadata.formats["VK_FORMAT_R4G4_UNORM_PACK8"] | ||
assert image_format.packed == 8 | ||
|
||
|
||
def test_vulkan_image_format_components() -> None: | ||
""""Test an image format with components""" | ||
|
||
xml = """<?xml version="1.0" encoding="UTF-8"?> | ||
<formats> | ||
<format name="VK_FORMAT_A1R5G5B5_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16"> | ||
<component name="A" bits="1" numericFormat="UNORM"/> | ||
<component name="R" bits="5" numericFormat="UNORM"/> | ||
<component name="G" bits="5" numericFormat="UNORM"/> | ||
<component name="B" bits="5" numericFormat="UNORM"/> | ||
</format> | ||
</formats>""" | ||
|
||
image_format_metadata = formats_parser.parse(ET.fromstring(xml)) | ||
image_format = image_format_metadata.formats["VK_FORMAT_A1R5G5B5_UNORM_PACK16"] | ||
|
||
components = list(image_format.components.values()) | ||
|
||
assert components[0].name == "A" | ||
assert components[0].bits == 1 | ||
assert components[0].numeric_format == "UNORM" | ||
|
||
assert components[1].name == "R" | ||
assert components[1].bits == 5 | ||
assert components[1].numeric_format == "UNORM" | ||
|
||
assert components[2].name == "G" | ||
assert components[2].bits == 5 | ||
assert components[2].numeric_format == "UNORM" | ||
|
||
assert components[3].name == "B" | ||
assert components[3].bits == 5 | ||
assert components[3].numeric_format == "UNORM" | ||
|
||
|
||
def test_vulkan_image_format_uncompressed_components() -> None: | ||
""""Test an image format with uncompressed components""" | ||
|
||
xml = """<?xml version="1.0" encoding="UTF-8"?> | ||
<formats> | ||
<format name="VK_FORMAT_A1R5G5B5_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16"> | ||
<component name="A" bits="1" numericFormat="UNORM"/> | ||
<component name="R" bits="5" numericFormat="UNORM"/> | ||
<component name="G" bits="5" numericFormat="UNORM"/> | ||
<component name="B" bits="5" numericFormat="UNORM"/> | ||
</format> | ||
</formats>""" | ||
|
||
image_format_metadata = formats_parser.parse(ET.fromstring(xml)) | ||
image_format = image_format_metadata.formats["VK_FORMAT_A1R5G5B5_UNORM_PACK16"] | ||
|
||
components = list(image_format.components.values()) | ||
assert not components[0].compressed | ||
assert not components[1].compressed | ||
assert not components[2].compressed | ||
assert not components[3].compressed | ||
|
||
|
||
def test_vulkan_image_format_compressed_components() -> None: | ||
""""Test an image format with compressed components""" | ||
|
||
xml = """<?xml version="1.0" encoding="UTF-8"?> | ||
<formats> | ||
<format name="VK_FORMAT_BC5_SNORM_BLOCK" class="BC5" blockSize="16" texelsPerBlock="16" | ||
blockExtent="4,4,1" compressed="BC"> | ||
<component name="R" bits="compressed" numericFormat="SRGB"/> | ||
<component name="G" bits="compressed" numericFormat="SRGB"/> | ||
</format> | ||
</formats>""" | ||
|
||
image_format_metadata = formats_parser.parse(ET.fromstring(xml)) | ||
image_format = image_format_metadata.formats["VK_FORMAT_BC5_SNORM_BLOCK"] | ||
|
||
components = list(image_format.components.values()) | ||
|
||
assert components[0].compressed | ||
assert components[1].compressed | ||
|
||
|
||
def test_vulkan_image_format_planes() -> None: | ||
""""Test an image format with planes""" | ||
|
||
xml = """<?xml version="1.0" encoding="UTF-8"?> | ||
<formats> | ||
<format name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16" class="10-bit 2-plane 444" blockSize="6" | ||
texelsPerBlock="1" packed="16" chroma="444"> | ||
<component name="G" bits="10" numericFormat="UNORM" planeIndex="0"/> | ||
<component name="B" bits="10" numericFormat="UNORM" planeIndex="1"/> | ||
<component name="R" bits="10" numericFormat="UNORM" planeIndex="1"/> | ||
<plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/> | ||
<plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6G10X6_UNORM_2PACK16"/> | ||
</format> | ||
</formats>""" | ||
|
||
image_format_metadata = formats_parser.parse(ET.fromstring(xml)) | ||
image_format = image_format_metadata.formats["VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16"] | ||
|
||
assert image_format.planes[0].index == 0 | ||
assert image_format.planes[0].width_divisor == 1 | ||
assert image_format.planes[0].height_divisor == 1 | ||
assert image_format.planes[0].compatible == "VK_FORMAT_R10X6_UNORM_PACK16" | ||
|
||
assert image_format.planes[1].index == 1 | ||
assert image_format.planes[1].width_divisor == 1 | ||
assert image_format.planes[1].height_divisor == 1 | ||
assert image_format.planes[1].compatible == "VK_FORMAT_R10X6G10X6_UNORM_2PACK16" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
# Copyright (C) 2022 Google Inc. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
""" This module is responsible for parsing Vulkan Image Formats""" | ||
|
||
from typing import OrderedDict | ||
from typing import List | ||
from typing import Optional | ||
|
||
import xml.etree.ElementTree as ET | ||
|
||
from vulkan_generator.vulkan_utils import parsing_utils | ||
from vulkan_generator.vulkan_parser import types | ||
|
||
|
||
def parse_format_planes(format_element: ET.Element) -> List[types.ImageFormatPlane]: | ||
""" | ||
Parser for the image format planes if format is multi-planar | ||
Sample image format plane: | ||
<plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/> | ||
""" | ||
planes: List[types.ImageFormatPlane] = [] | ||
|
||
for plane in format_element: | ||
if plane.tag == "spirvimageformat": | ||
# this is handled by image format parser | ||
continue | ||
|
||
if plane.tag == "component": | ||
# this is handled by image format component parser | ||
continue | ||
|
||
if plane.tag == "plane": | ||
index = int(plane.attrib["index"], 0) | ||
with_divisor = int(plane.attrib["widthDivisor"], 0) | ||
height_divisor = int(plane.attrib["heightDivisor"], 0) | ||
compatible = plane.attrib["compatible"] | ||
|
||
planes.append(types.ImageFormatPlane( | ||
index=index, | ||
width_divisor=with_divisor, | ||
height_divisor=height_divisor, | ||
compatible=compatible | ||
)) | ||
else: | ||
raise SyntaxError(f"Uknown image format element{ET.tostring(plane, 'utf-8')!r}") | ||
|
||
return planes | ||
|
||
|
||
def parse_format_components(format_element: ET.Element) -> OrderedDict[str, types.ImageFormatComponent]: | ||
""" | ||
Parser for the image formats components | ||
Sample image format component: | ||
<component name="R" bits="compressed" numericFormat="SRGB"/> | ||
""" | ||
components: OrderedDict[str, types.ImageFormatComponent] = OrderedDict() | ||
|
||
for component in format_element: | ||
if component.tag == "spirvimageformat": | ||
# this is handled by image format parser | ||
continue | ||
|
||
if component.tag == "plane": | ||
# this is handled by image format planes parser | ||
continue | ||
|
||
if component.tag == "component": | ||
name = component.attrib["name"] | ||
numeric_format = component.attrib["numericFormat"] | ||
|
||
# if the image is not compressed then bits per component is available | ||
bits = None | ||
compressed = component.attrib["bits"] == "compressed" | ||
if not compressed: | ||
bits = int(component.attrib["bits"], 0) | ||
|
||
components[name] = types.ImageFormatComponent( | ||
name=name, | ||
numeric_format=numeric_format, | ||
bits=bits, | ||
compressed=compressed | ||
) | ||
else: | ||
raise SyntaxError(f"Uknown image format element{ET.tostring(component, 'utf-8')!r}") | ||
|
||
return components | ||
|
||
|
||
def parse_format(format_element: ET.Element) -> types.ImageFormat: | ||
""" | ||
Parser for the Vulkan image formats | ||
A sample Vulkan image format: | ||
<format name="VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM" class="8-bit 3-plane 420" | ||
blockSize="3" texelsPerBlock="1" chroma="420"> | ||
<component name="G" bits="8" numericFormat="UNORM" planeIndex="0"/> | ||
<component name="B" bits="8" numericFormat="UNORM" planeIndex="1"/> | ||
<component name="R" bits="8" numericFormat="UNORM" planeIndex="2"/> | ||
<plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/> | ||
<plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R8_UNORM"/> | ||
<plane index="2" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R8_UNORM"/> | ||
</format> | ||
""" | ||
name = format_element.attrib["name"] | ||
format_class = format_element.attrib["class"] | ||
block_size = int(format_element.attrib["blockSize"], 0) | ||
texels_per_block = int(format_element.attrib["texelsPerBlock"], 0) | ||
|
||
# Pack size for the packed formats | ||
packed: Optional[int] = None | ||
packed_str = parsing_utils.try_get_attribute(format_element, "packed") | ||
if packed_str: | ||
packed = int(format_element.attrib["packed"], 0) | ||
|
||
# if the image has a spirv equavelant, it's stated in a child node | ||
spirv_format: Optional[str] = None | ||
for child in format_element: | ||
if child.tag == "spirvimageformat": | ||
spirv_format = child.attrib["name"] | ||
|
||
components = parse_format_components(format_element) | ||
|
||
# Parse plane info for multi-planar formats. For non-planar formats | ||
# this list will be empty | ||
planes = parse_format_planes(format_element) | ||
|
||
return types.ImageFormat( | ||
name=name, | ||
format_class=format_class, | ||
block_size=block_size, | ||
texels_per_block=texels_per_block, | ||
packed=packed, | ||
spirv_format=spirv_format, | ||
components=components, | ||
planes=planes) | ||
|
||
|
||
def parse(formats_element: ET.Element) -> types.ImageFormatMetadata: | ||
format_metadata = types.ImageFormatMetadata() | ||
|
||
for format_element in formats_element: | ||
image_format = parse_format(format_element) | ||
format_metadata.formats[image_format.name] = image_format | ||
|
||
return format_metadata |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.