Initial code commit

This commit is contained in:
leblane 2023-04-28 15:47:06 +03:00
parent 7485d9cbe1
commit 029dc67524
25 changed files with 21809 additions and 0 deletions

109
LICENCE.txt Normal file
View file

@ -0,0 +1,109 @@
TextureTaffy
============
MIT License
Copyright (c) 2023 leblane
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
stb_image and stb_image_resize
------------------------------
[stb_image and stb_image_resize] are available under 2 licenses -- choose whichever you prefer.
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
ISPC Texture Compressor
-----------------------
Copyright 2017 Intel Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Khronos DFD Components
----------------------
** Copyright 2015-2020 The Khronos Group Inc.
** SPDX-License-Identifier: Apache-2.0
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.

14
README.md Normal file
View file

@ -0,0 +1,14 @@
# TextureTaffy
A utility to create compressed textures, in BC1 (DXT1), BC3 (DXT5), BC4, BC5, BC6(U)H and BC7 compression formats, with the [KTX File Format Version 2.0](https://registry.khronos.org/KTX/specs/2.0/ktxspec.v2.html) (KTX2).
## Requirements
* [The Meson build system](https://mesonbuild.com/)
* [Intel® Implicit SPMD Program Compiler](https://ispc.github.io/)
## Building
## Notes and limitations

1039
Source/HalfFloat.cpp Normal file

File diff suppressed because it is too large Load diff

8
Source/HalfFloat.h Normal file
View file

@ -0,0 +1,8 @@
#pragma once
#include <cstdint>
namespace HalfFloat
{
uint16_t FromFloat(float x);
};

619
Source/KHR/khr_df.h Normal file
View file

@ -0,0 +1,619 @@
/* The Khronos Data Format Specification (version 1.3) */
/*
** Copyright 2015-2020 The Khronos Group Inc.
** SPDX-License-Identifier: Apache-2.0
*/
/* This header defines a structure that can describe the layout of image
formats in memory. This means that the data format is transparent to
the application, and the expectation is that this should be used when
the layout is defined external to the API. Many Khronos APIs deliberately
keep the internal layout of images opaque, to allow proprietary layouts
and optimisations. This structure is not appropriate for describing
opaque layouts. */
/* We stick to standard C89 constructs for simplicity and portability. */
#ifndef _KHR_DATA_FORMAT_H_
#define _KHR_DATA_FORMAT_H_
/* Accessors */
typedef enum _khr_word_e {
KHR_DF_WORD_VENDORID = 0U,
KHR_DF_WORD_DESCRIPTORTYPE = 0U,
KHR_DF_WORD_VERSIONNUMBER = 1U,
KHR_DF_WORD_DESCRIPTORBLOCKSIZE = 1U,
KHR_DF_WORD_MODEL = 2U,
KHR_DF_WORD_PRIMARIES = 2U,
KHR_DF_WORD_TRANSFER = 2U,
KHR_DF_WORD_FLAGS = 2U,
KHR_DF_WORD_TEXELBLOCKDIMENSION0 = 3U,
KHR_DF_WORD_TEXELBLOCKDIMENSION1 = 3U,
KHR_DF_WORD_TEXELBLOCKDIMENSION2 = 3U,
KHR_DF_WORD_TEXELBLOCKDIMENSION3 = 3U,
KHR_DF_WORD_BYTESPLANE0 = 4U,
KHR_DF_WORD_BYTESPLANE1 = 4U,
KHR_DF_WORD_BYTESPLANE2 = 4U,
KHR_DF_WORD_BYTESPLANE3 = 4U,
KHR_DF_WORD_BYTESPLANE4 = 5U,
KHR_DF_WORD_BYTESPLANE5 = 5U,
KHR_DF_WORD_BYTESPLANE6 = 5U,
KHR_DF_WORD_BYTESPLANE7 = 5U,
KHR_DF_WORD_SAMPLESTART = 6U,
KHR_DF_WORD_SAMPLEWORDS = 4U
} khr_df_word_e;
typedef enum _khr_df_shift_e {
KHR_DF_SHIFT_VENDORID = 0U,
KHR_DF_SHIFT_DESCRIPTORTYPE = 17U,
KHR_DF_SHIFT_VERSIONNUMBER = 0U,
KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE = 16U,
KHR_DF_SHIFT_MODEL = 0U,
KHR_DF_SHIFT_PRIMARIES = 8U,
KHR_DF_SHIFT_TRANSFER = 16U,
KHR_DF_SHIFT_FLAGS = 24U,
KHR_DF_SHIFT_TEXELBLOCKDIMENSION0 = 0U,
KHR_DF_SHIFT_TEXELBLOCKDIMENSION1 = 8U,
KHR_DF_SHIFT_TEXELBLOCKDIMENSION2 = 16U,
KHR_DF_SHIFT_TEXELBLOCKDIMENSION3 = 24U,
KHR_DF_SHIFT_BYTESPLANE0 = 0U,
KHR_DF_SHIFT_BYTESPLANE1 = 8U,
KHR_DF_SHIFT_BYTESPLANE2 = 16U,
KHR_DF_SHIFT_BYTESPLANE3 = 24U,
KHR_DF_SHIFT_BYTESPLANE4 = 0U,
KHR_DF_SHIFT_BYTESPLANE5 = 8U,
KHR_DF_SHIFT_BYTESPLANE6 = 16U,
KHR_DF_SHIFT_BYTESPLANE7 = 24U
} khr_df_shift_e;
typedef enum _khr_df_mask_e {
KHR_DF_MASK_VENDORID = 0x1FFFFU,
KHR_DF_MASK_DESCRIPTORTYPE = 0x7FFFU,
KHR_DF_MASK_VERSIONNUMBER = 0xFFFFU,
KHR_DF_MASK_DESCRIPTORBLOCKSIZE = 0xFFFFU,
KHR_DF_MASK_MODEL = 0xFFU,
KHR_DF_MASK_PRIMARIES = 0xFFU,
KHR_DF_MASK_TRANSFER = 0xFFU,
KHR_DF_MASK_FLAGS = 0xFFU,
KHR_DF_MASK_TEXELBLOCKDIMENSION0 = 0xFFU,
KHR_DF_MASK_TEXELBLOCKDIMENSION1 = 0xFFU,
KHR_DF_MASK_TEXELBLOCKDIMENSION2 = 0xFFU,
KHR_DF_MASK_TEXELBLOCKDIMENSION3 = 0xFFU,
KHR_DF_MASK_BYTESPLANE0 = 0xFFU,
KHR_DF_MASK_BYTESPLANE1 = 0xFFU,
KHR_DF_MASK_BYTESPLANE2 = 0xFFU,
KHR_DF_MASK_BYTESPLANE3 = 0xFFU,
KHR_DF_MASK_BYTESPLANE4 = 0xFFU,
KHR_DF_MASK_BYTESPLANE5 = 0xFFU,
KHR_DF_MASK_BYTESPLANE6 = 0xFFU,
KHR_DF_MASK_BYTESPLANE7 = 0xFFU
} khr_df_mask_e;
/* Helper macro:
Extract field X from basic descriptor block BDB */
#define KHR_DFDVAL(BDB, X) \
(((BDB)[KHR_DF_WORD_ ## X] >> (KHR_DF_SHIFT_ ## X)) \
& (KHR_DF_MASK_ ## X))
/* Helper macro:
Set field X of basic descriptor block BDB */
#define KHR_DFDSETVAL(BDB, X, val) \
((BDB)[KHR_DF_WORD_ ## X] = \
((BDB)[KHR_DF_WORD_ ## X] & \
~((KHR_DF_MASK_ ## X) << (KHR_DF_SHIFT_ ## X))) | \
(((val) & (KHR_DF_MASK_ ## X)) << (KHR_DF_SHIFT_ ## X)))
/* Offsets relative to the start of a sample */
typedef enum _khr_df_sampleword_e {
KHR_DF_SAMPLEWORD_BITOFFSET = 0U,
KHR_DF_SAMPLEWORD_BITLENGTH = 0U,
KHR_DF_SAMPLEWORD_CHANNELID = 0U,
KHR_DF_SAMPLEWORD_QUALIFIERS = 0U,
KHR_DF_SAMPLEWORD_SAMPLEPOSITION0 = 1U,
KHR_DF_SAMPLEWORD_SAMPLEPOSITION1 = 1U,
KHR_DF_SAMPLEWORD_SAMPLEPOSITION2 = 1U,
KHR_DF_SAMPLEWORD_SAMPLEPOSITION3 = 1U,
KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL = 1U,
KHR_DF_SAMPLEWORD_SAMPLELOWER = 2U,
KHR_DF_SAMPLEWORD_SAMPLEUPPER = 3U
} khr_df_sampleword_e;
typedef enum _khr_df_sampleshift_e {
KHR_DF_SAMPLESHIFT_BITOFFSET = 0U,
KHR_DF_SAMPLESHIFT_BITLENGTH = 16U,
KHR_DF_SAMPLESHIFT_CHANNELID = 24U,
/* N.B. Qualifiers are defined as an offset into a byte */
KHR_DF_SAMPLESHIFT_QUALIFIERS = 24U,
KHR_DF_SAMPLESHIFT_SAMPLEPOSITION0 = 0U,
KHR_DF_SAMPLESHIFT_SAMPLEPOSITION1 = 8U,
KHR_DF_SAMPLESHIFT_SAMPLEPOSITION2 = 16U,
KHR_DF_SAMPLESHIFT_SAMPLEPOSITION3 = 24U,
KHR_DF_SAMPLESHIFT_SAMPLEPOSITION_ALL = 0U,
KHR_DF_SAMPLESHIFT_SAMPLELOWER = 0U,
KHR_DF_SAMPLESHIFT_SAMPLEUPPER = 0U
} khr_df_sampleshift_e;
typedef enum _khr_df_samplemask_e {
KHR_DF_SAMPLEMASK_BITOFFSET = 0xFFFFU,
KHR_DF_SAMPLEMASK_BITLENGTH = 0xFF,
KHR_DF_SAMPLEMASK_CHANNELID = 0xF,
/* N.B. Qualifiers are defined as an offset into a byte */
KHR_DF_SAMPLEMASK_QUALIFIERS = 0xF0,
KHR_DF_SAMPLEMASK_SAMPLEPOSITION0 = 0xFF,
KHR_DF_SAMPLEMASK_SAMPLEPOSITION1 = 0xFF,
KHR_DF_SAMPLEMASK_SAMPLEPOSITION2 = 0xFF,
KHR_DF_SAMPLEMASK_SAMPLEPOSITION3 = 0xFF,
/* ISO C restricts enum values to range of int hence the
cast. We do it verbosely instead of using -1 to ensure
it is a 32-bit value even if int is 64 bits. */
KHR_DF_SAMPLEMASK_SAMPLEPOSITION_ALL = (int) 0xFFFFFFFFU,
KHR_DF_SAMPLEMASK_SAMPLELOWER = (int) 0xFFFFFFFFU,
KHR_DF_SAMPLEMASK_SAMPLEUPPER = (int) 0xFFFFFFFFU
} khr_df_samplemask_e;
/* Helper macro:
Extract field X of sample S from basic descriptor block BDB */
#define KHR_DFDSVAL(BDB, S, X) \
(((BDB)[KHR_DF_WORD_SAMPLESTART + \
((S) * KHR_DF_WORD_SAMPLEWORDS) + \
KHR_DF_SAMPLEWORD_ ## X] >> (KHR_DF_SAMPLESHIFT_ ## X)) \
& (KHR_DF_SAMPLEMASK_ ## X))
/* Helper macro:
Set field X of sample S of basic descriptor block BDB */
#define KHR_DFDSETSVAL(BDB, S, X, val) \
((BDB)[KHR_DF_WORD_SAMPLESTART + \
((S) * KHR_DF_WORD_SAMPLEWORDS) + \
KHR_DF_SAMPLEWORD_ ## X] = \
((BDB)[KHR_DF_WORD_SAMPLESTART + \
((S) * KHR_DF_WORD_SAMPLEWORDS) + \
KHR_DF_SAMPLEWORD_ ## X] & \
~((uint32_t)(KHR_DF_SAMPLEMASK_ ## X) << (KHR_DF_SAMPLESHIFT_ ## X))) | \
(((val) & (uint32_t)(KHR_DF_SAMPLEMASK_ ## X)) << (KHR_DF_SAMPLESHIFT_ ## X)))
/* Helper macro:
Number of samples in basic descriptor block BDB */
#define KHR_DFDSAMPLECOUNT(BDB) \
(((KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE) >> 2) - \
KHR_DF_WORD_SAMPLESTART) \
/ KHR_DF_WORD_SAMPLEWORDS)
/* Helper macro:
Size in words of basic descriptor block for S samples */
#define KHR_DFDSIZEWORDS(S) \
(KHR_DF_WORD_SAMPLESTART + \
(S) * KHR_DF_WORD_SAMPLEWORDS)
/* Vendor ids */
typedef enum _khr_df_vendorid_e {
/* Standard Khronos descriptor */
KHR_DF_VENDORID_KHRONOS = 0U,
KHR_DF_VENDORID_MAX = 0x1FFFFU
} khr_df_vendorid_e;
/* Descriptor types */
typedef enum _khr_df_khr_descriptortype_e {
/* Default Khronos basic descriptor block */
KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT = 0U,
/* Extension descriptor block for additional planes */
KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES = 0x6001U,
/* Extension descriptor block for additional dimensions */
KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS = 0x6002U,
/* Bit indicates modifying requires understanding this extension */
KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_WRITE_BIT = 0x2000U,
/* Bit indicates processing requires understanding this extension */
KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_DECODE_BIT = 0x4000U,
KHR_DF_KHR_DESCRIPTORTYPE_MAX = 0x7FFFU
} khr_df_khr_descriptortype_e;
/* Descriptor block version */
typedef enum _khr_df_versionnumber_e {
/* Standard Khronos descriptor */
KHR_DF_VERSIONNUMBER_1_0 = 0U, /* Version 1.0 of the specification */
KHR_DF_VERSIONNUMBER_1_1 = 0U, /* Version 1.1 did not bump the version number */
KHR_DF_VERSIONNUMBER_1_2 = 1U, /* Version 1.2 increased the version number */
KHR_DF_VERSIONNUMBER_1_3 = 2U, /* Version 1.3 increased the version number */
KHR_DF_VERSIONNUMBER_LATEST = KHR_DF_VERSIONNUMBER_1_3,
KHR_DF_VERSIONNUMBER_MAX = 0xFFFFU
} khr_df_versionnumber_e;
/* Model in which the color coordinate space is defined.
There is no requirement that a color format use all the
channel types that are defined in the color model. */
typedef enum _khr_df_model_e {
/* No interpretation of color channels defined */
KHR_DF_MODEL_UNSPECIFIED = 0U,
/* Color primaries (red, green, blue) + alpha, depth and stencil */
KHR_DF_MODEL_RGBSDA = 1U,
/* Color differences (Y', Cb, Cr) + alpha, depth and stencil */
KHR_DF_MODEL_YUVSDA = 2U,
/* Color differences (Y', I, Q) + alpha, depth and stencil */
KHR_DF_MODEL_YIQSDA = 3U,
/* Perceptual color (CIE L*a*b*) + alpha, depth and stencil */
KHR_DF_MODEL_LABSDA = 4U,
/* Subtractive colors (cyan, magenta, yellow, black) + alpha */
KHR_DF_MODEL_CMYKA = 5U,
/* Non-color coordinate data (X, Y, Z, W) */
KHR_DF_MODEL_XYZW = 6U,
/* Hue, saturation, value, hue angle on color circle, plus alpha */
KHR_DF_MODEL_HSVA_ANG = 7U,
/* Hue, saturation, lightness, hue angle on color circle, plus alpha */
KHR_DF_MODEL_HSLA_ANG = 8U,
/* Hue, saturation, value, hue on color hexagon, plus alpha */
KHR_DF_MODEL_HSVA_HEX = 9U,
/* Hue, saturation, lightness, hue on color hexagon, plus alpha */
KHR_DF_MODEL_HSLA_HEX = 10U,
/* Lightweight approximate color difference (luma, orange, green) */
KHR_DF_MODEL_YCGCOA = 11U,
/* ITU BT.2020 constant luminance YcCbcCrc */
KHR_DF_MODEL_YCCBCCRC = 12U,
/* ITU BT.2100 constant intensity ICtCp */
KHR_DF_MODEL_ICTCP = 13U,
/* CIE 1931 XYZ color coordinates (X, Y, Z) */
KHR_DF_MODEL_CIEXYZ = 14U,
/* CIE 1931 xyY color coordinates (X, Y, Y) */
KHR_DF_MODEL_CIEXYY = 15U,
/* Compressed formats start at 128. */
/* These compressed formats should generally have a single sample,
sited at the 0,0 position of the texel block. Where multiple
channels are used to distinguish formats, these should be cosited. */
/* Direct3D (and S3) compressed formats */
/* Note that premultiplied status is recorded separately */
/* DXT1 "channels" are RGB (0), Alpha (1) */
/* DXT1/BC1 with one channel is opaque */
/* DXT1/BC1 with a cosited alpha sample is transparent */
KHR_DF_MODEL_DXT1A = 128U,
KHR_DF_MODEL_BC1A = 128U,
/* DXT2/DXT3/BC2, with explicit 4-bit alpha */
KHR_DF_MODEL_DXT2 = 129U,
KHR_DF_MODEL_DXT3 = 129U,
KHR_DF_MODEL_BC2 = 129U,
/* DXT4/DXT5/BC3, with interpolated alpha */
KHR_DF_MODEL_DXT4 = 130U,
KHR_DF_MODEL_DXT5 = 130U,
KHR_DF_MODEL_BC3 = 130U,
/* BC4 - single channel interpolated 8-bit data */
/* (The UNORM/SNORM variation is recorded in the channel data) */
KHR_DF_MODEL_BC4 = 131U,
/* BC5 - two channel interpolated 8-bit data */
/* (The UNORM/SNORM variation is recorded in the channel data) */
KHR_DF_MODEL_BC5 = 132U,
/* BC6H - DX11 format for 16-bit float channels */
KHR_DF_MODEL_BC6H = 133U,
/* BC7 - DX11 format */
KHR_DF_MODEL_BC7 = 134U,
/* Gap left for future desktop expansion */
/* Mobile compressed formats follow */
/* A format of ETC1 indicates that the format shall be decodable
by an ETC1-compliant decoder and not rely on ETC2 features */
KHR_DF_MODEL_ETC1 = 160U,
/* A format of ETC2 is permitted to use ETC2 encodings on top of
the baseline ETC1 specification */
/* The ETC2 format has channels "red", "green", "RGB" and "alpha",
which should be cosited samples */
/* Punch-through alpha can be distinguished from full alpha by
the plane size in bytes required for the texel block */
KHR_DF_MODEL_ETC2 = 161U,
/* Adaptive Scalable Texture Compression */
/* ASTC HDR vs LDR is determined by the float flag in the channel */
/* ASTC block size can be distinguished by texel block size */
KHR_DF_MODEL_ASTC = 162U,
/* ETC1S is a simplified subset of ETC1 */
KHR_DF_MODEL_ETC1S = 163U,
/* PowerVR Texture Compression */
KHR_DF_MODEL_PVRTC = 164U,
KHR_DF_MODEL_PVRTC2 = 165U,
KHR_DF_MODEL_UASTC = 166U,
/* Proprietary formats (ATITC, etc.) should follow */
KHR_DF_MODEL_MAX = 0xFFU
} khr_df_model_e;
/* Definition of channel names for each color model */
typedef enum _khr_df_model_channels_e {
/* Unspecified format with nominal channel numbering */
KHR_DF_CHANNEL_UNSPECIFIED_0 = 0U,
KHR_DF_CHANNEL_UNSPECIFIED_1 = 1U,
KHR_DF_CHANNEL_UNSPECIFIED_2 = 2U,
KHR_DF_CHANNEL_UNSPECIFIED_3 = 3U,
KHR_DF_CHANNEL_UNSPECIFIED_4 = 4U,
KHR_DF_CHANNEL_UNSPECIFIED_5 = 5U,
KHR_DF_CHANNEL_UNSPECIFIED_6 = 6U,
KHR_DF_CHANNEL_UNSPECIFIED_7 = 7U,
KHR_DF_CHANNEL_UNSPECIFIED_8 = 8U,
KHR_DF_CHANNEL_UNSPECIFIED_9 = 9U,
KHR_DF_CHANNEL_UNSPECIFIED_10 = 10U,
KHR_DF_CHANNEL_UNSPECIFIED_11 = 11U,
KHR_DF_CHANNEL_UNSPECIFIED_12 = 12U,
KHR_DF_CHANNEL_UNSPECIFIED_13 = 13U,
KHR_DF_CHANNEL_UNSPECIFIED_14 = 14U,
KHR_DF_CHANNEL_UNSPECIFIED_15 = 15U,
/* MODEL_RGBSDA - red, green, blue, stencil, depth, alpha */
KHR_DF_CHANNEL_RGBSDA_RED = 0U,
KHR_DF_CHANNEL_RGBSDA_R = 0U,
KHR_DF_CHANNEL_RGBSDA_GREEN = 1U,
KHR_DF_CHANNEL_RGBSDA_G = 1U,
KHR_DF_CHANNEL_RGBSDA_BLUE = 2U,
KHR_DF_CHANNEL_RGBSDA_B = 2U,
KHR_DF_CHANNEL_RGBSDA_STENCIL = 13U,
KHR_DF_CHANNEL_RGBSDA_S = 13U,
KHR_DF_CHANNEL_RGBSDA_DEPTH = 14U,
KHR_DF_CHANNEL_RGBSDA_D = 14U,
KHR_DF_CHANNEL_RGBSDA_ALPHA = 15U,
KHR_DF_CHANNEL_RGBSDA_A = 15U,
/* MODEL_YUVSDA - luma, Cb, Cr, stencil, depth, alpha */
KHR_DF_CHANNEL_YUVSDA_Y = 0U,
KHR_DF_CHANNEL_YUVSDA_CB = 1U,
KHR_DF_CHANNEL_YUVSDA_U = 1U,
KHR_DF_CHANNEL_YUVSDA_CR = 2U,
KHR_DF_CHANNEL_YUVSDA_V = 2U,
KHR_DF_CHANNEL_YUVSDA_STENCIL = 13U,
KHR_DF_CHANNEL_YUVSDA_S = 13U,
KHR_DF_CHANNEL_YUVSDA_DEPTH = 14U,
KHR_DF_CHANNEL_YUVSDA_D = 14U,
KHR_DF_CHANNEL_YUVSDA_ALPHA = 15U,
KHR_DF_CHANNEL_YUVSDA_A = 15U,
/* MODEL_YIQSDA - luma, in-phase, quadrature, stencil, depth, alpha */
KHR_DF_CHANNEL_YIQSDA_Y = 0U,
KHR_DF_CHANNEL_YIQSDA_I = 1U,
KHR_DF_CHANNEL_YIQSDA_Q = 2U,
KHR_DF_CHANNEL_YIQSDA_STENCIL = 13U,
KHR_DF_CHANNEL_YIQSDA_S = 13U,
KHR_DF_CHANNEL_YIQSDA_DEPTH = 14U,
KHR_DF_CHANNEL_YIQSDA_D = 14U,
KHR_DF_CHANNEL_YIQSDA_ALPHA = 15U,
KHR_DF_CHANNEL_YIQSDA_A = 15U,
/* MODEL_LABSDA - CIELAB/L*a*b* luma, red-green, blue-yellow, stencil, depth, alpha */
KHR_DF_CHANNEL_LABSDA_L = 0U,
KHR_DF_CHANNEL_LABSDA_A = 1U,
KHR_DF_CHANNEL_LABSDA_B = 2U,
KHR_DF_CHANNEL_LABSDA_STENCIL = 13U,
KHR_DF_CHANNEL_LABSDA_S = 13U,
KHR_DF_CHANNEL_LABSDA_DEPTH = 14U,
KHR_DF_CHANNEL_LABSDA_D = 14U,
KHR_DF_CHANNEL_LABSDA_ALPHA = 15U,
/* NOTE: KHR_DF_CHANNEL_LABSDA_A is not a synonym for alpha! */
/* MODEL_CMYKA - cyan, magenta, yellow, key/blacK, alpha */
KHR_DF_CHANNEL_CMYKSDA_CYAN = 0U,
KHR_DF_CHANNEL_CMYKSDA_C = 0U,
KHR_DF_CHANNEL_CMYKSDA_MAGENTA = 1U,
KHR_DF_CHANNEL_CMYKSDA_M = 1U,
KHR_DF_CHANNEL_CMYKSDA_YELLOW = 2U,
KHR_DF_CHANNEL_CMYKSDA_Y = 2U,
KHR_DF_CHANNEL_CMYKSDA_KEY = 3U,
KHR_DF_CHANNEL_CMYKSDA_BLACK = 3U,
KHR_DF_CHANNEL_CMYKSDA_K = 3U,
KHR_DF_CHANNEL_CMYKSDA_ALPHA = 15U,
KHR_DF_CHANNEL_CMYKSDA_A = 15U,
/* MODEL_XYZW - coordinates x, y, z, w */
KHR_DF_CHANNEL_XYZW_X = 0U,
KHR_DF_CHANNEL_XYZW_Y = 1U,
KHR_DF_CHANNEL_XYZW_Z = 2U,
KHR_DF_CHANNEL_XYZW_W = 3U,
/* MODEL_HSVA_ANG - value (luma), saturation, hue, alpha, angular projection, conical space */
KHR_DF_CHANNEL_HSVA_ANG_VALUE = 0U,
KHR_DF_CHANNEL_HSVA_ANG_V = 0U,
KHR_DF_CHANNEL_HSVA_ANG_SATURATION = 1U,
KHR_DF_CHANNEL_HSVA_ANG_S = 1U,
KHR_DF_CHANNEL_HSVA_ANG_HUE = 2U,
KHR_DF_CHANNEL_HSVA_ANG_H = 2U,
KHR_DF_CHANNEL_HSVA_ANG_ALPHA = 15U,
KHR_DF_CHANNEL_HSVA_ANG_A = 15U,
/* MODEL_HSLA_ANG - lightness (luma), saturation, hue, alpha, angular projection, double conical space */
KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS = 0U,
KHR_DF_CHANNEL_HSLA_ANG_L = 0U,
KHR_DF_CHANNEL_HSLA_ANG_SATURATION = 1U,
KHR_DF_CHANNEL_HSLA_ANG_S = 1U,
KHR_DF_CHANNEL_HSLA_ANG_HUE = 2U,
KHR_DF_CHANNEL_HSLA_ANG_H = 2U,
KHR_DF_CHANNEL_HSLA_ANG_ALPHA = 15U,
KHR_DF_CHANNEL_HSLA_ANG_A = 15U,
/* MODEL_HSVA_HEX - value (luma), saturation, hue, alpha, hexagonal projection, conical space */
KHR_DF_CHANNEL_HSVA_HEX_VALUE = 0U,
KHR_DF_CHANNEL_HSVA_HEX_V = 0U,
KHR_DF_CHANNEL_HSVA_HEX_SATURATION = 1U,
KHR_DF_CHANNEL_HSVA_HEX_S = 1U,
KHR_DF_CHANNEL_HSVA_HEX_HUE = 2U,
KHR_DF_CHANNEL_HSVA_HEX_H = 2U,
KHR_DF_CHANNEL_HSVA_HEX_ALPHA = 15U,
KHR_DF_CHANNEL_HSVA_HEX_A = 15U,
/* MODEL_HSLA_HEX - lightness (luma), saturation, hue, alpha, hexagonal projection, double conical space */
KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS = 0U,
KHR_DF_CHANNEL_HSLA_HEX_L = 0U,
KHR_DF_CHANNEL_HSLA_HEX_SATURATION = 1U,
KHR_DF_CHANNEL_HSLA_HEX_S = 1U,
KHR_DF_CHANNEL_HSLA_HEX_HUE = 2U,
KHR_DF_CHANNEL_HSLA_HEX_H = 2U,
KHR_DF_CHANNEL_HSLA_HEX_ALPHA = 15U,
KHR_DF_CHANNEL_HSLA_HEX_A = 15U,
/* MODEL_YCGCOA - luma, green delta, orange delta, alpha */
KHR_DF_CHANNEL_YCGCOA_Y = 0U,
KHR_DF_CHANNEL_YCGCOA_CG = 1U,
KHR_DF_CHANNEL_YCGCOA_CO = 2U,
KHR_DF_CHANNEL_YCGCOA_ALPHA = 15U,
KHR_DF_CHANNEL_YCGCOA_A = 15U,
/* MODEL_CIEXYZ - CIE 1931 X, Y, Z */
KHR_DF_CHANNEL_CIEXYZ_X = 0U,
KHR_DF_CHANNEL_CIEXYZ_Y = 1U,
KHR_DF_CHANNEL_CIEXYZ_Z = 2U,
/* MODEL_CIEXYY - CIE 1931 x, y, Y */
KHR_DF_CHANNEL_CIEXYY_X = 0U,
KHR_DF_CHANNEL_CIEXYY_YCHROMA = 1U,
KHR_DF_CHANNEL_CIEXYY_YLUMA = 2U,
/* Compressed formats */
/* MODEL_DXT1A/MODEL_BC1A */
KHR_DF_CHANNEL_DXT1A_COLOR = 0U,
KHR_DF_CHANNEL_BC1A_COLOR = 0U,
KHR_DF_CHANNEL_DXT1A_ALPHAPRESENT = 1U,
KHR_DF_CHANNEL_DXT1A_ALPHA = 1U,
KHR_DF_CHANNEL_BC1A_ALPHAPRESENT = 1U,
KHR_DF_CHANNEL_BC1A_ALPHA = 1U,
/* MODEL_DXT2/3/MODEL_BC2 */
KHR_DF_CHANNEL_DXT2_COLOR = 0U,
KHR_DF_CHANNEL_DXT3_COLOR = 0U,
KHR_DF_CHANNEL_BC2_COLOR = 0U,
KHR_DF_CHANNEL_DXT2_ALPHA = 15U,
KHR_DF_CHANNEL_DXT3_ALPHA = 15U,
KHR_DF_CHANNEL_BC2_ALPHA = 15U,
/* MODEL_DXT4/5/MODEL_BC3 */
KHR_DF_CHANNEL_DXT4_COLOR = 0U,
KHR_DF_CHANNEL_DXT5_COLOR = 0U,
KHR_DF_CHANNEL_BC3_COLOR = 0U,
KHR_DF_CHANNEL_DXT4_ALPHA = 15U,
KHR_DF_CHANNEL_DXT5_ALPHA = 15U,
KHR_DF_CHANNEL_BC3_ALPHA = 15U,
/* MODEL_BC4 */
KHR_DF_CHANNEL_BC4_DATA = 0U,
/* MODEL_BC5 */
KHR_DF_CHANNEL_BC5_RED = 0U,
KHR_DF_CHANNEL_BC5_R = 0U,
KHR_DF_CHANNEL_BC5_GREEN = 1U,
KHR_DF_CHANNEL_BC5_G = 1U,
/* MODEL_BC6H */
KHR_DF_CHANNEL_BC6H_COLOR = 0U,
KHR_DF_CHANNEL_BC6H_DATA = 0U,
/* MODEL_BC7 */
KHR_DF_CHANNEL_BC7_DATA = 0U,
KHR_DF_CHANNEL_BC7_COLOR = 0U,
/* MODEL_ETC1 */
KHR_DF_CHANNEL_ETC1_DATA = 0U,
KHR_DF_CHANNEL_ETC1_COLOR = 0U,
/* MODEL_ETC2 */
KHR_DF_CHANNEL_ETC2_RED = 0U,
KHR_DF_CHANNEL_ETC2_R = 0U,
KHR_DF_CHANNEL_ETC2_GREEN = 1U,
KHR_DF_CHANNEL_ETC2_G = 1U,
KHR_DF_CHANNEL_ETC2_COLOR = 2U,
KHR_DF_CHANNEL_ETC2_ALPHA = 15U,
KHR_DF_CHANNEL_ETC2_A = 15U,
/* MODEL_ASTC */
KHR_DF_CHANNEL_ASTC_DATA = 0U,
/* MODEL_ETC1S */
KHR_DF_CHANNEL_ETC1S_RGB = 0U,
KHR_DF_CHANNEL_ETC1S_RRR = 3U,
KHR_DF_CHANNEL_ETC1S_GGG = 4U,
KHR_DF_CHANNEL_ETC1S_AAA = 15U,
/* MODEL_PVRTC */
KHR_DF_CHANNEL_PVRTC_DATA = 0U,
KHR_DF_CHANNEL_PVRTC_COLOR = 0U,
/* MODEL_PVRTC2 */
KHR_DF_CHANNEL_PVRTC2_DATA = 0U,
KHR_DF_CHANNEL_PVRTC2_COLOR = 0U,
/* MODEL UASTC */
KHR_DF_CHANNEL_UASTC_DATA = 0U,
KHR_DF_CHANNEL_UASTC_RGB = 0U,
KHR_DF_CHANNEL_UASTC_RGBA = 3U,
KHR_DF_CHANNEL_UASTC_RRR = 4U,
KHR_DF_CHANNEL_UASTC_RRRG = 5U,
KHR_DF_CHANNEL_UASTC_RG = 6U,
/* Common channel names shared by multiple formats */
KHR_DF_CHANNEL_COMMON_LUMA = 0U,
KHR_DF_CHANNEL_COMMON_L = 0U,
KHR_DF_CHANNEL_COMMON_STENCIL = 13U,
KHR_DF_CHANNEL_COMMON_S = 13U,
KHR_DF_CHANNEL_COMMON_DEPTH = 14U,
KHR_DF_CHANNEL_COMMON_D = 14U,
KHR_DF_CHANNEL_COMMON_ALPHA = 15U,
KHR_DF_CHANNEL_COMMON_A = 15U
} khr_df_model_channels_e;
/* Definition of the primary colors in color coordinates.
This is implicitly responsible for defining the conversion
between RGB an YUV color spaces.
LAB and related absolute color models should use
KHR_DF_PRIMARIES_CIEXYZ. */
typedef enum _khr_df_primaries_e {
/* No color primaries defined */
KHR_DF_PRIMARIES_UNSPECIFIED = 0U,
/* Color primaries of ITU-R BT.709 and sRGB */
KHR_DF_PRIMARIES_BT709 = 1U,
/* Synonym for KHR_DF_PRIMARIES_BT709 */
KHR_DF_PRIMARIES_SRGB = 1U,
/* Color primaries of ITU-R BT.601 (625-line EBU variant) */
KHR_DF_PRIMARIES_BT601_EBU = 2U,
/* Color primaries of ITU-R BT.601 (525-line SMPTE C variant) */
KHR_DF_PRIMARIES_BT601_SMPTE = 3U,
/* Color primaries of ITU-R BT.2020 */
KHR_DF_PRIMARIES_BT2020 = 4U,
/* CIE theoretical color coordinate space */
KHR_DF_PRIMARIES_CIEXYZ = 5U,
/* Academy Color Encoding System primaries */
KHR_DF_PRIMARIES_ACES = 6U,
/* Color primaries of ACEScc */
KHR_DF_PRIMARIES_ACESCC = 7U,
/* Legacy NTSC 1953 primaries */
KHR_DF_PRIMARIES_NTSC1953 = 8U,
/* Legacy PAL 525-line primaries */
KHR_DF_PRIMARIES_PAL525 = 9U,
/* Color primaries of Display P3 */
KHR_DF_PRIMARIES_DISPLAYP3 = 10U,
/* Color primaries of Adobe RGB (1998) */
KHR_DF_PRIMARIES_ADOBERGB = 11U,
KHR_DF_PRIMARIES_MAX = 0xFFU
} khr_df_primaries_e;
/* Definition of the optical to digital transfer function
("gamma correction"). Most transfer functions are not a pure
power function and also include a linear element.
LAB and related absolute color representations should use
KHR_DF_TRANSFER_UNSPECIFIED. */
typedef enum _khr_df_transfer_e {
/* No transfer function defined */
KHR_DF_TRANSFER_UNSPECIFIED = 0U,
/* Linear transfer function (value proportional to intensity) */
KHR_DF_TRANSFER_LINEAR = 1U,
/* Perceptually-linear transfer function of sRGH (~2.4) */
KHR_DF_TRANSFER_SRGB = 2U,
/* Perceptually-linear transfer function of ITU BT.601, BT.709 and BT.2020 (~1/.45) */
KHR_DF_TRANSFER_ITU = 3U,
/* SMTPE170M (digital NTSC) defines an alias for the ITU transfer function (~1/.45) */
KHR_DF_TRANSFER_SMTPE170M = 3U,
/* Perceptually-linear gamma function of original NTSC (simple 2.2 gamma) */
KHR_DF_TRANSFER_NTSC = 4U,
/* Sony S-log used by Sony video cameras */
KHR_DF_TRANSFER_SLOG = 5U,
/* Sony S-log 2 used by Sony video cameras */
KHR_DF_TRANSFER_SLOG2 = 6U,
/* ITU BT.1886 EOTF */
KHR_DF_TRANSFER_BT1886 = 7U,
/* ITU BT.2100 HLG OETF */
KHR_DF_TRANSFER_HLG_OETF = 8U,
/* ITU BT.2100 HLG EOTF */
KHR_DF_TRANSFER_HLG_EOTF = 9U,
/* ITU BT.2100 PQ EOTF */
KHR_DF_TRANSFER_PQ_EOTF = 10U,
/* ITU BT.2100 PQ OETF */
KHR_DF_TRANSFER_PQ_OETF = 11U,
/* DCI P3 transfer function */
KHR_DF_TRANSFER_DCIP3 = 12U,
/* Legacy PAL OETF */
KHR_DF_TRANSFER_PAL_OETF = 13U,
/* Legacy PAL 625-line EOTF */
KHR_DF_TRANSFER_PAL625_EOTF = 14U,
/* Legacy ST240 transfer function */
KHR_DF_TRANSFER_ST240 = 15U,
/* ACEScc transfer function */
KHR_DF_TRANSFER_ACESCC = 16U,
/* ACEScct transfer function */
KHR_DF_TRANSFER_ACESCCT = 17U,
/* Adobe RGB (1998) transfer function */
KHR_DF_TRANSFER_ADOBERGB = 18U,
KHR_DF_TRANSFER_MAX = 0xFFU
} khr_df_transfer_e;
typedef enum _khr_df_flags_e {
KHR_DF_FLAG_ALPHA_STRAIGHT = 0U,
KHR_DF_FLAG_ALPHA_PREMULTIPLIED = 1U
} khr_df_flags_e;
typedef enum _khr_df_sample_datatype_qualifiers_e {
KHR_DF_SAMPLE_DATATYPE_LINEAR = 1U << 4U,
KHR_DF_SAMPLE_DATATYPE_EXPONENT = 1U << 5U,
KHR_DF_SAMPLE_DATATYPE_SIGNED = 1U << 6U,
KHR_DF_SAMPLE_DATATYPE_FLOAT = 1U << 7U
} khr_df_sample_datatype_qualifiers_e;
#endif

619
Source/Main.cpp Normal file
View file

@ -0,0 +1,619 @@
#include <iostream>
#include <string>
#include <map>
#include <tuple>
#include <algorithm>
#include <vulkan/vulkan.hpp>
#include <math.h>
#include <thread>
#include <mutex>
#include <numeric>
#include <fstream>
#include <iomanip>
#include <vector>
#include "stb_image_resize.h"
#include "stb_image.h"
#include "dfd.h"
#include "ispc_texcomp/ispc_texcomp.h"
#include "HalfFloat.h"
const std::vector<std::string> formatOrder = {
"BC1",
"BC1_SRGB",
"BC4",
"BC5",
"BC3",
"BC3_SRGB",
"BC6H",
"BC7",
"BC7_SRGB"
};
const std::map<std::string, std::tuple<std::string, int, vk::Format>> formats = {
{"BC1", {"(DXT1) 5:6:5 Color, 1 bit alpha. 8 bytes per block.", 8, vk::Format::eBc1RgbUnormBlock}},
{"BC1_SRGB", {"(DXT1) 5:6:5 Color, 1 bit alpha. 8 bytes per block.", 8, vk::Format::eBc1RgbSrgbBlock}},
{"BC4", {"Greyscale, 8 bytes per block.", 8, vk::Format::eBc4UnormBlock}},
{"BC5", {"2x BC4 images. 16 bytes per block.", 16, vk::Format::eBc5UnormBlock}},
{"BC3", {"(DXT5) BC1 Color, BC4 Alpha, 16 bytes per block.", 16, vk::Format::eBc3UnormBlock}},
{"BC3_SRGB", {"(DXT5) BC1 Color, BC4 Alpha, 16 bytes per block.", 16, vk::Format::eBc3SrgbBlock}},
{"BC6H", {"16 bit RGB, no alpha. Signed. 16 bytes per block.", 16, vk::Format::eBc6HUfloatBlock}},
{"BC7", {"8 bit RGBA - Good general purpose. 16 bytes per block.", 16, vk::Format::eBc7UnormBlock}},
{"BC7_SRGB", {"8 bit RGBA - Good general purpose. 16 bytes per block.", 16, vk::Format::eBc7SrgbBlock}}
};
const std::string usage = "Usage: TextureConverter [cube|array] <input> [input2, input3...] <output> <format> [fast|slow|veryslow]";
int main(int argc, char ** argv)
{
ISPCInit();
if (argc < 4) {
std::cout << usage << std::endl;
std::cout << "Formats:" << std::endl;
for (auto & formatName : formatOrder) {
auto format = formats.at(formatName);
std::cout << " " << formatName << " - " << std::get<0>(format) << std::endl;
}
return 1;
}
int numInputs = argc - 3;
unsigned int inputsStart = 1;
std::vector<std::string> inputs;
std::string output;
std::string option(argv[1]);
if (option == "cube" || option == "array") {
numInputs -= 1;
inputsStart += 1;
} else {
option = "none";
}
std::string speed(argv[argc - 1]);
std::string formatString;
bool fastMode = true;
bool verySlow = false;
if (speed == "fast" || speed == "slow" || speed == "veryslow") {
formatString = std::string(argv[argc - 2]);
numInputs -= 1;
if (speed == "slow") {
fastMode = false;
} else if (speed == "veryslow") {
fastMode = false;
verySlow = true;
}
} else {
formatString = std::string(argv[argc - 1]);
}
if (numInputs < 1) {
std::cout << usage << std::endl;
return 1;
}
if (option == "cube" && numInputs != 6) {
std::cout << "Cube maps must have 6 inputs." << std::endl;
return 1;
}
if (option == "array" && numInputs < 2) {
std::cout << "Array maps must have at least 2 inputs." << std::endl;
return 1;
}
if (formats.find(formatString) == formats.end()) {
std::cout << "Invalid format: " << formatString << std::endl;
std::cout << usage << std::endl;
std::cout << "Formats:" << std::endl;
for (auto & formatName : formatOrder) {
auto format = formats.at(formatName);
std::cout << " " << formatName << " - " << std::get<0>(format) << std::endl;
}
return 1;
}
/* Check if it ends in SRGB */
bool srgb = false;
if (formatString.length() > 5 && formatString.substr(formatString.length() - 5, 5) == "_SRGB") {
srgb = true;
}
bool hdr = false;
if (formatString.substr(0, 3) == "BC6") {
hdr = true;
}
for (int i = inputsStart; i < (int)(inputsStart + numInputs); i++) {
inputs.push_back(std::string(argv[i]));
}
output = std::string(argv[inputsStart + numInputs]);
/* Print inputs and output */
std::cout << "Inputs: " << std::endl;
for (auto & input : inputs) {
std::cout << " " << input << std::endl;
}
std::cout << "Output: " << output << std::endl;
std::cout << "Format: " << formatString << std::endl;
std::cout << "Speed: " << (fastMode ? "Fast" : verySlow ? "Very slow" : "Slow") << std::endl;
int isa;
isa = ISPCIsa();
std::string isaName;
switch(isa) {
case 0:
isaName = "SSE2";
break;
case 1:
isaName = "SSE4";
break;
case 2:
isaName = "AVX2";
break;
default:
isaName = "Unknown";
};
std::cout << "ISPC ISA: " << isaName << std::endl;
unsigned char * ldrBufferA, * ldrBufferB, * ldrBufferMain, * ldrBufferOther;
float * hdrBufferA, * hdrBufferB, * hdrBufferMain, * hdrBufferOther;
int width, height, channels;
int copyChannels = 4;
int forcedChannels = 4;
if (formatString == "BC4") {
copyChannels = 1;
} else if (formatString == "BC5") {
copyChannels = 2;
}
std::vector<std::vector<std::vector<unsigned char>>> ldrLevels;
std::vector<std::vector<std::vector<float>>> hdrLevels;
std::vector<std::vector<std::vector<std::vector<unsigned char>>>> ldrLevelBlocks;
std::vector<std::vector<std::vector<std::vector<uint16_t>>>> hdrLevelBlocks;
if (hdr) {
hdrLevels.resize(numInputs);
hdrLevelBlocks.resize(numInputs);
} else {
ldrLevels.resize(numInputs);
ldrLevelBlocks.resize(numInputs);
}
uint32_t levelCount;
for (int input = 0; input < numInputs; input++) {
int level = 0;
std::cout << "Loading/scaling " << input << ": " << inputs[input] << std::endl;
if (hdr) {
hdrBufferA = stbi_loadf(inputs[input].c_str(), &width, &height, &channels, forcedChannels);
if (hdrBufferA == nullptr) {
std::cout << "Failed to load image: " << inputs[input] << std::endl;
return 1;
}
hdrBufferB = new float[width * height * forcedChannels];
hdrBufferMain = hdrBufferA;
hdrBufferOther = hdrBufferB;
} else {
ldrBufferA = stbi_load(inputs[input].c_str(), &width, &height, &channels, forcedChannels);
if (ldrBufferA == nullptr) {
std::cout << "Failed to load image: " << inputs[input] << std::endl;
return 1;
}
ldrBufferB = new unsigned char[width * height * forcedChannels];
ldrBufferMain = ldrBufferA;
ldrBufferOther = ldrBufferB;
}
int oldWidth = width;
int oldHeight = height;
levelCount = 1;
{
int levelWidth = width;
int levelHeight = height;
while (levelWidth > 1 || levelHeight > 1) {
levelWidth = std::max(1, (int)floorf((float)levelWidth / 2));
levelHeight = std::max(1, (int)floorf((float)levelHeight / 2));
levelCount++;
}
}
while(1) {
if (hdr) {
hdrLevels[input].push_back(std::vector<float>(hdrBufferMain, hdrBufferMain + oldWidth * oldHeight * forcedChannels));
} else {
ldrLevels[input].push_back(std::vector<uint8_t>(ldrBufferMain, ldrBufferMain + oldWidth * oldHeight * forcedChannels));
}
if (oldWidth == 1 && oldHeight == 1) {
break;
}
int newWidth = std::max(1, (int)floorf((float)oldWidth / 2));
int newHeight = std::max(1, (int)floorf((float)oldHeight / 2));
stbir_colorspace colorspace = srgb ? STBIR_COLORSPACE_SRGB : STBIR_COLORSPACE_LINEAR;
int alphaChannel = channels == 4 ? 3 : STBIR_ALPHA_CHANNEL_NONE;
if (hdr) {
int rv = stbir_resize_float_generic(hdrBufferMain, oldWidth, oldHeight, 0, hdrBufferOther, newWidth, newHeight, 0, forcedChannels, alphaChannel, 0, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL, colorspace, nullptr);
if (rv != 1) {
std::cerr << "Error resizing" << std::endl;
}
std::swap(hdrBufferMain, hdrBufferOther);
} else {
int rv = stbir_resize_uint8_generic(ldrBufferMain, oldWidth, oldHeight, 0, ldrBufferOther, newWidth, newHeight, 0, forcedChannels, alphaChannel, 0, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL, colorspace, nullptr);
if (rv != 1) {
std::cerr << "Error resizing" << std::endl;
}
std::swap(ldrBufferMain, ldrBufferOther);
}
oldWidth = newWidth;
oldHeight = newHeight;
level++;
}
oldWidth = width;
oldHeight = height;
level = 0;
if (hdr) {
free(hdrBufferA);
delete[] hdrBufferB;
} else {
free(ldrBufferA);
delete[] ldrBufferB;
}
}
bc6h_enc_settings bc6henc;
bc7_enc_settings bc7enc;
if (formatString == "BC6H") {
if (fastMode) {
GetProfile_bc6h_basic(&bc6henc);
} else {
if (verySlow) {
GetProfile_bc6h_veryslow(&bc6henc);
} else {
GetProfile_bc6h_slow(&bc6henc);
}
}
} else {
if (channels == 3) {
if (fastMode) {
GetProfile_basic(&bc7enc);
} else {
GetProfile_slow(&bc7enc);
}
} else {
if (fastMode) {
GetProfile_alpha_basic(&bc7enc);
} else {
GetProfile_alpha_slow(&bc7enc);
}
}
}
std::vector<std::vector<std::vector<unsigned char>>> levelBlocksCompressed(numInputs);
std::tuple<std::string, int, vk::Format> format = formats.find(formatString)->second;
size_t blockSize = std::get<1>(format);
for (int input = 0; input < numInputs; input++) {
if (numInputs > 1) {
if (option == "cube") {
std::cout << "Face " << input << std::endl;
} else {
std::cout << "Layer " << input << std::endl;
}
}
if (hdr) {
hdrLevelBlocks[input].resize(levelCount);
} else {
ldrLevelBlocks[input].resize(levelCount);
}
int level = 0;
int oldWidth = width;
int oldHeight = height;
while(1) {
unsigned int blocksWidth = (oldWidth + 3) / 4;
unsigned int blocksHeight = (oldHeight + 3) / 4;
if (hdr) {
hdrLevelBlocks[input][level].resize(blocksWidth * blocksHeight);
for (unsigned int y = 0; y < blocksHeight; y++) {
for (unsigned int x = 0; x < blocksWidth; x++) {
std::vector<uint16_t> block(16 * copyChannels);
for (unsigned int pixelY = y * 4; pixelY < y * 4 + 4; pixelY++) {
for (unsigned int pixelX = x * 4; pixelX < x * 4 + 4; pixelX++) {
unsigned int clampedY = std::min(pixelY, (unsigned int)oldHeight - 1);
unsigned int clampedX = std::min(pixelX, (unsigned int)oldWidth - 1);
for (int channel = 0; channel < copyChannels; channel++) {
float value = hdrLevels[input][level][(clampedY * oldWidth + clampedX) * forcedChannels + channel];
if (value < 0.0f) {
value = 0.0f;
}
if (value > 65504.0f) {
value = 65504.0f;
}
block[((pixelY % 4) * 4 + (pixelX % 4)) * copyChannels + channel] = HalfFloat::FromFloat(value);
}
}
}
hdrLevelBlocks[input][level][blocksWidth * y + x] = block;
}
}
} else {
ldrLevelBlocks[input][level].resize(blocksWidth * blocksHeight);
for (unsigned int y = 0; y < blocksHeight; y++) {
for (unsigned int x = 0; x < blocksWidth; x++) {
std::vector<uint8_t> block(16 * copyChannels);
for (unsigned int pixelY = y * 4; pixelY < y * 4 + 4; pixelY++) {
for (unsigned int pixelX = x * 4; pixelX < x * 4 + 4; pixelX++) {
unsigned int clampedY = std::min(pixelY, (unsigned int)oldHeight - 1);
unsigned int clampedX = std::min(pixelX, (unsigned int)oldWidth - 1);
for (int channel = 0; channel < copyChannels; channel++) {
block[((pixelY % 4) * 4 + (pixelX % 4)) * copyChannels + channel] = ldrLevels[input][level][(clampedY * oldWidth + clampedX) * forcedChannels + channel];
}
}
}
ldrLevelBlocks[input][level][blocksWidth * y + x] = block;
}
}
}
if (oldWidth == 1 && oldHeight == 1) {
break;
}
oldWidth = std::max(1, (int)floorf((float)oldWidth / 2));
oldHeight = std::max(1, (int)floorf((float)oldHeight / 2));
level++;
}
/* Compress */
levelBlocksCompressed[input].resize(levelCount);
for (unsigned int l = 0; l < levelCount; l++) {
if (hdr) {
levelBlocksCompressed[input][l].resize(hdrLevelBlocks[input][l].size() * blockSize);
} else {
levelBlocksCompressed[input][l].resize(ldrLevelBlocks[input][l].size() * blockSize);
}
}
std::mutex mutex;
std::vector<unsigned int> completedBlocks(levelCount, 0);
unsigned int numThreads = std::thread::hardware_concurrency();
std::vector<std::thread> threads;
unsigned int maxLevel = 0;
for (unsigned t = 0; t < numThreads; t++) {
threads.push_back(std::thread([&, t](){
for (unsigned int l = 0; l < levelCount; l++) {
unsigned int blocksPerThread;
if (hdr) {
blocksPerThread = hdrLevelBlocks[input][l].size() / numThreads;
} else {
blocksPerThread = ldrLevelBlocks[input][l].size() / numThreads;
}
unsigned int startBlock = t * blocksPerThread;
unsigned int endBlock = startBlock + blocksPerThread;
if (hdr) {
if (t == numThreads - 1) {
endBlock = hdrLevelBlocks[input][l].size();
}
} else {
if (t == numThreads - 1) {
endBlock = ldrLevelBlocks[input][l].size();
}
}
for (unsigned int b = startBlock; b < endBlock; b++) {
if (formatString == "BC6H") {
rgba_surface surface;
surface.ptr = (uint8_t *)hdrLevelBlocks[input][l][b].data();
surface.width = 4;
surface.height = 4;
surface.stride = copyChannels * 4 * 2;
CompressBlocksBC6H(&surface, &levelBlocksCompressed[input][l][b * blockSize], &bc6henc);
} else {
rgba_surface surface;
surface.ptr = ldrLevelBlocks[input][l][b].data();
surface.width = 4;
surface.height = 4;
surface.stride = copyChannels * 4;
if (formatString == "BC1" || formatString == "BC1_SRGB") {
CompressBlocksBC1(&surface, &levelBlocksCompressed[input][l][b * blockSize]);
} else if (formatString == "BC3" || formatString == "BC3_SRGB") {
CompressBlocksBC3(&surface, &levelBlocksCompressed[input][l][b * blockSize]);
} else if (formatString == "BC4") {
CompressBlocksBC4(&surface, &levelBlocksCompressed[input][l][b * blockSize]);
} else if (formatString == "BC5") {
CompressBlocksBC5(&surface, &levelBlocksCompressed[input][l][b * blockSize]);
} else if (formatString == "BC7" || formatString == "BC7_SRGB") {
CompressBlocksBC7(&surface, &levelBlocksCompressed[input][l][b * blockSize], &bc7enc);
}
}
std::lock_guard<std::mutex> lock(mutex);
completedBlocks[l]++;
if (completedBlocks[l] % 100 == 0) {
maxLevel = std::max(l, maxLevel);
if (l == maxLevel) {
float progress;
if (hdr) {
progress = (float)completedBlocks[l] / hdrLevelBlocks[input][l].size();
} else {
progress = (float)completedBlocks[l] / ldrLevelBlocks[input][l].size();
}
int barWidth = 70;
std::cout << std::setw(2) << l << " [";
int pos = barWidth * progress;
for (int i = 0; i < barWidth; ++i) {
if (i < pos) std::cout << "=";
else if (i == pos) std::cout << ">";
else std::cout << " ";
}
std::cout << "] " << std::setw(2) << int(progress * 100.0) << " %\r";
std::cout.flush();
}
}
}
}
}));
}
for (unsigned t = 0; t < numThreads; t++) {
threads[t].join();
}
if (hdr) {
hdrLevelBlocks[input].clear();
} else {
ldrLevelBlocks[input].clear();
}
int barWidth = 70;
std::cout << std::setw(2) << (levelCount - 1) << " [";
int pos = barWidth;
for (int i = 0; i < barWidth; ++i) {
if (i < pos) std::cout << "=";
else if (i == pos) std::cout << ">";
else std::cout << " ";
}
std::cout << "] " << std::setw(2) << 100 << " %\r";
std::cout.flush();
std::cout << std::endl;
}
/* Write KTX2 */
std::ofstream fh (output, std::ios::out | std::ios::binary);
if (!fh.is_open()) {
std::cout << "Failed to open output file: " << output << std::endl;
return 1;
}
const uint8_t identifier[] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};
fh.write((char *)identifier, sizeof(identifier));
vk::Format vkformat = std::get<2>(formats.at(formatString));
fh.write((char *)&vkformat, sizeof(vkformat));
uint32_t typeSize = 1; // Fix for uncompressed vkformats, size of an individual component
fh.write((char *)&typeSize, sizeof(typeSize));
uint32_t pixelWidth = width;
uint32_t pixelHeight = height;
uint32_t pixelDepth = 0;
uint32_t layerCount;
uint32_t faceCount;
if (numInputs > 1) {
if (option == "cube") {
layerCount = 0;
faceCount = 6;
} else {
layerCount = numInputs;
faceCount = 1;
}
} else {
layerCount = 0;
faceCount = 1;
}
uint32_t supercompressionScheme = 0;
fh.write((char *)&pixelWidth, sizeof(pixelWidth));
fh.write((char *)&pixelHeight, sizeof(pixelHeight));
fh.write((char *)&pixelDepth, sizeof(pixelDepth));
fh.write((char *)&layerCount, sizeof(layerCount));
fh.write((char *)&faceCount, sizeof(faceCount));
fh.write((char *)&levelCount, sizeof(levelCount));
fh.write((char *)&supercompressionScheme, sizeof(supercompressionScheme));
uint32_t * dfd = vk2dfd(*(VkFormat *)&vkformat);
uint32_t dfdByteOffset = 0;
uint32_t dfdByteLength = dfd[0];
uint32_t kvdByteOffset = 0;
uint32_t kvdByteLength = 0;
uint64_t sgdByteOffset = 0;
uint64_t sgdByteLength = 0;
auto dfdByteOffsetPosition = fh.tellp();
fh.write((char *)&dfdByteOffset, sizeof(dfdByteOffset));
fh.write((char *)&dfdByteLength, sizeof(dfdByteLength));
fh.write((char *)&kvdByteOffset, sizeof(kvdByteOffset));
fh.write((char *)&kvdByteLength, sizeof(kvdByteLength));
fh.write((char *)&sgdByteOffset, sizeof(sgdByteOffset));
fh.write((char *)&sgdByteLength, sizeof(sgdByteLength));
auto levelOffsetBytePosition = fh.tellp();
for (unsigned int i = 0; i < levelCount; i++) {
uint64_t byteOffset = 0;
uint64_t byteLength = 0;
uint64_t uncompressedByteLength = 0;
fh.write((char *)&byteOffset, sizeof(byteOffset));
fh.write((char *)&byteLength, sizeof(byteLength));
fh.write((char *)&uncompressedByteLength, sizeof(uncompressedByteLength));
}
dfdByteOffset = fh.tellp();
fh.write((char *)dfd, dfdByteLength);
free(dfd);
kvdByteOffset = fh.tellp();
fh.seekp(dfdByteOffsetPosition);
fh.write((char *)&dfdByteOffset, sizeof(dfdByteOffset));
fh.seekp(kvdByteOffset);
size_t alignment = std::lcm((size_t)4, (size_t)std::get<1>(formats.at(formatString)));
for (int level = levelCount - 1; level >= 0; level--) {
// Alignment
while (fh.tellp() % alignment != 0) {
uint8_t padding = 0;
fh.write((char *)&padding, sizeof(padding));
}
auto levelBytePosition = fh.tellp();
fh.seekp(levelOffsetBytePosition + (std::ofstream::pos_type)(level * 24));
uint64_t byteOffset = levelBytePosition;
fh.write((char *)&byteOffset, sizeof(byteOffset));
uint64_t byteLength = levelBlocksCompressed[0][level].size() * numInputs;
fh.write((char *)&byteLength, sizeof(byteLength));
fh.write((char *)&byteLength, sizeof(byteLength));
fh.seekp(levelBytePosition);
for (int input = 0; input < numInputs; input++) {
fh.write((char *)levelBlocksCompressed[input][level].data(), levelBlocksCompressed[input][level].size());
}
}
return 0;
}

659
Source/createdfd.cpp Normal file
View file

@ -0,0 +1,659 @@
/* -*- tab-width: 4; -*- */
/* vi: set sw=2 ts=4 expandtab: */
/* Copyright 2019-2020 The Khronos Group Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @~English
* @brief Utilities for creating data format descriptors.
*/
/*
* Author: Andrew Garrard
*/
#include <stdlib.h>
#include <KHR/khr_df.h>
#include "dfd.h"
typedef enum { i_COLOR, i_NON_COLOR } channels_infotype;
static uint32_t *writeHeader(int numSamples, int bytes, int suffix,
channels_infotype infotype)
{
uint32_t *DFD = (uint32_t *) malloc(sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS));
uint32_t* BDFD = DFD+1;
DFD[0] = sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS);
BDFD[KHR_DF_WORD_VENDORID] =
(KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) |
(KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE);
BDFD[KHR_DF_WORD_VERSIONNUMBER] =
(KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) |
(((uint32_t)sizeof(uint32_t) *
(KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS)
<< KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE));
BDFD[KHR_DF_WORD_MODEL] =
((KHR_DF_MODEL_RGBSDA << KHR_DF_SHIFT_MODEL) | /* Only supported model */
(KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS));
if (infotype == i_COLOR) {
BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES; /* Assumed */
} else {
BDFD[KHR_DF_WORD_PRIMARIES] |= KHR_DF_PRIMARIES_UNSPECIFIED << KHR_DF_SHIFT_PRIMARIES;
}
if (suffix == s_SRGB) {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER;
} else {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER;
}
BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] = 0; /* Only 1x1x1x1 texel blocks supported */
BDFD[KHR_DF_WORD_BYTESPLANE0] = bytes; /* bytesPlane0 = bytes, bytesPlane3..1 = 0 */
BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */
return DFD;
}
static uint32_t setChannelFlags(uint32_t channel, enum VkSuffix suffix)
{
switch (suffix) {
case s_UNORM: break;
case s_SNORM:
channel |=
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_USCALED: break;
case s_SSCALED:
channel |=
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_UINT: break;
case s_SINT:
channel |=
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_SFLOAT:
channel |=
KHR_DF_SAMPLE_DATATYPE_FLOAT |
KHR_DF_SAMPLE_DATATYPE_SIGNED;
break;
case s_UFLOAT:
channel |=
KHR_DF_SAMPLE_DATATYPE_FLOAT;
break;
case s_SRGB:
if (channel == KHR_DF_CHANNEL_RGBSDA_ALPHA) {
channel |= KHR_DF_SAMPLE_DATATYPE_LINEAR;
}
break;
}
return channel;
}
static void writeSample(uint32_t *DFD, int sampleNo, int channel,
int bits, int offset,
int topSample, int bottomSample, enum VkSuffix suffix)
{
// Use this to avoid type-punning complaints from the gcc optimizer
// with -Wall.
union {
uint32_t i;
float f;
} lower, upper;
uint32_t *sample = DFD + 1 + KHR_DF_WORD_SAMPLESTART + sampleNo * KHR_DF_WORD_SAMPLEWORDS;
if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA;
if (channel == 3) channel = KHR_DF_CHANNEL_RGBSDA_ALPHA;
channel = setChannelFlags(channel, suffix);
sample[KHR_DF_SAMPLEWORD_BITOFFSET] =
(offset << KHR_DF_SAMPLESHIFT_BITOFFSET) |
((bits - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |
(channel << KHR_DF_SAMPLESHIFT_CHANNELID);
sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;
switch (suffix) {
case s_UNORM:
case s_SRGB:
default:
if (bits > 32) {
upper.i = 0xFFFFFFFFU;
} else {
upper.i = (uint32_t)((1U << bits) - 1U);
}
lower.i = 0U;
break;
case s_SNORM:
if (bits > 32) {
upper.i = 0x7FFFFFFF;
} else {
upper.i = topSample ? (1U << (bits - 1)) - 1 : (1U << bits) - 1;
}
lower.i = ~upper.i;
if (bottomSample) lower.i += 1;
break;
case s_USCALED:
case s_UINT:
upper.i = bottomSample ? 1U : 0U;
lower.i = 0U;
break;
case s_SSCALED:
case s_SINT:
upper.i = bottomSample ? 1U : 0U;
lower.i = ~0U;
break;
case s_SFLOAT:
upper.f = 1.0f;
lower.f = -1.0f;
break;
case s_UFLOAT:
upper.f = 1.0f;
lower.f = 0.0f;
break;
}
sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;
sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;
}
/**
* @~English
* @brief Create a Data Format Descriptor for an unpacked format.
*
* @param bigEndian Set to 1 for big-endian byte ordering and
0 for little-endian byte ordering.
* @param numChannels The number of color channels.
* @param bytes The number of bytes per channel.
* @param redBlueSwap Normally channels appear in consecutive R, G, B, A order
* in memory; redBlueSwap inverts red and blue, allowing
* B, G, R, A.
* @param suffix Indicates the format suffix for the type.
*
* @return A data format descriptor in malloc'd data. The caller is responsible
* for freeing the descriptor.
**/
uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes,
int redBlueSwap, enum VkSuffix suffix)
{
uint32_t *DFD;
if (bigEndian) {
int channelCounter, channelByte;
/* Number of samples = number of channels * bytes per channel */
DFD = writeHeader(numChannels * bytes, numChannels * bytes, suffix, i_COLOR);
/* First loop over the channels */
for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {
int channel = channelCounter;
if (redBlueSwap && (channel == 0 || channel == 2)) {
channel ^= 2;
}
/* Loop over the bytes that constitute a channel */
for (channelByte = 0; channelByte < bytes; ++channelByte) {
writeSample(DFD, channelCounter * bytes + channelByte, channel,
8, 8 * (channelCounter * bytes + bytes - channelByte - 1),
channelByte == bytes-1, channelByte == 0, suffix);
}
}
} else { /* Little-endian */
int sampleCounter;
/* One sample per channel */
DFD = writeHeader(numChannels, numChannels * bytes, suffix, i_COLOR);
for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {
int channel = sampleCounter;
if (redBlueSwap && (channel == 0 || channel == 2)) {
channel ^= 2;
}
writeSample(DFD, sampleCounter, channel,
8 * bytes, 8 * sampleCounter * bytes,
1, 1, suffix);
}
}
return DFD;
}
/**
* @~English
* @brief Create a Data Format Descriptor for a packed format.
*
* @param bigEndian Big-endian flag: Set to 1 for big-endian byte ordering and
* 0 for little-endian byte ordering.
* @param numChannels The number of color channels.
* @param bits[] An array of length numChannels.
* Each entry is the number of bits composing the channel, in
* order starting at bit 0 of the packed type.
* @param channels[] An array of length numChannels.
* Each entry enumerates the channel type: 0 = red, 1 = green,
* 2 = blue, 15 = alpha, in order starting at bit 0 of the
* packed type. These values match channel IDs for RGBSDA in
* the Khronos Data Format header. To simplify iteration
* through channels, channel id 3 is a synonym for alpha.
* @param suffix Indicates the format suffix for the type.
*
* @return A data format descriptor in malloc'd data. The caller is responsible
* for freeing the descriptor.
**/
uint32_t *createDFDPacked(int bigEndian, int numChannels,
int bits[], int channels[],
enum VkSuffix suffix)
{
uint32_t *DFD = 0;
if (numChannels == 6) {
/* Special case E5B9G9R9 */
DFD = writeHeader(numChannels, 4, s_UFLOAT, i_COLOR);
writeSample(DFD, 0, 0,
9, 0,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 0, SAMPLEUPPER, 8448);
writeSample(DFD, 1, 0 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,
5, 27,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 1, SAMPLELOWER, 15);
KHR_DFDSETSVAL((DFD+1), 1, SAMPLEUPPER, 31);
writeSample(DFD, 2, 1,
9, 9,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 2, SAMPLEUPPER, 8448);
writeSample(DFD, 3, 1 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,
5, 27,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 3, SAMPLELOWER, 15);
KHR_DFDSETSVAL((DFD+1), 3, SAMPLEUPPER, 31);
writeSample(DFD, 4, 2,
9, 18,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 4, SAMPLEUPPER, 8448);
writeSample(DFD, 5, 2 | KHR_DF_SAMPLE_DATATYPE_EXPONENT,
5, 27,
1, 1, s_UNORM);
KHR_DFDSETSVAL((DFD+1), 5, SAMPLELOWER, 15);
KHR_DFDSETSVAL((DFD+1), 5, SAMPLEUPPER, 31);
} else if (bigEndian) {
/* No packed format is larger than 32 bits. */
/* No packed channel crosses more than two bytes. */
int totalBits = 0;
int bitChannel[32];
int beChannelStart[4];
int channelCounter;
int bitOffset = 0;
int BEMask;
int numSamples = numChannels;
int sampleCounter;
for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {
beChannelStart[channelCounter] = totalBits;
totalBits += bits[channelCounter];
}
BEMask = (totalBits - 1) & 0x18;
for (channelCounter = 0; channelCounter < numChannels; ++channelCounter) {
bitChannel[bitOffset ^ BEMask] = channelCounter;
if (((bitOffset + bits[channelCounter] - 1) & ~7) != (bitOffset & ~7)) {
/* Continuation sample */
bitChannel[((bitOffset + bits[channelCounter] - 1) & ~7) ^ BEMask] = channelCounter;
numSamples++;
}
bitOffset += bits[channelCounter];
}
DFD = writeHeader(numSamples, totalBits >> 3, suffix, i_COLOR);
sampleCounter = 0;
for (bitOffset = 0; bitOffset < totalBits;) {
if (bitChannel[bitOffset] == -1) {
/* Done this bit, so this is the lower half of something. */
/* We must therefore jump to the end of the byte and continue. */
bitOffset = (bitOffset + 8) & ~7;
} else {
/* Start of a channel? */
int thisChannel = bitChannel[bitOffset];
if ((beChannelStart[thisChannel] ^ BEMask) == bitOffset) {
/* Must be just one sample if we hit it first. */
writeSample(DFD, sampleCounter++, channels[thisChannel],
bits[thisChannel], bitOffset,
1, 1, suffix);
bitOffset += bits[thisChannel];
} else {
/* Two samples. Move to the end of the first one we hit when we're done. */
int firstSampleBits = 8 - (beChannelStart[thisChannel] & 0x7); /* Rest of the byte */
int secondSampleBits = bits[thisChannel] - firstSampleBits; /* Rest of the bits */
writeSample(DFD, sampleCounter++, channels[thisChannel],
firstSampleBits, beChannelStart[thisChannel] ^ BEMask,
0, 1, suffix);
/* Mark that we've already handled this sample */
bitChannel[beChannelStart[thisChannel] ^ BEMask] = -1;
writeSample(DFD, sampleCounter++, channels[thisChannel],
secondSampleBits, bitOffset,
1, 0, suffix);
bitOffset += secondSampleBits;
}
}
}
} else { /* Little-endian */
int sampleCounter;
int totalBits = 0;
int bitOffset = 0;
for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {
totalBits += bits[sampleCounter];
}
/* One sample per channel */
DFD = writeHeader(numChannels, totalBits >> 3, suffix, i_COLOR);
for (sampleCounter = 0; sampleCounter < numChannels; ++sampleCounter) {
writeSample(DFD, sampleCounter, channels[sampleCounter],
bits[sampleCounter], bitOffset,
1, 1, suffix);
bitOffset += bits[sampleCounter];
}
}
return DFD;
}
static khr_df_model_e compModelMapping[] = {
KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, no alpha. */
KHR_DF_MODEL_BC1A, /*!< BC1, aka DXT1, punch-through alpha. */
KHR_DF_MODEL_BC2, /*!< BC2, aka DXT2 and DXT3. */
KHR_DF_MODEL_BC3, /*!< BC3, aka DXT4 and DXT5. */
KHR_DF_MODEL_BC4, /*!< BC4. */
KHR_DF_MODEL_BC5, /*!< BC5. */
KHR_DF_MODEL_BC6H, /*!< BC6h HDR format. */
KHR_DF_MODEL_BC7, /*!< BC7. */
KHR_DF_MODEL_ETC2, /*!< ETC2 no alpha. */
KHR_DF_MODEL_ETC2, /*!< ETC2 punch-through alpha. */
KHR_DF_MODEL_ETC2, /*!< ETC2 independent alpha. */
KHR_DF_MODEL_ETC2, /*!< R11 ETC2 single-channel. */
KHR_DF_MODEL_ETC2, /*!< R11G11 ETC2 dual-channel. */
KHR_DF_MODEL_ASTC, /*!< ASTC. */
KHR_DF_MODEL_ETC1S, /*!< ETC1S. */
KHR_DF_MODEL_PVRTC, /*!< PVRTC(1). */
KHR_DF_MODEL_PVRTC2 /*!< PVRTC2. */
};
static uint32_t compSampleCount[] = {
1U, /*!< BC1, aka DXT1, no alpha. */
1U, /*!< BC1, aka DXT1, punch-through alpha. */
2U, /*!< BC2, aka DXT2 and DXT3. */
2U, /*!< BC3, aka DXT4 and DXT5. */
1U, /*!< BC4. */
2U, /*!< BC5. */
1U, /*!< BC6h HDR format. */
1U, /*!< BC7. */
1U, /*!< ETC2 no alpha. */
2U, /*!< ETC2 punch-through alpha. */
2U, /*!< ETC2 independent alpha. */
1U, /*!< R11 ETC2 single-channel. */
2U, /*!< R11G11 ETC2 dual-channel. */
1U, /*!< ASTC. */
1U, /*!< ETC1S. */
1U, /*!< PVRTC. */
1U /*!< PVRTC2. */
};
static khr_df_model_channels_e compFirstChannel[] = {
KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */
KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */
KHR_DF_CHANNEL_BC2_ALPHA, /*!< BC2, aka DXT2 and DXT3. */
KHR_DF_CHANNEL_BC3_ALPHA, /*!< BC3, aka DXT4 and DXT5. */
KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */
KHR_DF_CHANNEL_BC5_RED, /*!< BC5. */
KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */
KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */
KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */
KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 punch-through alpha. */
KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 independent alpha. */
KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */
KHR_DF_CHANNEL_ETC2_RED, /*!< R11G11 ETC2 dual-channel. */
KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */
KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */
KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */
KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */
};
static khr_df_model_channels_e compSecondChannel[] = {
KHR_DF_CHANNEL_BC1A_COLOR, /*!< BC1, aka DXT1, no alpha. */
KHR_DF_CHANNEL_BC1A_ALPHAPRESENT, /*!< BC1, aka DXT1, punch-through alpha. */
KHR_DF_CHANNEL_BC2_COLOR, /*!< BC2, aka DXT2 and DXT3. */
KHR_DF_CHANNEL_BC3_COLOR, /*!< BC3, aka DXT4 and DXT5. */
KHR_DF_CHANNEL_BC4_DATA, /*!< BC4. */
KHR_DF_CHANNEL_BC5_GREEN, /*!< BC5. */
KHR_DF_CHANNEL_BC6H_COLOR, /*!< BC6h HDR format. */
KHR_DF_CHANNEL_BC7_COLOR, /*!< BC7. */
KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 no alpha. */
KHR_DF_CHANNEL_ETC2_ALPHA, /*!< ETC2 punch-through alpha. */
KHR_DF_CHANNEL_ETC2_COLOR, /*!< ETC2 independent alpha. */
KHR_DF_CHANNEL_ETC2_RED, /*!< R11 ETC2 single-channel. */
KHR_DF_CHANNEL_ETC2_GREEN, /*!< R11G11 ETC2 dual-channel. */
KHR_DF_CHANNEL_ASTC_DATA, /*!< ASTC. */
KHR_DF_CHANNEL_ETC1S_RGB, /*!< ETC1S. */
KHR_DF_CHANNEL_PVRTC_COLOR, /*!< PVRTC. */
KHR_DF_CHANNEL_PVRTC2_COLOR /*!< PVRTC2. */
};
static uint32_t compSecondChannelOffset[] = {
0U, /*!< BC1, aka DXT1, no alpha. */
0U, /*!< BC1, aka DXT1, punch-through alpha. */
64U, /*!< BC2, aka DXT2 and DXT3. */
64U, /*!< BC3, aka DXT4 and DXT5. */
0U, /*!< BC4. */
64U, /*!< BC5. */
0U, /*!< BC6h HDR format. */
0U, /*!< BC7. */
0U, /*!< ETC2 no alpha. */
0U, /*!< ETC2 punch-through alpha. */
64U, /*!< ETC2 independent alpha. */
0U, /*!< R11 ETC2 single-channel. */
64U, /*!< R11G11 ETC2 dual-channel. */
0U, /*!< ASTC. */
0U, /*!< ETC1S. */
0U, /*!< PVRTC. */
0U /*!< PVRTC2. */
};
static uint32_t compChannelBits[] = {
64U, /*!< BC1, aka DXT1, no alpha. */
64U, /*!< BC1, aka DXT1, punch-through alpha. */
64U, /*!< BC2, aka DXT2 and DXT3. */
64U, /*!< BC3, aka DXT4 and DXT5. */
64U, /*!< BC4. */
64U, /*!< BC5. */
128U, /*!< BC6h HDR format. */
128U, /*!< BC7. */
64U, /*!< ETC2 no alpha. */
64U, /*!< ETC2 punch-through alpha. */
64U, /*!< ETC2 independent alpha. */
64U, /*!< R11 ETC2 single-channel. */
64U, /*!< R11G11 ETC2 dual-channel. */
128U, /*!< ASTC. */
64U, /*!< ETC1S. */
64U, /*!< PVRTC. */
64U /*!< PVRTC2. */
};
static uint32_t compBytes[] = {
8U, /*!< BC1, aka DXT1, no alpha. */
8U, /*!< BC1, aka DXT1, punch-through alpha. */
16U, /*!< BC2, aka DXT2 and DXT3. */
16U, /*!< BC3, aka DXT4 and DXT5. */
8U, /*!< BC4. */
16U, /*!< BC5. */
16U, /*!< BC6h HDR format. */
16U, /*!< BC7. */
8U, /*!< ETC2 no alpha. */
8U, /*!< ETC2 punch-through alpha. */
16U, /*!< ETC2 independent alpha. */
8U, /*!< R11 ETC2 single-channel. */
16U, /*!< R11G11 ETC2 dual-channel. */
16U, /*!< ASTC. */
8U, /*!< ETC1S. */
8U, /*!< PVRTC. */
8U /*!< PVRTC2. */
};
/**
* @~English
* @brief Create a Data Format Descriptor for a compressed format.
*
* @param compScheme Vulkan-style compression scheme enumeration.
* @param bwidth Block width in texel coordinates.
* @param bheight Block height in texel coordinates.
* @param bdepth Block depth in texel coordinates.
* @author Mark Callow, Edgewise Consulting.
* @param suffix Indicates the format suffix for the type.
*
* @return A data format descriptor in malloc'd data. The caller is responsible
* for freeing the descriptor.
**/
uint32_t *createDFDCompressed(enum VkCompScheme compScheme, int bwidth, int bheight, int bdepth,
enum VkSuffix suffix)
{
uint32_t *DFD = 0;
uint32_t numSamples = compSampleCount[compScheme];
uint32_t* BDFD;
uint32_t *sample;
uint32_t channel;
// Use union to avoid type-punning complaints from gcc optimizer
// with -Wall.
union {
uint32_t i;
float f;
} lower, upper;
DFD = (uint32_t *) malloc(sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS));
BDFD = DFD+1;
DFD[0] = sizeof(uint32_t) *
(1 + KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS);
BDFD[KHR_DF_WORD_VENDORID] =
(KHR_DF_VENDORID_KHRONOS << KHR_DF_SHIFT_VENDORID) |
(KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT << KHR_DF_SHIFT_DESCRIPTORTYPE);
BDFD[KHR_DF_WORD_VERSIONNUMBER] =
(KHR_DF_VERSIONNUMBER_LATEST << KHR_DF_SHIFT_VERSIONNUMBER) |
(((uint32_t)sizeof(uint32_t) *
(KHR_DF_WORD_SAMPLESTART +
numSamples * KHR_DF_WORD_SAMPLEWORDS)
<< KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE));
BDFD[KHR_DF_WORD_MODEL] =
((compModelMapping[compScheme] << KHR_DF_SHIFT_MODEL) |
(KHR_DF_PRIMARIES_BT709 << KHR_DF_SHIFT_PRIMARIES) | /* Assumed */
(KHR_DF_FLAG_ALPHA_STRAIGHT << KHR_DF_SHIFT_FLAGS));
if (suffix == s_SRGB) {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_SRGB << KHR_DF_SHIFT_TRANSFER;
} else {
BDFD[KHR_DF_WORD_TRANSFER] |= KHR_DF_TRANSFER_LINEAR << KHR_DF_SHIFT_TRANSFER;
}
BDFD[KHR_DF_WORD_TEXELBLOCKDIMENSION0] =
(bwidth - 1) | ((bheight - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION1) | ((bdepth - 1) << KHR_DF_SHIFT_TEXELBLOCKDIMENSION2);
/* bytesPlane0 = bytes, bytesPlane3..1 = 0 */
BDFD[KHR_DF_WORD_BYTESPLANE0] = compBytes[compScheme];
BDFD[KHR_DF_WORD_BYTESPLANE4] = 0; /* bytesPlane7..5 = 0 */
sample = BDFD + KHR_DF_WORD_SAMPLESTART;
channel = compFirstChannel[compScheme];
channel = setChannelFlags(channel, suffix);
sample[KHR_DF_SAMPLEWORD_BITOFFSET] =
(0 << KHR_DF_SAMPLESHIFT_BITOFFSET) |
((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |
(channel << KHR_DF_SAMPLESHIFT_CHANNELID);
sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;
switch (suffix) {
case s_UNORM:
case s_SRGB:
default:
upper.i = 0xFFFFFFFFU;
lower.i = 0U;
break;
case s_SNORM:
upper.i = 0x7FFFFFFF;
lower.i = ~upper.i;
break;
case s_USCALED:
case s_UINT:
upper.i = 1U;
lower.i = 0U;
break;
case s_SSCALED:
case s_SINT:
upper.i = 1U;
lower.i = ~0U;
break;
case s_SFLOAT:
upper.f = 1.0f;
lower.f = -1.0f;
break;
case s_UFLOAT:
upper.f = 1.0f;
lower.f = 0.0f;
break;
}
sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;
sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;
if (compSampleCount[compScheme] > 1) {
sample += KHR_DF_WORD_SAMPLEWORDS;
channel = compSecondChannel[compScheme];
channel = setChannelFlags(channel, suffix);
sample[KHR_DF_SAMPLEWORD_BITOFFSET] =
(compSecondChannelOffset[compScheme] << KHR_DF_SAMPLESHIFT_BITOFFSET) |
((compChannelBits[compScheme] - 1) << KHR_DF_SAMPLESHIFT_BITLENGTH) |
(channel << KHR_DF_SAMPLESHIFT_CHANNELID);
sample[KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL] = 0;
sample[KHR_DF_SAMPLEWORD_SAMPLELOWER] = lower.i;
sample[KHR_DF_SAMPLEWORD_SAMPLEUPPER] = upper.i;
}
return DFD;
}
/**
* @~English
* @brief Create a Data Format Descriptor for a depth-stencil format.
*
* @param depthBits The numeber of bits in the depth channel.
* @param stencilBits The numeber of bits in the stencil channel.
* @param sizeBytes The total byte size of the texel.
*
* @return A data format descriptor in malloc'd data. The caller is responsible
* for freeing the descriptor.
**/
uint32_t *createDFDDepthStencil(int depthBits,
int stencilBits,
int sizeBytes)
{
/* N.B. Little-endian is assumed. */
uint32_t *DFD = 0;
DFD = writeHeader((depthBits > 0) + (stencilBits > 0),
sizeBytes, s_UNORM, i_NON_COLOR);
if (depthBits == 32) {
writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH,
32, 0,
1, 1, s_SFLOAT);
} else if (depthBits > 0) {
writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_DEPTH,
depthBits, 0,
1, 1, s_UNORM);
}
if (stencilBits > 0) {
if (depthBits > 0) {
writeSample(DFD, 1, KHR_DF_CHANNEL_RGBSDA_STENCIL,
stencilBits, depthBits,
1, 1, s_UINT);
} else {
writeSample(DFD, 0, KHR_DF_CHANNEL_RGBSDA_STENCIL,
stencilBits, 0,
1, 1, s_UINT);
}
}
return DFD;
}

173
Source/dfd.h Normal file
View file

@ -0,0 +1,173 @@
/* -*- tab-width: 4; -*- */
/* vi: set sw=2 ts=4 expandtab: */
/* Copyright 2019-2020 The Khronos Group Inc.
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @~English
* @brief Header file defining the data format descriptor utilities API.
*/
/*
* Author: Andrew Garrard
*/
#ifndef _DFD_H_
#define _DFD_H_
#include <vulkan/vulkan.h>
#include <KHR/khr_df.h>
#ifdef __cplusplus
extern "C" {
#endif
/** Qualifier suffix to the format, in Vulkan terms. */
enum VkSuffix {
s_UNORM, /*!< Unsigned normalized format. */
s_SNORM, /*!< Signed normalized format. */
s_USCALED, /*!< Unsigned scaled format. */
s_SSCALED, /*!< Signed scaled format. */
s_UINT, /*!< Unsigned integer format. */
s_SINT, /*!< Signed integer format. */
s_SFLOAT, /*!< Signed float format. */
s_UFLOAT, /*!< Unsigned float format. */
s_SRGB /*!< sRGB normalized format. */
};
/** Compression scheme, in Vulkan terms. */
enum VkCompScheme {
c_BC1_RGB, /*!< BC1, aka DXT1, no alpha. */
c_BC1_RGBA, /*!< BC1, aka DXT1, punch-through alpha. */
c_BC2, /*!< BC2, aka DXT2 and DXT3. */
c_BC3, /*!< BC3, aka DXT4 and DXT5. */
c_BC4, /*!< BC4. */
c_BC5, /*!< BC5. */
c_BC6H, /*!< BC6h HDR format. */
c_BC7, /*!< BC7. */
c_ETC2_R8G8B8, /*!< ETC2 no alpha. */
c_ETC2_R8G8B8A1, /*!< ETC2 punch-through alpha. */
c_ETC2_R8G8B8A8, /*!< ETC2 independent alpha. */
c_EAC_R11, /*!< R11 ETC2 single-channel. */
c_EAC_R11G11, /*!< R11G11 ETC2 dual-channel. */
c_ASTC, /*!< ASTC. */
c_ETC1S, /*!< ETC1S. */
c_PVRTC, /*!< PVRTC(1). */
c_PVRTC2 /*!< PVRTC2. */
};
#if !defined(uint32_t)
typedef unsigned int uint32_t;
#endif
#if !defined(LIBKTX)
#include <vulkan/vulkan_core.h>
#else
#include "../vkformat_enum.h"
#endif
uint32_t* vk2dfd(enum VkFormat format);
/* Create a Data Format Descriptor for an unpacked format. */
uint32_t *createDFDUnpacked(int bigEndian, int numChannels, int bytes,
int redBlueSwap, enum VkSuffix suffix);
/* Create a Data Format Descriptor for a packed format. */
uint32_t *createDFDPacked(int bigEndian, int numChannels,
int bits[], int channels[],
enum VkSuffix suffix);
/* Create a Data Format Descriptor for a compressed format. */
uint32_t *createDFDCompressed(enum VkCompScheme compScheme,
int bwidth, int bheight, int bdepth,
enum VkSuffix suffix);
/* Create a Data Format Descriptor for a depth/stencil format. */
uint32_t *createDFDDepthStencil(int depthBits,
int stencilBits,
int sizeBytes);
/** @brief Result of interpreting the data format descriptor. */
enum InterpretDFDResult {
i_LITTLE_ENDIAN_FORMAT_BIT = 0, /*!< Confirmed little-endian (default for 8bpc). */
i_BIG_ENDIAN_FORMAT_BIT = 1, /*!< Confirmed big-endian. */
i_PACKED_FORMAT_BIT = 2, /*!< Packed format. */
i_SRGB_FORMAT_BIT = 4, /*!< sRGB transfer function. */
i_NORMALIZED_FORMAT_BIT = 8, /*!< Normalized (UNORM or SNORM). */
i_SIGNED_FORMAT_BIT = 16, /*!< Format is signed. */
i_FLOAT_FORMAT_BIT = 32, /*!< Format is floating point. */
i_UNSUPPORTED_ERROR_BIT = 64, /*!< Format not successfully interpreted. */
/** "NONTRIVIAL_ENDIANNESS" means not big-endian, not little-endian
* (a channel has bits that are not consecutive in either order). **/
i_UNSUPPORTED_NONTRIVIAL_ENDIANNESS = i_UNSUPPORTED_ERROR_BIT,
/** "MULTIPLE_SAMPLE_LOCATIONS" is an error because only single-sample
* texel blocks (with coordinates 0,0,0,0 for all samples) are supported. **/
i_UNSUPPORTED_MULTIPLE_SAMPLE_LOCATIONS = i_UNSUPPORTED_ERROR_BIT + 1,
/** "MULTIPLE_PLANES" is an error because only contiguous data is supported. */
i_UNSUPPORTED_MULTIPLE_PLANES = i_UNSUPPORTED_ERROR_BIT + 2,
/** Only channels R, G, B and A are supported. */
i_UNSUPPORTED_CHANNEL_TYPES = i_UNSUPPORTED_ERROR_BIT + 3,
/** Only channels with the same flags are supported
* (e.g. we don't support float red with integer green). */
i_UNSUPPORTED_MIXED_CHANNELS = i_UNSUPPORTED_ERROR_BIT + 4
};
/** @brief Interpretation of a channel from the data format descriptor. */
typedef struct _InterpretedDFDChannel {
uint32_t offset; /*!< Offset in bits for packed, bytes for unpacked. */
uint32_t size; /*!< Size in bits for packed, bytes for unpacked. */
} InterpretedDFDChannel;
/* Interpret a Data Format Descriptor. */
enum InterpretDFDResult interpretDFD(const uint32_t *DFD,
InterpretedDFDChannel *R,
InterpretedDFDChannel *G,
InterpretedDFDChannel *B,
InterpretedDFDChannel *A,
uint32_t *wordBytes);
/* Print a human-readable interpretation of a data format descriptor. */
void printDFD(uint32_t *DFD);
/* Get the number of components & component size from a DFD for an
* unpacked format.
*/
void
getDFDComponentInfoUnpacked(const uint32_t* DFD, uint32_t* numComponents,
uint32_t* componentByteLength);
/* Return the number of components described by a DFD. */
uint32_t getDFDNumComponents(const uint32_t* DFD);
/* Recreate and return the value of bytesPlane0 as it should be for the data
* post-inflation from variable-rate compression.
*/
void
recreateBytesPlane0FromSampleInfo(const uint32_t* DFD, uint32_t* bytesPlane0);
/** @brief Colourspace primaries information.
*
* Structure to store the 1931 CIE x,y chromaticities of the red, green, and blue
* display primaries and the reference white point of a colourspace.
*/
typedef struct _Primaries {
float Rx; /*!< Red x. */
float Ry; /*!< Red y. */
float Gx; /*!< Green x. */
float Gy; /*!< Green y. */
float Bx; /*!< Blue x. */
float By; /*!< Blue y. */
float Wx; /*!< White x. */
float Wy; /*!< White y. */
} Primaries;
khr_df_primaries_e findMapping(Primaries *p, float latitude);
#ifdef __cplusplus
}
#endif
#endif /* _DFD_H_ */

View file

@ -0,0 +1,557 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2019, Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#include "ispc_texcomp.h"
#include "kernel_ispc.h"
#include <memory.h> // memcpy
namespace ispc {
extern "C" {
extern int32_t ISPCIsa_ispc_sse4();
extern "C" void CompressBlocksBC1_ispc_sse4(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC3_ispc_sse4(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC4_ispc_sse4(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC5_ispc_sse4(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC6H_ispc_sse4(const rgba_surface* src, uint8_t* dst, bc6h_enc_settings* settings);
extern "C" void CompressBlocksBC7_ispc_sse4(const rgba_surface* src, uint8_t* dst, bc7_enc_settings* settings);
extern "C" void CompressBlocksETC1_ispc_sse4(const rgba_surface* src, uint8_t* dst, etc_enc_settings* settings);
extern "C" void CompressBlocksASTC_ispc_sse4(const rgba_surface* src, uint8_t* dst, astc_enc_settings* settings);
}
}
static bool isAmd = false;
void ISPCInit()
{
#if defined(_MSC_VER)
{
int CPUInfo[4];
__cpuid(CPUInfo, 0x80000001);
isAmd = (CPUInfo[2] & (1 << 6)) != 0;
}
#else
{
unsigned int eax = 0x80000001;
unsigned int ebx = 0;
unsigned int ecx = 0;
unsigned int edx = 0;
asm volatile("cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(eax));
isAmd = (ecx & (1 << 6)) != 0;
}
#endif
}
void GetProfile_ultrafast(bc7_enc_settings* settings)
{
settings->channels = 3;
// mode02
settings->mode_selection[0] = false;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode13
settings->mode_selection[1] = false;
settings->fastSkipTreshold_mode1 = 3;
settings->fastSkipTreshold_mode3 = 1;
settings->fastSkipTreshold_mode7 = 0;
settings->refineIterations[1] = 2;
settings->refineIterations[3] = 1;
// mode45
settings->mode_selection[2] = false;
settings->mode45_channel0 = 0;
settings->refineIterations_channel = 0;
settings->refineIterations[4] = 2;
settings->refineIterations[5] = 2;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 1;
}
void GetProfile_veryfast(bc7_enc_settings* settings)
{
settings->channels = 3;
// mode02
settings->mode_selection[0] = false;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode13
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 3;
settings->fastSkipTreshold_mode3 = 1;
settings->fastSkipTreshold_mode7 = 0;
settings->refineIterations[1] = 2;
settings->refineIterations[3] = 1;
// mode45
settings->mode_selection[2] = false;
settings->mode45_channel0 = 0;
settings->refineIterations_channel = 0;
settings->refineIterations[4] = 2;
settings->refineIterations[5] = 2;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 1;
}
void GetProfile_fast(bc7_enc_settings* settings)
{
settings->channels = 3;
// mode02
settings->mode_selection[0] = false;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode13
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 12;
settings->fastSkipTreshold_mode3 = 4;
settings->fastSkipTreshold_mode7 = 0;
settings->refineIterations[1] = 2;
settings->refineIterations[3] = 1;
// mode45
settings->mode_selection[2] = false;
settings->mode45_channel0 = 0;
settings->refineIterations_channel = 0;
settings->refineIterations[4] = 2;
settings->refineIterations[5] = 2;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2;
}
void GetProfile_basic(bc7_enc_settings* settings)
{
settings->channels = 3;
// mode02
settings->mode_selection[0] = true;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode13
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 8+4;
settings->fastSkipTreshold_mode3 = 8;
settings->fastSkipTreshold_mode7 = 0;
settings->refineIterations[1] = 2;
settings->refineIterations[3] = 2;
// mode45
settings->mode_selection[2] = true;
settings->mode45_channel0 = 0;
settings->refineIterations_channel = 2;
settings->refineIterations[4] = 2;
settings->refineIterations[5] = 2;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2;
}
void GetProfile_slow(bc7_enc_settings* settings)
{
settings->channels = 3;
int moreRefine = 2;
// mode02
settings->mode_selection[0] = true;
settings->skip_mode2 = false;
settings->refineIterations[0] = 2+moreRefine;
settings->refineIterations[2] = 2+moreRefine;
// mode13
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 64;
settings->fastSkipTreshold_mode3 = 64;
settings->fastSkipTreshold_mode7 = 0;
settings->refineIterations[1] = 2+moreRefine;
settings->refineIterations[3] = 2+moreRefine;
// mode45
settings->mode_selection[2] = true;
settings->mode45_channel0 = 0;
settings->refineIterations_channel = 2+moreRefine;
settings->refineIterations[4] = 2+moreRefine;
settings->refineIterations[5] = 2+moreRefine;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2+moreRefine;
}
void GetProfile_alpha_ultrafast(bc7_enc_settings* settings)
{
settings->channels = 4;
// mode02
settings->mode_selection[0] = false;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode137
settings->mode_selection[1] = false;
settings->fastSkipTreshold_mode1 = 0;
settings->fastSkipTreshold_mode3 = 0;
settings->fastSkipTreshold_mode7 = 4;
settings->refineIterations[1] = 1;
settings->refineIterations[3] = 1;
settings->refineIterations[7] = 2;
// mode45
settings->mode_selection[2] = true;
settings->mode45_channel0 = 3;
settings->refineIterations_channel = 1;
settings->refineIterations[4] = 1;
settings->refineIterations[5] = 1;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2;
}
void GetProfile_alpha_veryfast(bc7_enc_settings* settings)
{
settings->channels = 4;
// mode02
settings->mode_selection[0] = false;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode137
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 0;
settings->fastSkipTreshold_mode3 = 0;
settings->fastSkipTreshold_mode7 = 4;
settings->refineIterations[1] = 1;
settings->refineIterations[3] = 1;
settings->refineIterations[7] = 2;
// mode45
settings->mode_selection[2] = true;
settings->mode45_channel0 = 3;
settings->refineIterations_channel = 2;
settings->refineIterations[4] = 2;
settings->refineIterations[5] = 2;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2;
}
void GetProfile_alpha_fast(bc7_enc_settings* settings)
{
settings->channels = 4;
// mode02
settings->mode_selection[0] = false;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode137
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 4;
settings->fastSkipTreshold_mode3 = 4;
settings->fastSkipTreshold_mode7 = 8;
settings->refineIterations[1] = 1;
settings->refineIterations[3] = 1;
settings->refineIterations[7] = 2;
// mode45
settings->mode_selection[2] = true;
settings->mode45_channel0 = 3;
settings->refineIterations_channel = 2;
settings->refineIterations[4] = 2;
settings->refineIterations[5] = 2;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2;
}
void GetProfile_alpha_basic(bc7_enc_settings* settings)
{
settings->channels = 4;
// mode02
settings->mode_selection[0] = true;
settings->skip_mode2 = true;
settings->refineIterations[0] = 2;
settings->refineIterations[2] = 2;
// mode137
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 8+4;
settings->fastSkipTreshold_mode3 = 8;
settings->fastSkipTreshold_mode7 = 8;
settings->refineIterations[1] = 2;
settings->refineIterations[3] = 2;
settings->refineIterations[7] = 2;
// mode45
settings->mode_selection[2] = true;
settings->mode45_channel0 = 0;
settings->refineIterations_channel = 2;
settings->refineIterations[4] = 2;
settings->refineIterations[5] = 2;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2;
}
void GetProfile_alpha_slow(bc7_enc_settings* settings)
{
settings->channels = 4;
int moreRefine = 2;
// mode02
settings->mode_selection[0] = true;
settings->skip_mode2 = false;
settings->refineIterations[0] = 2+moreRefine;
settings->refineIterations[2] = 2+moreRefine;
// mode137
settings->mode_selection[1] = true;
settings->fastSkipTreshold_mode1 = 64;
settings->fastSkipTreshold_mode3 = 64;
settings->fastSkipTreshold_mode7 = 64;
settings->refineIterations[1] = 2+moreRefine;
settings->refineIterations[3] = 2+moreRefine;
settings->refineIterations[7] = 2+moreRefine;
// mode45
settings->mode_selection[2] = true;
settings->mode45_channel0 = 0;
settings->refineIterations_channel = 2+moreRefine;
settings->refineIterations[4] = 2+moreRefine;
settings->refineIterations[5] = 2+moreRefine;
// mode6
settings->mode_selection[3] = true;
settings->refineIterations[6] = 2+moreRefine;
}
void GetProfile_bc6h_veryfast(bc6h_enc_settings* settings)
{
settings->slow_mode = false;
settings->fast_mode = true;
settings->fastSkipTreshold = 0;
settings->refineIterations_1p = 0;
settings->refineIterations_2p = 0;
}
void GetProfile_bc6h_fast(bc6h_enc_settings* settings)
{
settings->slow_mode = false;
settings->fast_mode = true;
settings->fastSkipTreshold = 2;
settings->refineIterations_1p = 0;
settings->refineIterations_2p = 1;
}
void GetProfile_bc6h_basic(bc6h_enc_settings* settings)
{
settings->slow_mode = false;
settings->fast_mode = false;
settings->fastSkipTreshold = 4;
settings->refineIterations_1p = 2;
settings->refineIterations_2p = 2;
}
void GetProfile_bc6h_slow(bc6h_enc_settings* settings)
{
settings->slow_mode = true;
settings->fast_mode = false;
settings->fastSkipTreshold = 10;
settings->refineIterations_1p = 2;
settings->refineIterations_2p = 2;
}
void GetProfile_bc6h_veryslow(bc6h_enc_settings* settings)
{
settings->slow_mode = true;
settings->fast_mode = false;
settings->fastSkipTreshold = 32;
settings->refineIterations_1p = 2;
settings->refineIterations_2p = 2;
}
void GetProfile_etc_slow(etc_enc_settings* settings)
{
settings->fastSkipTreshold = 6;
}
void ReplicateBorders(rgba_surface* dst_slice, const rgba_surface* src_tex, int start_x, int start_y, int bpp)
{
int bytes_per_pixel = bpp >> 3;
bool aliasing = false;
if (&src_tex->ptr[src_tex->stride * start_y + bytes_per_pixel * start_x] == dst_slice->ptr) aliasing = true;
for (int y = 0; y < dst_slice->height; y++)
for (int x = 0; x < dst_slice->width; x++)
{
int xx = start_x + x;
int yy = start_y + y;
if (aliasing && xx < src_tex->width && yy < src_tex->height) continue;
if (xx >= src_tex->width) xx = src_tex->width - 1;
if (yy >= src_tex->height) yy = src_tex->height - 1;
void* dst = &dst_slice->ptr[dst_slice->stride * y + bytes_per_pixel * x];
void* src = &src_tex->ptr[src_tex->stride * yy + bytes_per_pixel * xx];
memcpy(dst, src, bytes_per_pixel);
}
}
void CompressBlocksBC1(const rgba_surface* src, uint8_t* dst)
{
if (isAmd) {
ispc::CompressBlocksBC1_ispc_sse4((ispc::rgba_surface*)src, dst);
} else {
ispc::CompressBlocksBC1_ispc((ispc::rgba_surface*)src, dst);
}
}
void CompressBlocksBC3(const rgba_surface* src, uint8_t* dst)
{
if (isAmd) {
ispc::CompressBlocksBC3_ispc_sse4((ispc::rgba_surface*)src, dst);
} else {
ispc::CompressBlocksBC3_ispc((ispc::rgba_surface*)src, dst);
}
}
void CompressBlocksBC4(const rgba_surface* src, uint8_t* dst)
{
if (isAmd) {
ispc::CompressBlocksBC4_ispc_sse4((ispc::rgba_surface*)src, dst);
} else {
ispc::CompressBlocksBC4_ispc((ispc::rgba_surface*)src, dst);
}
}
void CompressBlocksBC5(const rgba_surface* src, uint8_t* dst)
{
if (isAmd) {
ispc::CompressBlocksBC5_ispc_sse4((ispc::rgba_surface*)src, dst);
} else {
ispc::CompressBlocksBC5_ispc((ispc::rgba_surface*)src, dst);
}
}
void CompressBlocksBC7(const rgba_surface* src, uint8_t* dst, bc7_enc_settings* settings)
{
if (isAmd) {
ispc::CompressBlocksBC7_ispc_sse4((ispc::rgba_surface*)src, dst, (ispc::bc7_enc_settings*)settings);
} else {
ispc::CompressBlocksBC7_ispc((ispc::rgba_surface*)src, dst, (ispc::bc7_enc_settings*)settings);
}
}
void CompressBlocksBC6H(const rgba_surface* src, uint8_t* dst, bc6h_enc_settings* settings)
{
if (isAmd) {
ispc::CompressBlocksBC6H_ispc_sse4((ispc::rgba_surface*)src, dst, (ispc::bc6h_enc_settings*)settings);
} else {
ispc::CompressBlocksBC6H_ispc((ispc::rgba_surface*)src, dst, (ispc::bc6h_enc_settings*)settings);
}
}
void CompressBlocksETC1(const rgba_surface* src, uint8_t* dst, etc_enc_settings* settings)
{
if (isAmd) {
ispc::CompressBlocksETC1_ispc_sse4((ispc::rgba_surface*)src, dst, (ispc::etc_enc_settings*)settings);
} else {
ispc::CompressBlocksETC1_ispc((ispc::rgba_surface*)src, dst, (ispc::etc_enc_settings*)settings);
}
}
int ISPCIsa()
{
if (isAmd) {
return ispc::ISPCIsa_ispc_sse4();
} else {
return ispc::ISPCIsa_ispc();
}
}

View file

@ -0,0 +1,30 @@
LIBRARY ispc_texcomp
EXPORTS
CompressBlocksBC1
CompressBlocksBC3
CompressBlocksBC4
CompressBlocksBC5
CompressBlocksBC6H
CompressBlocksBC7
CompressBlocksETC1
CompressBlocksASTC
GetProfile_ultrafast
GetProfile_veryfast
GetProfile_fast
GetProfile_basic
GetProfile_slow
GetProfile_alpha_ultrafast
GetProfile_alpha_veryfast
GetProfile_alpha_fast
GetProfile_alpha_basic
GetProfile_alpha_slow
GetProfile_bc6h_veryfast
GetProfile_bc6h_fast
GetProfile_bc6h_basic
GetProfile_bc6h_slow
GetProfile_bc6h_veryslow
GetProfile_etc_slow
GetProfile_astc_fast
GetProfile_astc_alpha_fast
GetProfile_astc_alpha_slow
ReplicateBorders

View file

@ -0,0 +1,128 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2019, Intel Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#include <stdint.h>
struct rgba_surface
{
uint8_t* ptr;
int32_t width;
int32_t height;
int32_t stride; // in bytes
};
struct bc7_enc_settings
{
bool mode_selection[4];
int refineIterations[8];
bool skip_mode2;
int fastSkipTreshold_mode1;
int fastSkipTreshold_mode3;
int fastSkipTreshold_mode7;
int mode45_channel0;
int refineIterations_channel;
int channels;
};
struct bc6h_enc_settings
{
bool slow_mode;
bool fast_mode;
int refineIterations_1p;
int refineIterations_2p;
int fastSkipTreshold;
};
struct etc_enc_settings
{
int fastSkipTreshold;
};
struct astc_enc_settings
{
int block_width;
int block_height;
int channels;
int fastSkipTreshold;
int refineIterations;
};
// profiles for RGB data (alpha channel will be ignored)
extern "C" void GetProfile_ultrafast(bc7_enc_settings* settings);
extern "C" void GetProfile_veryfast(bc7_enc_settings* settings);
extern "C" void GetProfile_fast(bc7_enc_settings* settings);
extern "C" void GetProfile_basic(bc7_enc_settings* settings);
extern "C" void GetProfile_slow(bc7_enc_settings* settings);
// profiles for RGBA inputs
extern "C" void GetProfile_alpha_ultrafast(bc7_enc_settings* settings);
extern "C" void GetProfile_alpha_veryfast(bc7_enc_settings* settings);
extern "C" void GetProfile_alpha_fast(bc7_enc_settings* settings);
extern "C" void GetProfile_alpha_basic(bc7_enc_settings* settings);
extern "C" void GetProfile_alpha_slow(bc7_enc_settings* settings);
// profiles for BC6H (RGB HDR)
extern "C" void GetProfile_bc6h_veryfast(bc6h_enc_settings* settings);
extern "C" void GetProfile_bc6h_fast(bc6h_enc_settings* settings);
extern "C" void GetProfile_bc6h_basic(bc6h_enc_settings* settings);
extern "C" void GetProfile_bc6h_slow(bc6h_enc_settings* settings);
extern "C" void GetProfile_bc6h_veryslow(bc6h_enc_settings* settings);
// profiles for ETC
extern "C" void GetProfile_etc_slow(etc_enc_settings* settings);
// profiles for ASTC
extern "C" void GetProfile_astc_fast(astc_enc_settings* settings, int block_width, int block_height);
extern "C" void GetProfile_astc_alpha_fast(astc_enc_settings* settings, int block_width, int block_height);
extern "C" void GetProfile_astc_alpha_slow(astc_enc_settings* settings, int block_width, int block_height);
// helper function to replicate border pixels for the desired block sizes (bpp = 32 or 64)
extern "C" void ReplicateBorders(rgba_surface* dst_slice, const rgba_surface* src_tex, int x, int y, int bpp);
/*
Notes:
- input width and height need to be a multiple of block size
- LDR input is 32 bit/pixel (sRGB), HDR is 64 bit/pixel (half float)
- for BC4 input is 8bit/pixel (R8), for BC5 input is 16bit/pixel (RG8)
- dst buffer must be allocated with enough space for the compressed texture:
- 8 bytes/block for BC1/BC4/ETC1,
- 16 bytes/block for BC3/BC5/BC6H/BC7/ASTC
- the blocks are stored in raster scan order (natural CPU texture layout)
- use the GetProfile_* functions to select various speed/quality tradeoffs
- the RGB profiles are slightly faster as they ignore the alpha channel
*/
extern "C" void CompressBlocksBC1(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC3(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC4(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC5(const rgba_surface* src, uint8_t* dst);
extern "C" void CompressBlocksBC6H(const rgba_surface* src, uint8_t* dst, bc6h_enc_settings* settings);
extern "C" void CompressBlocksBC7(const rgba_surface* src, uint8_t* dst, bc7_enc_settings* settings);
extern "C" void CompressBlocksETC1(const rgba_surface* src, uint8_t* dst, etc_enc_settings* settings);
extern "C" void CompressBlocksASTC(const rgba_surface* src, uint8_t* dst, astc_enc_settings* settings);
extern "C" void ISPCInit();
extern "C" int ISPCIsa();

View file

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9B44F7B9-A9AF-45A4-8695-96792A18B052}</ProjectGuid>
<RootNamespace>ispc_texcomp</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ExecutablePath>$(SolutionDir);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ExecutablePath>$(SolutionDir);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ExecutablePath>$(SolutionDir);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ExecutablePath>$(SolutionDir);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
<ModuleDefinitionFile>ispc_texcomp.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ModuleDefinitionFile>ispc_texcomp.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>ispc_texcomp.def</ModuleDefinitionFile>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<ModuleDefinitionFile>ispc_texcomp.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ispc_texcomp.cpp" />
<ClCompile Include="ispc_texcomp_astc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ispc_texcomp.h" />
<ClInclude Include="kernel_astc_ispc.h" />
<ClInclude Include="kernel_astc_ispc_avx.h" />
<ClInclude Include="kernel_astc_ispc_avx2.h" />
<ClInclude Include="kernel_astc_ispc_sse2.h" />
<ClInclude Include="kernel_astc_ispc_sse4.h" />
<ClInclude Include="kernel_ispc.h" />
<ClInclude Include="kernel_ispc_avx.h" />
<ClInclude Include="kernel_ispc_avx2.h" />
<ClInclude Include="kernel_ispc_sse2.h" />
<ClInclude Include="kernel_ispc_sse4.h" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="kernel.ispc">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --arch=x86 --target=sse2,sse4,avx,avx2 --opt=fast-math</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --target=sse2,sse4,avx,avx2 --opt=fast-math</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)%(Filename).obj;$(TargetDir)%(Filename)_sse2.obj;$(TargetDir)%(Filename)_sse4.obj;$(TargetDir)%(Filename)_avx.obj;$(TargetDir)%(Filename)_avx2.obj;</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(TargetDir)%(Filename).obj;$(TargetDir)%(Filename)_sse2.obj;$(TargetDir)%(Filename)_sse4.obj;$(TargetDir)%(Filename)_avx.obj;$(TargetDir)%(Filename)_avx2.obj;</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --arch=x86 --target=sse2,sse4,avx,avx2 --opt=fast-math</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(TargetDir)%(Filename).obj;$(TargetDir)%(Filename)_sse2.obj;$(TargetDir)%(Filename)_sse4.obj;$(TargetDir)%(Filename)_avx.obj;$(TargetDir)%(Filename)_avx2.obj;</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --target=sse2,sse4,avx,avx2 --opt=fast-math</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(TargetDir)%(Filename).obj;$(TargetDir)%(Filename)_sse2.obj;$(TargetDir)%(Filename)_sse4.obj;$(TargetDir)%(Filename)_avx.obj;$(TargetDir)%(Filename)_avx2.obj;</Outputs>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="kernel_astc.ispc">
<FileType>Document</FileType>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --target=sse2,sse4,avx,avx2 --opt=fast-math</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(TargetDir)%(Filename).obj;$(TargetDir)%(Filename)_sse2.obj;$(TargetDir)%(Filename)_sse4.obj;$(TargetDir)%(Filename)_avx.obj;$(TargetDir)%(Filename)_avx2.obj;</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --target=avx --opt=fast-math</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(TargetDir)%(Filename).obj;</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --arch=x86 --target=sse2,sse4,avx,avx2 --opt=fast-math</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(TargetDir)%(Filename).obj;$(TargetDir)%(Filename)_sse2.obj;$(TargetDir)%(Filename)_sse4.obj;$(TargetDir)%(Filename)_avx.obj;$(TargetDir)%(Filename)_avx2.obj;</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(ProjectDir)..\ISPC\win\ispc.exe" -O2 "%(Filename).ispc" -o "$(TargetDir)%(Filename).obj" -h "$(ProjectDir)%(Filename)_ispc.h" --arch=x86 --target=avx --opt=fast-math</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)%(Filename).obj;</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
</Filter>
<Filter Include="Generated Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ispc_texcomp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ispc_texcomp_astc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="kernel.ispc">
<Filter>Source Files</Filter>
</CustomBuild>
<CustomBuild Include="kernel_astc.ispc">
<Filter>Source Files</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ispc_texcomp.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="kernel_astc_ispc_sse2.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_astc_ispc_sse4.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_ispc.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_ispc_avx.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_ispc_avx2.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_ispc_sse2.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_ispc_sse4.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_astc_ispc.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_astc_ispc_avx.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
<ClInclude Include="kernel_astc_ispc_avx2.h">
<Filter>Generated Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -0,0 +1,564 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016, Intel Corporation
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of
// the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "ispc_texcomp.h"
#include "kernel_astc_ispc.h"
#include <cassert>
#include <cstring>
#include <algorithm>
#include <vector>
#include <limits>
void GetProfile_astc_fast(astc_enc_settings* settings, int block_width, int block_height)
{
settings->block_width = block_width;
settings->block_height = block_height;
settings->channels = 3;
settings->fastSkipTreshold = 5;
settings->refineIterations = 2;
}
void GetProfile_astc_alpha_fast(astc_enc_settings* settings, int block_width, int block_height)
{
settings->block_width = block_width;
settings->block_height = block_height;
settings->channels = 4;
settings->fastSkipTreshold = 5;
settings->refineIterations = 2;
}
void GetProfile_astc_alpha_slow(astc_enc_settings* settings, int block_width, int block_height)
{
settings->block_width = block_width;
settings->block_height = block_height;
settings->channels = 4;
settings->fastSkipTreshold = 64;
settings->refineIterations = 2;
}
struct astc_block
{
int width;
int height;
uint8_t dual_plane;
int weight_range;
uint8_t weights[64];
int color_component_selector;
int partitions;
int partition_id;
int color_endpoint_pairs;
int channels;
int color_endpoint_modes[4];
int endpoint_range;
uint8_t endpoints[18];
};
bool can_store(int value, int bits)
{
if (value < 0) return false;
if (value >= 1 << bits) return false;
return true;
}
int pack_block_mode(astc_block* block)
{
int block_mode = 0;
int D = block->dual_plane;
int H = block->weight_range >= 6;
int DH = D * 2 + H;
int R = block->weight_range + 2 - ((H > 0) ? 6 : 0);
R = R / 2 + R % 2 * 4;
if (can_store(block->width - 4, 2) && can_store(block->height - 2, 2))
{
int B = block->width - 4;
int A = block->height - 2;
block_mode = (DH << 9) | (B << 7) | (A << 5) | ((R & 4) << 2) | (R & 3);
}
if (can_store(block->width - 8, 2) && can_store(block->height - 2, 2))
{
int B = block->width - 8;
int A = block->height - 2;
block_mode = (DH << 9) | (B << 7) | (A << 5) | ((R & 4) << 2) | 4 | (R & 3);
}
if (can_store(block->width - 2, 2) && can_store(block->height - 8, 2))
{
int A = block->width - 2;
int B = block->height - 8;
block_mode = (DH << 9) | (B << 7) | (A << 5) | ((R & 4) << 2) | 8 | (R & 3);
}
if (can_store(block->width - 2, 2) && can_store(block->height - 6, 1))
{
int A = block->width - 2;
int B = block->height - 6;
block_mode = (DH << 9) | (B << 7) | (A << 5) | ((R & 4) << 2) | 12 | (R & 3);
}
if (can_store(block->width - 2, 1) && can_store(block->height - 2, 2))
{
int B = block->width;
int A = block->height - 2;
block_mode = (DH << 9) | (B << 7) | (A << 5) | ((R & 4) << 2) | 12 | (R & 3);
}
if (DH == 0 && can_store(block->width - 6, 2) && can_store(block->height - 6, 2))
{
int A = block->width - 6;
int B = block->height - 6;
block_mode = (B << 9) | 256 | (A << 5) | (R << 2);
}
return block_mode;
}
int range_table[][3] =
{
//2^ 3^ 5^
{ 1, 0, 0 }, // 0..1
{ 0, 1, 0 }, // 0..2
{ 2, 0, 0 }, // 0..3
{ 0, 0, 1 }, // 0..4
{ 1, 1, 0 }, // 0..5
{ 3, 0, 0 }, // 0..7
{ 1, 0, 1 }, // 0..9
{ 2, 1, 0 }, // 0..11
{ 4, 0, 0 }, // 0..15
{ 2, 0, 1 }, // 0..19
{ 3, 1, 0 }, // 0..23
{ 5, 0, 0 }, // 0..31
{ 3, 0, 1 }, // 0..39
{ 4, 1, 0 }, // 0..47
{ 6, 0, 0 }, // 0..63
{ 4, 0, 1 }, // 0..79
{ 5, 1, 0 }, // 0..95
{ 7, 0, 0 }, // 0..127
{ 5, 0, 1 }, // 0..159
{ 6, 1, 0 }, // 0..191
{ 8, 0, 0 }, // 0..255
};
int get_levels(int range)
{
return (1 + 2 * range_table[range][1] + 4 * range_table[range][2]) << range_table[range][0];
}
int sequence_bits(int count, int range)
{
int bits = count * range_table[range][0];
bits += (count * range_table[range][1] * 8 + 4) / 5;
bits += (count * range_table[range][2] * 7 + 2) / 3;
return bits;
}
void set_bits(uint32_t data[4], int* pos, int bits, uint32_t value)
{
assert(bits <= 25);
uint32_t word = *(uint32_t*)(((uint8_t*)data) + *pos / 8);
uint32_t mask = (1 << bits) - 1;
word |= value << (*pos % 8);
*(uint32_t*)(((uint8_t*)data) + *pos / 8) = word;
*pos += bits;
}
uint32_t get_field(uint32_t input, int a, int b)
{
assert(a >= b);
return (input >> b) & ((1 << (a - b + 1)) - 1);
}
uint32_t get_bit(uint32_t input, int a)
{
return get_field(input, a, a);
}
void pack_five_trits(uint32_t data[4], int sequence[5], int* pos, int n)
{
int t[5];
int m[5];
for (int i = 0; i < 5; i++)
{
t[i] = sequence[i] >> n;
m[i] = sequence[i] - (t[i] << n);
}
int C;
if (t[1] == 2 && t[2] == 2)
{
C = 3 * 4 + t[0];
}
else if (t[2] == 2)
{
C = t[1] * 16 + t[0] * 4 + 3;
}
else
{
C = t[2] * 16 + t[1] * 4 + t[0];
}
int T;
if (t[3] == 2 && t[4] == 2)
{
T = get_field(C, 4, 2) * 32 + 7 * 4 + get_field(C, 1, 0);
}
else
{
T = get_field(C, 4, 0);
if (t[4] == 2)
{
T += t[3] * 128 + 3 * 32;
}
else
{
T += t[4] * 128 + t[3] * 32;
}
}
uint32_t pack1 = 0;
pack1 |= m[0];
pack1 |= get_field(T, 1, 0) << n;
pack1 |= m[1] << (2 + n);
uint32_t pack2 = 0;
pack2 |= get_field(T, 3, 2);
pack2 |= m[2] << 2;
pack2 |= get_field(T, 4, 4) << (2 + n);
pack2 |= m[3] << (3 + n);
pack2 |= get_field(T, 6, 5) << (3 + n * 2);
pack2 |= m[4] << (5 + n * 2);
pack2 |= get_field(T, 7, 7) << (5 + n * 3);
set_bits(data, pos, 2 + n * 2, pack1);
set_bits(data, pos, 6 + n * 3, pack2);
}
void pack_three_quint(uint32_t data[4], int sequence[3], int* pos, int n)
{
int q[3];
int m[3];
for (int i = 0; i < 3; i++)
{
q[i] = sequence[i] >> n;
m[i] = sequence[i] - (q[i] << n);
}
int Q;
if (q[0] == 4 && q[1] == 4)
{
Q = get_field(q[2], 1, 0) * 8 + 3 * 2 + get_bit(q[2], 2);
}
else
{
int C;
if (q[1] == 4)
{
C = (q[0] << 3) + 5;
}
else
{
C = (q[1] << 3) + q[0];
}
if (q[2] == 4)
{
Q = get_field(~C, 2, 1) * 32 + get_field(C, 4, 3) * 8 + 3 * 2 + get_bit(C, 0);
}
else
{
Q = q[2] * 32 + get_field(C, 4, 0);
}
}
uint32_t pack = 0;
pack |= m[0];
pack |= get_field(Q, 2, 0) << n;
pack |= m[1] << (3 + n);
pack |= get_field(Q, 4, 3) << (3 + n * 2);
pack |= m[2] << (5 + n * 2);
pack |= get_field(Q, 6, 5) << (5 + n * 3);
set_bits(data, pos, 7 + n * 3, pack);
}
void pack_integer_sequence(uint32_t output_data[4], uint8_t sequence[], int pos, int count, int range)
{
int n = range_table[range][0];
int bits = sequence_bits(count, range);
int pos0 = pos;
uint32_t data[5] = { 0 };
if (range_table[range][1] == 1)
{
for (int j = 0; j < (count + 4) / 5; j++)
{
int temp[5] = { 0 };
for (int i = 0; i < std::min(count - j * 5, 5); i++) temp[i] = sequence[j * 5 + i];
pack_five_trits(data, temp, &pos, n);
}
}
else if (range_table[range][2] == 1)
{
for (int j = 0; j < (count + 2) / 3; j++)
{
int temp[3] = { 0 };
for (int i = 0; i < std::min(count - j * 3, 3); i++) temp[i] = sequence[j * 3 + i];
pack_three_quint(data, temp, &pos, n);
}
}
else
{
for (int i = 0; i < count; i++)
{
set_bits(data, &pos, n, sequence[i]);
}
}
if (pos0 + bits < 96) data[3] = 0;
if (pos0 + bits < 64) data[2] = 0;
if (pos0 + bits < 32) data[1] = 0;
data[(pos0 + bits) / 32] &= (1 << ((pos0 + bits) % 32)) - 1;
for (int k = 0; k < 4; k++) output_data[k] |= data[k];
}
uint32_t reverse_bits_32(uint32_t input)
{
uint32_t t = input;
t = (t << 16) | (t >> 16);
t = ((t & 0x00FF00FF) << 8) | ((t & 0xFF00FF00) >> 8);
t = ((t & 0x0F0F0F0F) << 4) | ((t & 0xF0F0F0F0) >> 4);
t = ((t & 0x33333333) << 2) | ((t & 0xCCCCCCCC) >> 2);
t = ((t & 0x55555555) << 1) | ((t & 0xAAAAAAAA) >> 1);
return t;
}
void pack_block(uint32_t data[4], astc_block* block)
{
memset(data, 0, 16);
int pos = 0;
set_bits(data, &pos, 11, pack_block_mode(block));
int num_weights = block->width * block->height * (block->dual_plane ? 2 : 1);
int weight_bits = sequence_bits(num_weights, block->weight_range);
int extra_bits = 0;
assert(num_weights <= 64);
assert(24 <= weight_bits && weight_bits <= 96);
set_bits(data, &pos, 2, block->partitions - 1);
if (block->partitions > 1)
{
set_bits(data, &pos, 10, block->partition_id);
int min_cem = 16;
int max_cem = 0;
for (int j = 0; j < block->partitions; j++)
{
min_cem = std::min(min_cem, block->color_endpoint_modes[j]);
max_cem = std::max(max_cem, block->color_endpoint_modes[j]);
}
assert(max_cem / 4 <= min_cem / 4 + 1);
int CEM = block->color_endpoint_modes[0] << 2;
if (max_cem != min_cem)
{
CEM = std::min(3, min_cem / 4 + 1);
for (int j = 0; j < block->partitions; j++)
{
int c = block->color_endpoint_modes[j] / 4 - ((CEM & 3) - 1);
int m = block->color_endpoint_modes[j] % 4;
assert(c == 0 || c == 1);
CEM |= c << (2 + j);
CEM |= m << (2 + block->partitions + 2 * j);
}
extra_bits = 3 * block->partitions - 4;
int pos2 = 128 - weight_bits - extra_bits;
set_bits(data, &pos2, extra_bits, CEM >> 6);
}
set_bits(data, &pos, 6, CEM & 63);
}
else
{
set_bits(data, &pos, 4, block->color_endpoint_modes[0]);
}
if (block->dual_plane)
{
assert(block->partitions < 4);
extra_bits += 2;
int pos2 = 128 - weight_bits - extra_bits;
set_bits(data, &pos2, 2, block->color_component_selector);
}
int config_bits = pos + extra_bits;
int remaining_bits = 128 - config_bits - weight_bits;
int num_cem_pairs = 0;
for (int j = 0; j < block->partitions; j++) num_cem_pairs += 1 + block->color_endpoint_modes[j] / 4;
assert(num_cem_pairs <= 9);
int endpoint_range = -1;
for (int range = 20; range>0; range--)
{
int bits = sequence_bits(2 * num_cem_pairs, range);
if (bits <= remaining_bits)
{
endpoint_range = range;
break;
}
}
assert(endpoint_range >= 4);
assert(block->endpoint_range == endpoint_range);
pack_integer_sequence(data, block->endpoints, pos, 2 * num_cem_pairs, endpoint_range);
uint32_t rdata[4] = { 0, 0, 0, 0 };
pack_integer_sequence(rdata, block->weights, 0, num_weights, block->weight_range);
for (int i = 0; i < 4; i++) data[i] |= reverse_bits_32(rdata[3 - i]);
}
void atsc_rank(const rgba_surface* src, int xx, int yy, uint32_t* mode_buffer, astc_enc_settings* settings)
{
ispc::astc_rank_ispc((ispc::rgba_surface*)src, xx, yy, mode_buffer, (ispc::astc_enc_settings*)settings);
}
extern "C" void pack_block_c(uint32_t data[4], ispc::astc_block* block)
{
assert(sizeof(ispc::astc_block) == sizeof(astc_block));
pack_block(data, (astc_block*)block);
}
void setup_list_context(ispc::astc_enc_context* ctx, uint32_t packed_mode)
{
ctx->width = 2 + get_field(packed_mode, 15, 13); // 2..8 <= 2^3
ctx->height = 2 + get_field(packed_mode, 18, 16); // 2..8 <= 2^3
ctx->dual_plane = get_field(packed_mode, 19, 19); // 0 or 1
ctx->partitions = 1;
int color_endpoint_modes0 = get_field(packed_mode, 7, 6) * 2 + 6; // 6, 8, 10 or 12
ctx->color_endpoint_pairs = 1 + (color_endpoint_modes0 / 4);
ctx->channels = (color_endpoint_modes0 > 8) ? 4 : 3;
}
void astc_encode(const rgba_surface* src, float* block_scores, uint8_t* dst, uint64_t* list, astc_enc_settings* settings)
{
ispc::astc_enc_context list_context;
setup_list_context(&list_context, uint32_t(list[1] & 0xFFFFFFFF));
assert(sizeof(ispc::rgba_surface) == sizeof(rgba_surface));
assert(sizeof(ispc::astc_enc_settings) == sizeof(astc_enc_settings));
ispc::astc_encode_ispc((ispc::rgba_surface*)src, block_scores, dst, list, &list_context, (ispc::astc_enc_settings*)settings);
}
void CompressBlocksASTC(const rgba_surface* src, uint8_t* dst, astc_enc_settings* settings)
{
assert(src->height % settings->block_height == 0);
assert(src->width % settings->block_width == 0);
assert(settings->block_height <= 8);
assert(settings->block_width <= 8);
int tex_width = src->width / settings->block_width;
int programCount = ispc::get_programCount();
std::vector<float> block_scores(tex_width * src->height / settings->block_height);
for (int yy = 0; yy < src->height / settings->block_height; yy++)
for (int xx = 0; xx < tex_width; xx++)
{
block_scores[yy * tex_width + xx] = std::numeric_limits<float>::infinity();
}
int mode_list_size = 3334;
int list_size = programCount;
std::vector<uint64_t> mode_lists(list_size * mode_list_size);
std::vector<uint32_t> mode_buffer(programCount * settings->fastSkipTreshold);
for (int yy = 0; yy < src->height / settings->block_height; yy++)
for (int _x = 0; _x < (tex_width + programCount - 1) / programCount; _x++)
{
int xx = _x * programCount;
atsc_rank(src, xx, yy, mode_buffer.data(), settings);
for (int i = 0; i < settings->fastSkipTreshold; i++)
for (int k = 0; k < programCount; k++)
{
if (xx + k >= tex_width) continue;
uint32_t offset = (yy << 16) + (xx + k);
uint32_t mode = mode_buffer[programCount * i + k];
int mode_bin = mode >> 20;
uint64_t* mode_list = &mode_lists[list_size * mode_bin];
if (*mode_list < programCount - 1)
{
int index = int(mode_list[0] + 1);
mode_list[0] = index;
mode_list[index] = (uint64_t(offset) << 32) + mode;
}
else
{
mode_list[0] = (uint64_t(offset) << 32) + mode;
astc_encode(src, block_scores.data(), dst, mode_list, settings);
memset(mode_list, 0, list_size * sizeof(uint64_t));
}
}
}
for (int mode_bin = 0; mode_bin < mode_list_size; mode_bin++)
{
uint64_t* mode_list = &mode_lists[list_size * mode_bin];
if (mode_list[0] == 0) continue;
mode_list[0] = 0;
astc_encode(src, block_scores.data(), dst, mode_list, settings);
memset(mode_list, 0, list_size * sizeof(uint64_t));
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

26
Source/meson.build Normal file
View file

@ -0,0 +1,26 @@
sources = files([
'createdfd.cpp',
'HalfFloat.cpp',
'Main.cpp',
'stb_image_resize.cpp',
'stb_image.cpp',
'vk2dfd.cpp'
])
incdirs = include_directories([
])
dependencies = [
]
ispc_kernel = custom_target('ipsc_kernel', input: ['ispc_texcomp/kernel.ispc'], output: ['kernel_ispc.o', 'kernel_ispc_avx2.o', 'kernel_ispc_sse4.o', 'kernel_ispc.h'], command: ['ispc', '-O3', '--arch=x86_64', '--target=sse4,avx2', '--opt=fast-math', '--pic', '@INPUT@', '-h', '@OUTDIR@/kernel_ispc.h', '-o', '@OUTPUT0@'])
ispc_sources = [
ispc_kernel,
'ispc_texcomp/ispc_texcomp.cpp',
'ispc_texcomp/ispc_texcomp.h'
]
ispc_texcomp = static_library('ispc_texcomp', ispc_sources)
executable('TextureTaffy', sources, dependencies: dependencies, include_directories: incdirs, install: true, install_dir: '', install_tag: 'exe', link_with: ispc_texcomp)

2
Source/stb_image.cpp Normal file
View file

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

7987
Source/stb_image.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"

2634
Source/stb_image_resize.h Normal file

File diff suppressed because it is too large Load diff

33
Source/vk2dfd.cpp Normal file
View file

@ -0,0 +1,33 @@
/* -*- tab-width: 4; -*- */
/* vi: set sw=2 ts=4 expandtab: */
/* Copyright 2019-2020 Mark Callow
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @~English
* @brief Create a DFD for a VkFormat.
*/
#include "dfd.h"
/**
* @~English
* @brief Create a DFD matching a VkFormat.
*
* @param[in] format VkFormat for which to create a DFD.
*
* @return pointer to the created DFD or 0 if format not supported or
* unrecognized. Caller is responsible for freeing the created
* DFD.
*/
uint32_t * vk2dfd(enum VkFormat format)
{
switch (format) {
#include "vk2dfd.inl"
default: return 0;
}
}

294
Source/vk2dfd.inl Normal file
View file

@ -0,0 +1,294 @@
/* Copyright 2019-2020 The Khronos Group Inc. */
/* SPDX-License-Identifier: Apache-2.0 */
/***************************** Do not edit. *****************************
Automatically generated by makevk2dfd.pl.
*************************************************************************/
/* Vulkan combined depth & stencil formats are not included here
* because they do not exist outside a Vulkan device.
*/
case VK_FORMAT_R4G4_UNORM_PACK8: {
int channels[] = {1,0}; int bits[] = {4,4};
return createDFDPacked(0, 2, bits, channels, s_UNORM);
}
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: {
int channels[] = {3,2,1,0}; int bits[] = {4,4,4,4};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: {
int channels[] = {3,0,1,2}; int bits[] = {4,4,4,4};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_R5G6B5_UNORM_PACK16: {
int channels[] = {2,1,0}; int bits[] = {5,6,5};
return createDFDPacked(0, 3, bits, channels, s_UNORM);
}
case VK_FORMAT_B5G6R5_UNORM_PACK16: {
int channels[] = {0,1,2}; int bits[] = {5,6,5};
return createDFDPacked(0, 3, bits, channels, s_UNORM);
}
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: {
int channels[] = {3,2,1,0}; int bits[] = {1,5,5,5};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: {
int channels[] = {3,0,1,2}; int bits[] = {1,5,5,5};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: {
int channels[] = {2,1,0,3}; int bits[] = {5,5,5,1};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_R8_UNORM: return createDFDUnpacked(0, 1, 1, 0, s_UNORM);
case VK_FORMAT_R8_SNORM: return createDFDUnpacked(0, 1, 1, 0, s_SNORM);
case VK_FORMAT_R8_USCALED: return createDFDUnpacked(0, 1, 1, 0, s_USCALED);
case VK_FORMAT_R8_SSCALED: return createDFDUnpacked(0, 1, 1, 0, s_SSCALED);
case VK_FORMAT_R8_UINT: return createDFDUnpacked(0, 1, 1, 0, s_UINT);
case VK_FORMAT_R8_SINT: return createDFDUnpacked(0, 1, 1, 0, s_SINT);
case VK_FORMAT_R8_SRGB: return createDFDUnpacked(0, 1, 1, 0, s_SRGB);
case VK_FORMAT_R8G8_UNORM: return createDFDUnpacked(0, 2, 1, 0, s_UNORM);
case VK_FORMAT_R8G8_SNORM: return createDFDUnpacked(0, 2, 1, 0, s_SNORM);
case VK_FORMAT_R8G8_USCALED: return createDFDUnpacked(0, 2, 1, 0, s_USCALED);
case VK_FORMAT_R8G8_SSCALED: return createDFDUnpacked(0, 2, 1, 0, s_SSCALED);
case VK_FORMAT_R8G8_UINT: return createDFDUnpacked(0, 2, 1, 0, s_UINT);
case VK_FORMAT_R8G8_SINT: return createDFDUnpacked(0, 2, 1, 0, s_SINT);
case VK_FORMAT_R8G8_SRGB: return createDFDUnpacked(0, 2, 1, 0, s_SRGB);
case VK_FORMAT_R8G8B8_UNORM: return createDFDUnpacked(0, 3, 1, 0, s_UNORM);
case VK_FORMAT_R8G8B8_SNORM: return createDFDUnpacked(0, 3, 1, 0, s_SNORM);
case VK_FORMAT_R8G8B8_USCALED: return createDFDUnpacked(0, 3, 1, 0, s_USCALED);
case VK_FORMAT_R8G8B8_SSCALED: return createDFDUnpacked(0, 3, 1, 0, s_SSCALED);
case VK_FORMAT_R8G8B8_UINT: return createDFDUnpacked(0, 3, 1, 0, s_UINT);
case VK_FORMAT_R8G8B8_SINT: return createDFDUnpacked(0, 3, 1, 0, s_SINT);
case VK_FORMAT_R8G8B8_SRGB: return createDFDUnpacked(0, 3, 1, 0, s_SRGB);
case VK_FORMAT_B8G8R8_UNORM: return createDFDUnpacked(0, 3, 1, 1, s_UNORM);
case VK_FORMAT_B8G8R8_SNORM: return createDFDUnpacked(0, 3, 1, 1, s_SNORM);
case VK_FORMAT_B8G8R8_USCALED: return createDFDUnpacked(0, 3, 1, 1, s_USCALED);
case VK_FORMAT_B8G8R8_SSCALED: return createDFDUnpacked(0, 3, 1, 1, s_SSCALED);
case VK_FORMAT_B8G8R8_UINT: return createDFDUnpacked(0, 3, 1, 1, s_UINT);
case VK_FORMAT_B8G8R8_SINT: return createDFDUnpacked(0, 3, 1, 1, s_SINT);
case VK_FORMAT_B8G8R8_SRGB: return createDFDUnpacked(0, 3, 1, 1, s_SRGB);
case VK_FORMAT_R8G8B8A8_UNORM: return createDFDUnpacked(0, 4, 1, 0, s_UNORM);
case VK_FORMAT_R8G8B8A8_SNORM: return createDFDUnpacked(0, 4, 1, 0, s_SNORM);
case VK_FORMAT_R8G8B8A8_USCALED: return createDFDUnpacked(0, 4, 1, 0, s_USCALED);
case VK_FORMAT_R8G8B8A8_SSCALED: return createDFDUnpacked(0, 4, 1, 0, s_SSCALED);
case VK_FORMAT_R8G8B8A8_UINT: return createDFDUnpacked(0, 4, 1, 0, s_UINT);
case VK_FORMAT_R8G8B8A8_SINT: return createDFDUnpacked(0, 4, 1, 0, s_SINT);
case VK_FORMAT_R8G8B8A8_SRGB: return createDFDUnpacked(0, 4, 1, 0, s_SRGB);
case VK_FORMAT_B8G8R8A8_UNORM: return createDFDUnpacked(0, 4, 1, 1, s_UNORM);
case VK_FORMAT_B8G8R8A8_SNORM: return createDFDUnpacked(0, 4, 1, 1, s_SNORM);
case VK_FORMAT_B8G8R8A8_USCALED: return createDFDUnpacked(0, 4, 1, 1, s_USCALED);
case VK_FORMAT_B8G8R8A8_SSCALED: return createDFDUnpacked(0, 4, 1, 1, s_SSCALED);
case VK_FORMAT_B8G8R8A8_UINT: return createDFDUnpacked(0, 4, 1, 1, s_UINT);
case VK_FORMAT_B8G8R8A8_SINT: return createDFDUnpacked(0, 4, 1, 1, s_SINT);
case VK_FORMAT_B8G8R8A8_SRGB: return createDFDUnpacked(0, 4, 1, 1, s_SRGB);
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_A8B8G8R8_SNORM_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8};
return createDFDPacked(0, 4, bits, channels, s_SNORM);
}
case VK_FORMAT_A8B8G8R8_USCALED_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8};
return createDFDPacked(0, 4, bits, channels, s_USCALED);
}
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8};
return createDFDPacked(0, 4, bits, channels, s_SSCALED);
}
case VK_FORMAT_A8B8G8R8_UINT_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8};
return createDFDPacked(0, 4, bits, channels, s_UINT);
}
case VK_FORMAT_A8B8G8R8_SINT_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8};
return createDFDPacked(0, 4, bits, channels, s_SINT);
}
case VK_FORMAT_A8B8G8R8_SRGB_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {8,8,8,8};
return createDFDPacked(0, 4, bits, channels, s_SRGB);
}
case VK_FORMAT_A2R10G10B10_UNORM_PACK32: {
int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_A2R10G10B10_SNORM_PACK32: {
int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_SNORM);
}
case VK_FORMAT_A2R10G10B10_USCALED_PACK32: {
int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_USCALED);
}
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: {
int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_SSCALED);
}
case VK_FORMAT_A2R10G10B10_UINT_PACK32: {
int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_UINT);
}
case VK_FORMAT_A2R10G10B10_SINT_PACK32: {
int channels[] = {2,1,0,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_SINT);
}
case VK_FORMAT_A2B10G10R10_UNORM_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_A2B10G10R10_SNORM_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_SNORM);
}
case VK_FORMAT_A2B10G10R10_USCALED_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_USCALED);
}
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_SSCALED);
}
case VK_FORMAT_A2B10G10R10_UINT_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_UINT);
}
case VK_FORMAT_A2B10G10R10_SINT_PACK32: {
int channels[] = {0,1,2,3}; int bits[] = {10,10,10,2};
return createDFDPacked(0, 4, bits, channels, s_SINT);
}
case VK_FORMAT_R16_UNORM: return createDFDUnpacked(0, 1, 2, 0, s_UNORM);
case VK_FORMAT_R16_SNORM: return createDFDUnpacked(0, 1, 2, 0, s_SNORM);
case VK_FORMAT_R16_USCALED: return createDFDUnpacked(0, 1, 2, 0, s_USCALED);
case VK_FORMAT_R16_SSCALED: return createDFDUnpacked(0, 1, 2, 0, s_SSCALED);
case VK_FORMAT_R16_UINT: return createDFDUnpacked(0, 1, 2, 0, s_UINT);
case VK_FORMAT_R16_SINT: return createDFDUnpacked(0, 1, 2, 0, s_SINT);
case VK_FORMAT_R16_SFLOAT: return createDFDUnpacked(0, 1, 2, 0, s_SFLOAT);
case VK_FORMAT_R16G16_UNORM: return createDFDUnpacked(0, 2, 2, 0, s_UNORM);
case VK_FORMAT_R16G16_SNORM: return createDFDUnpacked(0, 2, 2, 0, s_SNORM);
case VK_FORMAT_R16G16_USCALED: return createDFDUnpacked(0, 2, 2, 0, s_USCALED);
case VK_FORMAT_R16G16_SSCALED: return createDFDUnpacked(0, 2, 2, 0, s_SSCALED);
case VK_FORMAT_R16G16_UINT: return createDFDUnpacked(0, 2, 2, 0, s_UINT);
case VK_FORMAT_R16G16_SINT: return createDFDUnpacked(0, 2, 2, 0, s_SINT);
case VK_FORMAT_R16G16_SFLOAT: return createDFDUnpacked(0, 2, 2, 0, s_SFLOAT);
case VK_FORMAT_R16G16B16_UNORM: return createDFDUnpacked(0, 3, 2, 0, s_UNORM);
case VK_FORMAT_R16G16B16_SNORM: return createDFDUnpacked(0, 3, 2, 0, s_SNORM);
case VK_FORMAT_R16G16B16_USCALED: return createDFDUnpacked(0, 3, 2, 0, s_USCALED);
case VK_FORMAT_R16G16B16_SSCALED: return createDFDUnpacked(0, 3, 2, 0, s_SSCALED);
case VK_FORMAT_R16G16B16_UINT: return createDFDUnpacked(0, 3, 2, 0, s_UINT);
case VK_FORMAT_R16G16B16_SINT: return createDFDUnpacked(0, 3, 2, 0, s_SINT);
case VK_FORMAT_R16G16B16_SFLOAT: return createDFDUnpacked(0, 3, 2, 0, s_SFLOAT);
case VK_FORMAT_R16G16B16A16_UNORM: return createDFDUnpacked(0, 4, 2, 0, s_UNORM);
case VK_FORMAT_R16G16B16A16_SNORM: return createDFDUnpacked(0, 4, 2, 0, s_SNORM);
case VK_FORMAT_R16G16B16A16_USCALED: return createDFDUnpacked(0, 4, 2, 0, s_USCALED);
case VK_FORMAT_R16G16B16A16_SSCALED: return createDFDUnpacked(0, 4, 2, 0, s_SSCALED);
case VK_FORMAT_R16G16B16A16_UINT: return createDFDUnpacked(0, 4, 2, 0, s_UINT);
case VK_FORMAT_R16G16B16A16_SINT: return createDFDUnpacked(0, 4, 2, 0, s_SINT);
case VK_FORMAT_R16G16B16A16_SFLOAT: return createDFDUnpacked(0, 4, 2, 0, s_SFLOAT);
case VK_FORMAT_R32_UINT: return createDFDUnpacked(0, 1, 4, 0, s_UINT);
case VK_FORMAT_R32_SINT: return createDFDUnpacked(0, 1, 4, 0, s_SINT);
case VK_FORMAT_R32_SFLOAT: return createDFDUnpacked(0, 1, 4, 0, s_SFLOAT);
case VK_FORMAT_R32G32_UINT: return createDFDUnpacked(0, 2, 4, 0, s_UINT);
case VK_FORMAT_R32G32_SINT: return createDFDUnpacked(0, 2, 4, 0, s_SINT);
case VK_FORMAT_R32G32_SFLOAT: return createDFDUnpacked(0, 2, 4, 0, s_SFLOAT);
case VK_FORMAT_R32G32B32_UINT: return createDFDUnpacked(0, 3, 4, 0, s_UINT);
case VK_FORMAT_R32G32B32_SINT: return createDFDUnpacked(0, 3, 4, 0, s_SINT);
case VK_FORMAT_R32G32B32_SFLOAT: return createDFDUnpacked(0, 3, 4, 0, s_SFLOAT);
case VK_FORMAT_R32G32B32A32_UINT: return createDFDUnpacked(0, 4, 4, 0, s_UINT);
case VK_FORMAT_R32G32B32A32_SINT: return createDFDUnpacked(0, 4, 4, 0, s_SINT);
case VK_FORMAT_R32G32B32A32_SFLOAT: return createDFDUnpacked(0, 4, 4, 0, s_SFLOAT);
case VK_FORMAT_R64_UINT: return createDFDUnpacked(0, 1, 8, 0, s_UINT);
case VK_FORMAT_R64_SINT: return createDFDUnpacked(0, 1, 8, 0, s_SINT);
case VK_FORMAT_R64_SFLOAT: return createDFDUnpacked(0, 1, 8, 0, s_SFLOAT);
case VK_FORMAT_R64G64_UINT: return createDFDUnpacked(0, 2, 8, 0, s_UINT);
case VK_FORMAT_R64G64_SINT: return createDFDUnpacked(0, 2, 8, 0, s_SINT);
case VK_FORMAT_R64G64_SFLOAT: return createDFDUnpacked(0, 2, 8, 0, s_SFLOAT);
case VK_FORMAT_R64G64B64_UINT: return createDFDUnpacked(0, 3, 8, 0, s_UINT);
case VK_FORMAT_R64G64B64_SINT: return createDFDUnpacked(0, 3, 8, 0, s_SINT);
case VK_FORMAT_R64G64B64_SFLOAT: return createDFDUnpacked(0, 3, 8, 0, s_SFLOAT);
case VK_FORMAT_R64G64B64A64_UINT: return createDFDUnpacked(0, 4, 8, 0, s_UINT);
case VK_FORMAT_R64G64B64A64_SINT: return createDFDUnpacked(0, 4, 8, 0, s_SINT);
case VK_FORMAT_R64G64B64A64_SFLOAT: return createDFDUnpacked(0, 4, 8, 0, s_SFLOAT);
case VK_FORMAT_B10G11R11_UFLOAT_PACK32: {
int channels[] = {0,1,2}; int bits[] = {11,11,10};
return createDFDPacked(0, 3, bits, channels, s_UFLOAT);
}
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: {
int bits[] = {0}; int channels[] = {0};
return createDFDPacked(0, 6, bits, channels, s_UFLOAT);
}
case VK_FORMAT_D16_UNORM: return createDFDDepthStencil(16,0,2);
case VK_FORMAT_X8_D24_UNORM_PACK32: return createDFDDepthStencil(24,0,4);
case VK_FORMAT_D32_SFLOAT: return createDFDDepthStencil(32,0,4);
case VK_FORMAT_S8_UINT: return createDFDDepthStencil(0,8,1);
case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_UNORM);
case VK_FORMAT_BC1_RGB_SRGB_BLOCK: return createDFDCompressed(c_BC1_RGB, 4, 4, 1, s_SRGB);
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return createDFDCompressed(c_BC1_RGBA, 4, 4, 1, s_UNORM);
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: return createDFDCompressed(c_BC1_RGBA, 4, 4, 1, s_SRGB);
case VK_FORMAT_BC2_UNORM_BLOCK: return createDFDCompressed(c_BC2, 4, 4, 1, s_UNORM);
case VK_FORMAT_BC2_SRGB_BLOCK: return createDFDCompressed(c_BC2, 4, 4, 1, s_SRGB);
case VK_FORMAT_BC3_UNORM_BLOCK: return createDFDCompressed(c_BC3, 4, 4, 1, s_UNORM);
case VK_FORMAT_BC3_SRGB_BLOCK: return createDFDCompressed(c_BC3, 4, 4, 1, s_SRGB);
case VK_FORMAT_BC4_UNORM_BLOCK: return createDFDCompressed(c_BC4, 4, 4, 1, s_UNORM);
case VK_FORMAT_BC4_SNORM_BLOCK: return createDFDCompressed(c_BC4, 4, 4, 1, s_SNORM);
case VK_FORMAT_BC5_UNORM_BLOCK: return createDFDCompressed(c_BC5, 4, 4, 1, s_UNORM);
case VK_FORMAT_BC5_SNORM_BLOCK: return createDFDCompressed(c_BC5, 4, 4, 1, s_SNORM);
case VK_FORMAT_BC6H_UFLOAT_BLOCK: return createDFDCompressed(c_BC6H, 4, 4, 1, s_UFLOAT);
case VK_FORMAT_BC6H_SFLOAT_BLOCK: return createDFDCompressed(c_BC6H, 4, 4, 1, s_SFLOAT);
case VK_FORMAT_BC7_UNORM_BLOCK: return createDFDCompressed(c_BC7, 4, 4, 1, s_UNORM);
case VK_FORMAT_BC7_SRGB_BLOCK: return createDFDCompressed(c_BC7, 4, 4, 1, s_SRGB);
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8, 4, 4, 1, s_UNORM);
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8, 4, 4, 1, s_SRGB);
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A1, 4, 4, 1, s_UNORM);
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A1, 4, 4, 1, s_SRGB);
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A8, 4, 4, 1, s_UNORM);
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return createDFDCompressed(c_ETC2_R8G8B8A8, 4, 4, 1, s_SRGB);
case VK_FORMAT_EAC_R11_UNORM_BLOCK: return createDFDCompressed(c_EAC_R11, 4, 4, 1, s_UNORM);
case VK_FORMAT_EAC_R11_SNORM_BLOCK: return createDFDCompressed(c_EAC_R11, 4, 4, 1, s_SNORM);
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: return createDFDCompressed(c_EAC_R11G11, 4, 4, 1, s_UNORM);
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: return createDFDCompressed(c_EAC_R11G11, 4, 4, 1, s_SNORM);
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 4, 4, 1, s_UNORM);
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 4, 4, 1, s_SRGB);
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 5, 4, 1, s_UNORM);
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 5, 4, 1, s_SRGB);
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 5, 5, 1, s_UNORM);
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 5, 5, 1, s_SRGB);
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 6, 5, 1, s_UNORM);
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 6, 5, 1, s_SRGB);
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 6, 6, 1, s_UNORM);
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 6, 6, 1, s_SRGB);
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 8, 5, 1, s_UNORM);
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 8, 5, 1, s_SRGB);
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 8, 6, 1, s_UNORM);
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 8, 6, 1, s_SRGB);
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 8, 8, 1, s_UNORM);
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 8, 8, 1, s_SRGB);
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 5, 1, s_UNORM);
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 5, 1, s_SRGB);
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 6, 1, s_UNORM);
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 6, 1, s_SRGB);
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 8, 1, s_UNORM);
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 8, 1, s_SRGB);
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 10, 10, 1, s_UNORM);
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 10, 10, 1, s_SRGB);
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 12, 10, 1, s_UNORM);
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 12, 10, 1, s_SRGB);
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_UNORM);
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: return createDFDCompressed(c_ASTC, 12, 12, 1, s_SRGB);
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8, 4, 1, s_UNORM);
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 4, 4, 1, s_UNORM);
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 8, 4, 1, s_UNORM);
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 4, 4, 1, s_UNORM);
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 8, 4, 1, s_SRGB);
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC, 4, 4, 1, s_SRGB);
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 8, 4, 1, s_SRGB);
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return createDFDCompressed(c_PVRTC2, 4, 4, 1, s_SRGB);
case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT: {
int channels[] = {2,1,0,3}; int bits[] = {4,4,4,4};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}
case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT: {
int channels[] = {0,1,2,3}; int bits[] = {4,4,4,4};
return createDFDPacked(0, 4, bits, channels, s_UNORM);
}

0
build/.keep Normal file
View file

3
meson.build Normal file
View file

@ -0,0 +1,3 @@
project('TextureTaffy', 'cpp')
subdir('Source')