Add ktx
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# Copyright 2024 The Khronos Group Inc.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
---
|
||||
# Use defaults from the Google style with the following exceptions:
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
IndentCaseLabels: false
|
||||
AccessModifierOffset: -2
|
||||
ColumnLimit: 100
|
||||
SortIncludes: false
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
IndentPPDirectives: BeforeHash
|
||||
...
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2019-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file basisu_sgd.h
|
||||
* @~English
|
||||
*
|
||||
* @brief Declare global data for Basis LZ supercompression with ETC1S.
|
||||
*
|
||||
* These functions are private and should not be used outside the library.
|
||||
*/
|
||||
|
||||
#ifndef _BASIS_SGD_H_
|
||||
#define _BASIS_SGD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// This must be the same value as cSliceDescFlagsFrameIsIFrame so we can just
|
||||
// invert the bit when passing back & forth. As FrameIsIFrame is within
|
||||
// a C namespace it can't easily be accessed from a c header.
|
||||
enum bu_image_flags__bits_e { ETC1S_P_FRAME = 0x02 };
|
||||
|
||||
typedef uint32_t buFlags;
|
||||
|
||||
typedef struct ktxBasisLzGlobalHeader {
|
||||
uint16_t endpointCount;
|
||||
uint16_t selectorCount;
|
||||
uint32_t endpointsByteLength;
|
||||
uint32_t selectorsByteLength;
|
||||
uint32_t tablesByteLength;
|
||||
uint32_t extendedByteLength;
|
||||
} ktxBasisLzGlobalHeader;
|
||||
|
||||
// This header is followed by imageCount "slice" descriptions.
|
||||
|
||||
// 1, or 2 slices per image (i.e. layer, face & slice).
|
||||
// These offsets are relative to start of a mip level as given by the
|
||||
// main levelIndex.
|
||||
typedef struct ktxBasisLzEtc1sImageDesc {
|
||||
buFlags imageFlags;
|
||||
uint32_t rgbSliceByteOffset;
|
||||
uint32_t rgbSliceByteLength;
|
||||
uint32_t alphaSliceByteOffset;
|
||||
uint32_t alphaSliceByteLength;
|
||||
} ktxBasisLzEtc1sImageDesc;
|
||||
|
||||
#define BGD_ETC1S_IMAGE_DESCS(bgd) \
|
||||
reinterpret_cast<ktxBasisLzEtc1sImageDesc*>(bgd + sizeof(ktxBasisLzGlobalHeader))
|
||||
|
||||
// The are followed in the global data by these ...
|
||||
// uint8_t[endpointsByteLength] endpointsData;
|
||||
// uint8_t[selectorsByteLength] selectorsData;
|
||||
// uint8_t[tablesByteLength] tablesData;
|
||||
|
||||
#define BGD_ENDPOINTS_ADDR(bgd, imageCount) \
|
||||
(bgd + sizeof(ktxBasisLzGlobalHeader) + sizeof(ktxBasisLzEtc1sImageDesc) * imageCount)
|
||||
|
||||
#define BGD_SELECTORS_ADDR(bgd, bgdh, imageCount) (BGD_ENDPOINTS_ADDR(bgd, imageCount) + bgdh.endpointsByteLength)
|
||||
|
||||
#define BGD_TABLES_ADDR(bgd, bgdh, imageCount) (BGD_SELECTORS_ADDR(bgd, bgdh, imageCount) + bgdh.selectorsByteLength)
|
||||
|
||||
#define BGD_EXTENDED_ADDR(bgd, bgdh, imageCount) (BGD_TABLES_ADDR(bgd, bgdh, imageCount) + bgdh.tablesByteLength)
|
||||
|
||||
// Just because this is a convenient place to put it for basis_{en,trans}code.
|
||||
enum alpha_content_e {
|
||||
eNone,
|
||||
eAlpha,
|
||||
eGreen
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BASIS_SGD_H_ */
|
||||
@@ -0,0 +1,744 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2019-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Functions for transcoding Basis Universal BasisLZ/ETC1S and UASTC textures.
|
||||
*
|
||||
* Two worlds collide here too. More uglyness!
|
||||
*
|
||||
* @author Mark Callow, github.com/MarkCallow
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <KHR/khr_df.h>
|
||||
|
||||
#include "dfdutils/dfd.h"
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
#include "texture2.h"
|
||||
#include "vkformat_enum.h"
|
||||
#include "vk_format.h"
|
||||
#include "basis_sgd.h"
|
||||
#include "basisu/transcoder/basisu_file_headers.h"
|
||||
#include "basisu/transcoder/basisu_transcoder.h"
|
||||
#include "basisu/transcoder/basisu_transcoder_internal.h"
|
||||
|
||||
#undef DECLARE_PRIVATE
|
||||
#undef DECLARE_PROTECTED
|
||||
#define DECLARE_PRIVATE(n,t2) ktxTexture2_private& n = *(t2->_private)
|
||||
#define DECLARE_PROTECTED(n,t2) ktxTexture_protected& n = *(t2->_protected)
|
||||
|
||||
using namespace basisu;
|
||||
using namespace basist;
|
||||
|
||||
inline bool isPow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); }
|
||||
|
||||
inline bool isPow2(uint64_t x) { return x && ((x & (x - 1U)) == 0U); }
|
||||
|
||||
KTX_error_code
|
||||
ktxTexture2_transcodeLzEtc1s(ktxTexture2* This,
|
||||
alpha_content_e alphaContent,
|
||||
ktxTexture2* prototype,
|
||||
ktx_transcode_fmt_e outputFormat,
|
||||
ktx_transcode_flags transcodeFlags);
|
||||
KTX_error_code
|
||||
ktxTexture2_transcodeUastc(ktxTexture2* This,
|
||||
alpha_content_e alphaContent,
|
||||
ktxTexture2* prototype,
|
||||
ktx_transcode_fmt_e outputFormat,
|
||||
ktx_transcode_flags transcodeFlags);
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @ingroup reader
|
||||
* @~English
|
||||
* @brief Transcode a KTX2 texture with BasisLZ/ETC1S or UASTC images.
|
||||
*
|
||||
* If the texture contains BasisLZ supercompressed images, Inflates them from
|
||||
* back to ETC1S then transcodes them to the specified block-compressed
|
||||
* format. If the texture contains UASTC images, inflates them, if they have been
|
||||
* supercompressed with zstd, then transcodes then to the specified format, The
|
||||
* transcoded images replace the original images and the texture's fields including
|
||||
* the DFD are modified to reflect the new format.
|
||||
*
|
||||
* These types of textures must be transcoded to a desired target
|
||||
* block-compressed format before they can be uploaded to a GPU via a
|
||||
* graphics API.
|
||||
*
|
||||
* The following block compressed transcode targets are available: @c KTX_TTF_ETC1_RGB,
|
||||
* @c KTX_TTF_ETC2_RGBA, @c KTX_TTF_BC1_RGB, @c KTX_TTF_BC3_RGBA,
|
||||
* @c KTX_TTF_BC4_R, @c KTX_TTF_BC5_RG, @c KTX_TTF_BC7_RGBA,
|
||||
* @c @c KTX_TTF_PVRTC1_4_RGB, @c KTX_TTF_PVRTC1_4_RGBA,
|
||||
* @c KTX_TTF_PVRTC2_4_RGB, @c KTX_TTF_PVRTC2_4_RGBA, @c KTX_TTF_ASTC_4x4_RGBA,
|
||||
* @c KTX_TTF_ETC2_EAC_R11, @c KTX_TTF_ETC2_EAC_RG11, @c KTX_TTF_ETC and
|
||||
* @c KTX_TTF_BC1_OR_3.
|
||||
*
|
||||
* @c KTX_TTF_ETC automatically selects between @c KTX_TTF_ETC1_RGB and
|
||||
* @c KTX_TTF_ETC2_RGBA according to whether an alpha channel is available. @c KTX_TTF_BC1_OR_3
|
||||
* does likewise between @c KTX_TTF_BC1_RGB and @c KTX_TTF_BC3_RGBA. Note that if
|
||||
* @c KTX_TTF_PVRTC1_4_RGBA or @c KTX_TTF_PVRTC2_4_RGBA is specified and there is no alpha
|
||||
* channel @c KTX_TTF_PVRTC1_4_RGB or @c KTX_TTF_PVRTC2_4_RGB respectively will be selected.
|
||||
*
|
||||
* Transcoding to ATC & FXT1 formats is not supported by libktx as there
|
||||
* are no equivalent Vulkan formats.
|
||||
*
|
||||
* The following uncompressed transcode targets are also available: @c KTX_TTF_RGBA32,
|
||||
* @c KTX_TTF_RGB565, KTX_TTF_BGR565 and KTX_TTF_RGBA4444.
|
||||
*
|
||||
* The following @p transcodeFlags are available.
|
||||
*
|
||||
* @sa ktxtexture2_CompressBasis().
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture2 object of interest.
|
||||
* @param[in] outputFormat a value from the ktx_texture_transcode_fmt_e enum
|
||||
* specifying the target format.
|
||||
* @param[in] transcodeFlags bitfield of flags modifying the transcode
|
||||
* operation. @sa ktx_texture_decode_flags_e.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_FILE_DATA_ERROR
|
||||
* Supercompression global data is corrupted.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The texture's format is not transcodable (not
|
||||
* ETC1S/BasisLZ or UASTC).
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Supercompression global data is missing, i.e.,
|
||||
* the texture object is invalid.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Image data is missing, i.e., the texture object
|
||||
* is invalid.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* @p outputFormat is PVRTC1 but the texture does
|
||||
* does not have power-of-two dimensions.
|
||||
* @exception KTX_INVALID_VALUE @p outputFormat is invalid.
|
||||
* @exception KTX_TRANSCODE_FAILED
|
||||
* Something went wrong during transcoding.
|
||||
* @exception KTX_UNSUPPORTED_FEATURE
|
||||
* KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 was requested
|
||||
* or the specified transcode target has not been
|
||||
* included in the library being used.
|
||||
* @exception KTX_OUT_OF_MEMORY Not enough memory to carry out transcoding.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_TranscodeBasis(ktxTexture2* This,
|
||||
ktx_transcode_fmt_e outputFormat,
|
||||
ktx_transcode_flags transcodeFlags)
|
||||
{
|
||||
uint32_t* BDB = This->pDfd + 1;
|
||||
khr_df_model_e colorModel = (khr_df_model_e)KHR_DFDVAL(BDB, MODEL);
|
||||
if (colorModel != KHR_DF_MODEL_UASTC
|
||||
// Constructor has checked color model matches BASIS_LZ.
|
||||
&& This->supercompressionScheme != KTX_SS_BASIS_LZ)
|
||||
{
|
||||
return KTX_INVALID_OPERATION; // Not in a transcodable format.
|
||||
}
|
||||
|
||||
DECLARE_PRIVATE(priv, This);
|
||||
if (This->supercompressionScheme == KTX_SS_BASIS_LZ) {
|
||||
if (!priv._supercompressionGlobalData || priv._sgdByteLength == 0)
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (transcodeFlags & KTX_TF_PVRTC_DECODE_TO_NEXT_POW2) {
|
||||
debug_printf("ktxTexture_TranscodeBasis: KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 currently unsupported\n");
|
||||
return KTX_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
|
||||
if (outputFormat == KTX_TTF_PVRTC1_4_RGB
|
||||
|| outputFormat == KTX_TTF_PVRTC1_4_RGBA) {
|
||||
if ((!isPow2(This->baseWidth)) || (!isPow2(This->baseHeight))) {
|
||||
debug_printf("ktxTexture_TranscodeBasis: PVRTC1 only supports power of 2 dimensions\n");
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
const bool srgb = (KHR_DFDVAL(BDB, TRANSFER) == KHR_DF_TRANSFER_SRGB);
|
||||
alpha_content_e alphaContent = eNone;
|
||||
if (colorModel == KHR_DF_MODEL_ETC1S) {
|
||||
if (KHR_DFDSAMPLECOUNT(BDB) == 2) {
|
||||
uint32_t channelId = KHR_DFDSVAL(BDB, 1, CHANNELID);
|
||||
if (channelId == KHR_DF_CHANNEL_ETC1S_AAA) {
|
||||
alphaContent = eAlpha;
|
||||
} else if (channelId == KHR_DF_CHANNEL_ETC1S_GGG){
|
||||
alphaContent = eGreen;
|
||||
} else {
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t channelId = KHR_DFDSVAL(BDB, 0, CHANNELID);
|
||||
if (channelId == KHR_DF_CHANNEL_UASTC_RGBA)
|
||||
alphaContent = eAlpha;
|
||||
else if (channelId == KHR_DF_CHANNEL_UASTC_RRRG)
|
||||
alphaContent = eGreen;
|
||||
}
|
||||
|
||||
VkFormat vkFormat;
|
||||
|
||||
// Do some format mapping.
|
||||
switch (outputFormat) {
|
||||
case KTX_TTF_BC1_OR_3:
|
||||
outputFormat = alphaContent != eNone ? KTX_TTF_BC3_RGBA
|
||||
: KTX_TTF_BC1_RGB;
|
||||
break;
|
||||
case KTX_TTF_ETC:
|
||||
outputFormat = alphaContent != eNone ? KTX_TTF_ETC2_RGBA
|
||||
: KTX_TTF_ETC1_RGB;
|
||||
break;
|
||||
case KTX_TTF_PVRTC1_4_RGBA:
|
||||
// This transcoder does not write opaque alpha blocks.
|
||||
outputFormat = alphaContent != eNone ? KTX_TTF_PVRTC1_4_RGBA
|
||||
: KTX_TTF_PVRTC1_4_RGB;
|
||||
break;
|
||||
case KTX_TTF_PVRTC2_4_RGBA:
|
||||
// This transcoder does not write opaque alpha blocks.
|
||||
outputFormat = alphaContent != eNone ? KTX_TTF_PVRTC2_4_RGBA
|
||||
: KTX_TTF_PVRTC2_4_RGB;
|
||||
break;
|
||||
default:
|
||||
/*NOP*/;
|
||||
}
|
||||
|
||||
switch (outputFormat) {
|
||||
case KTX_TTF_ETC1_RGB:
|
||||
vkFormat = srgb ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK
|
||||
: VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_ETC2_RGBA:
|
||||
vkFormat = srgb ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK
|
||||
: VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_ETC2_EAC_R11:
|
||||
vkFormat = VK_FORMAT_EAC_R11_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_ETC2_EAC_RG11:
|
||||
vkFormat = VK_FORMAT_EAC_R11G11_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_BC1_RGB:
|
||||
// Transcoding doesn't support BC1 alpha.
|
||||
vkFormat = srgb ? VK_FORMAT_BC1_RGB_SRGB_BLOCK
|
||||
: VK_FORMAT_BC1_RGB_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_BC3_RGBA:
|
||||
vkFormat = srgb ? VK_FORMAT_BC3_SRGB_BLOCK
|
||||
: VK_FORMAT_BC3_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_BC4_R:
|
||||
vkFormat = VK_FORMAT_BC4_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_BC5_RG:
|
||||
vkFormat = VK_FORMAT_BC5_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_PVRTC1_4_RGB:
|
||||
case KTX_TTF_PVRTC1_4_RGBA:
|
||||
vkFormat = srgb ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG
|
||||
: VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
|
||||
break;
|
||||
case KTX_TTF_PVRTC2_4_RGB:
|
||||
case KTX_TTF_PVRTC2_4_RGBA:
|
||||
vkFormat = srgb ? VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG
|
||||
: VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG;
|
||||
break;
|
||||
case KTX_TTF_BC7_RGBA:
|
||||
vkFormat = srgb ? VK_FORMAT_BC7_SRGB_BLOCK
|
||||
: VK_FORMAT_BC7_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_ASTC_4x4_RGBA:
|
||||
vkFormat = srgb ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK
|
||||
: VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
|
||||
break;
|
||||
case KTX_TTF_RGB565:
|
||||
vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||
break;
|
||||
case KTX_TTF_BGR565:
|
||||
vkFormat = VK_FORMAT_B5G6R5_UNORM_PACK16;
|
||||
break;
|
||||
case KTX_TTF_RGBA4444:
|
||||
vkFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
break;
|
||||
case KTX_TTF_RGBA32:
|
||||
vkFormat = srgb ? VK_FORMAT_R8G8B8A8_SRGB
|
||||
: VK_FORMAT_R8G8B8A8_UNORM;
|
||||
break;
|
||||
default:
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
basis_tex_format textureFormat;
|
||||
if (colorModel == KHR_DF_MODEL_UASTC)
|
||||
textureFormat = basis_tex_format::cUASTC4x4;
|
||||
else
|
||||
textureFormat = basis_tex_format::cETC1S;
|
||||
|
||||
if (!basis_is_format_supported((transcoder_texture_format)outputFormat,
|
||||
textureFormat)) {
|
||||
return KTX_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
|
||||
|
||||
// Create a prototype texture to use for calculating sizes in the target
|
||||
// format and, as useful side effects, provide us with a properly sized
|
||||
// data allocation and the DFD for the target format.
|
||||
ktxTextureCreateInfo createInfo;
|
||||
createInfo.glInternalformat = 0;
|
||||
createInfo.vkFormat = vkFormat;
|
||||
createInfo.baseWidth = This->baseWidth;
|
||||
createInfo.baseHeight = This->baseHeight;
|
||||
createInfo.baseDepth = This->baseDepth;
|
||||
createInfo.generateMipmaps = This->generateMipmaps;
|
||||
createInfo.isArray = This->isArray;
|
||||
createInfo.numDimensions = This->numDimensions;
|
||||
createInfo.numFaces = This->numFaces;
|
||||
createInfo.numLayers = This->numLayers;
|
||||
createInfo.numLevels = This->numLevels;
|
||||
createInfo.pDfd = nullptr;
|
||||
|
||||
KTX_error_code result;
|
||||
ktxTexture2* prototype;
|
||||
result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
||||
&prototype);
|
||||
|
||||
if (result != KTX_SUCCESS) {
|
||||
assert(result == KTX_OUT_OF_MEMORY); // The only run time error
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!This->pData) {
|
||||
if (ktxTexture_isActiveStream((ktxTexture*)This)) {
|
||||
// Load pending. Complete it.
|
||||
result = ktxTexture2_LoadImageData(This, NULL, 0);
|
||||
if (result != KTX_SUCCESS)
|
||||
{
|
||||
ktxTexture2_Destroy(prototype);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
// No data to transcode.
|
||||
ktxTexture2_Destroy(prototype);
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
// Transcoder global initialization. Requires ~9 milliseconds when compiled
|
||||
// and executed natively on a Core i7 2.2 GHz. If this is too slow, the
|
||||
// tables it computes can easily be moved to be compiled in.
|
||||
static bool transcoderInitialized;
|
||||
if (!transcoderInitialized) {
|
||||
basisu_transcoder_init();
|
||||
transcoderInitialized = true;
|
||||
}
|
||||
|
||||
if (textureFormat == basis_tex_format::cETC1S) {
|
||||
result = ktxTexture2_transcodeLzEtc1s(This, alphaContent,
|
||||
prototype, outputFormat,
|
||||
transcodeFlags);
|
||||
} else {
|
||||
result = ktxTexture2_transcodeUastc(This, alphaContent,
|
||||
prototype, outputFormat,
|
||||
transcodeFlags);
|
||||
}
|
||||
|
||||
if (result == KTX_SUCCESS) {
|
||||
// Fix up the current texture
|
||||
DECLARE_PROTECTED(thisPrtctd, This);
|
||||
DECLARE_PRIVATE(protoPriv, prototype);
|
||||
DECLARE_PROTECTED(protoPrtctd, prototype);
|
||||
memcpy(&thisPrtctd._formatSize, &protoPrtctd._formatSize,
|
||||
sizeof(ktxFormatSize));
|
||||
This->vkFormat = vkFormat;
|
||||
This->isCompressed = prototype->isCompressed;
|
||||
This->supercompressionScheme = KTX_SS_NONE;
|
||||
priv._requiredLevelAlignment = protoPriv._requiredLevelAlignment;
|
||||
// Copy the levelIndex from the prototype to This.
|
||||
memcpy(priv._levelIndex, protoPriv._levelIndex,
|
||||
This->numLevels * sizeof(ktxLevelIndexEntry));
|
||||
// Move the DFD and data from the prototype to This.
|
||||
free(This->pDfd);
|
||||
This->pDfd = prototype->pDfd;
|
||||
prototype->pDfd = 0;
|
||||
free(This->pData);
|
||||
This->pData = prototype->pData;
|
||||
This->dataSize = prototype->dataSize;
|
||||
prototype->pData = 0;
|
||||
prototype->dataSize = 0;
|
||||
// Free SGD data
|
||||
This->_private->_sgdByteLength = 0;
|
||||
if (This->_private->_supercompressionGlobalData) {
|
||||
free(This->_private->_supercompressionGlobalData);
|
||||
This->_private->_supercompressionGlobalData = NULL;
|
||||
}
|
||||
}
|
||||
ktxTexture2_Destroy(prototype);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2 @private
|
||||
* @ingroup reader
|
||||
* @~English
|
||||
* @brief Transcode a KTX2 texture with BasisLZ supercompressed ETC1S images.
|
||||
*
|
||||
* Inflates the images from BasisLZ supercompression back to ETC1S
|
||||
* then transcodes them to the specified block-compressed format. The
|
||||
* transcoded images replace the original images and the texture's fields
|
||||
* including the DFD are modified to reflect the new format.
|
||||
*
|
||||
* BasisLZ supercompressed textures must be transcoded to a desired target
|
||||
* block-compressed format before they can be uploaded to a GPU via a graphics
|
||||
* API.
|
||||
*
|
||||
* The following block compressed transcode targets are available: @c KTX_TTF_ETC1_RGB,
|
||||
* @c KTX_TTF_ETC2_RGBA, @c KTX_TTF_BC1_RGB, @c KTX_TTF_BC3_RGBA,
|
||||
* @c KTX_TTF_BC4_R, @c KTX_TTF_BC5_RG, @c KTX_TTF_BC7_RGBA,
|
||||
* @c @c KTX_TTF_PVRTC1_4_RGB, @c KTX_TTF_PVRTC1_4_RGBA,
|
||||
* @c KTX_TTF_PVRTC2_4_RGB, @c KTX_TTF_PVRTC2_4_RGBA, @c KTX_TTF_ASTC_4x4_RGBA,
|
||||
* @c KTX_TTF_ETC2_EAC_R11, @c KTX_TTF_ETC2_EAC_RG11, @c KTX_TTF_ETC and
|
||||
* @c KTX_TTF_BC1_OR_3.
|
||||
*
|
||||
* @c KTX_TTF_ETC automatically selects between @c KTX_TTF_ETC1_RGB and
|
||||
* @c KTX_TTF_ETC2_RGBA according to whether an alpha channel is available. @c KTX_TTF_BC1_OR_3
|
||||
* does likewise between @c KTX_TTF_BC1_RGB and @c KTX_TTF_BC3_RGBA. Note that if
|
||||
* @c KTX_TTF_PVRTC1_4_RGBA or @c KTX_TTF_PVRTC2_4_RGBA is specified and there is no alpha
|
||||
* channel @c KTX_TTF_PVRTC1_4_RGB or @c KTX_TTF_PVRTC2_4_RGB respectively will be selected.
|
||||
*
|
||||
* ATC & FXT1 formats are not supported by KTX2 & libktx as there are no equivalent Vulkan formats.
|
||||
*
|
||||
* The following uncompressed transcode targets are also available: @c KTX_TTF_RGBA32,
|
||||
* @c KTX_TTF_RGB565, KTX_TTF_BGR565 and KTX_TTF_RGBA4444.
|
||||
*
|
||||
* The following @p transcodeFlags are available.
|
||||
*
|
||||
* @sa ktxtexture2_CompressBasis().
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture2 object of interest.
|
||||
* @param[in] outputFormat a value from the ktx_texture_transcode_fmt_e enum
|
||||
* specifying the target format.
|
||||
* @param[in] transcodeFlags bitfield of flags modifying the transcode
|
||||
* operation. @sa ktx_texture_decode_flags_e.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_FILE_DATA_ERROR
|
||||
* Supercompression global data is corrupted.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The texture's format is not transcodable (not
|
||||
* ETC1S/BasisLZ or UASTC).
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Supercompression global data is missing, i.e.,
|
||||
* the texture object is invalid.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Image data is missing, i.e., the texture object
|
||||
* is invalid.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* @p outputFormat is PVRTC1 but the texture does
|
||||
* does not have power-of-two dimensions.
|
||||
* @exception KTX_INVALID_VALUE @p outputFormat is invalid.
|
||||
* @exception KTX_TRANSCODE_FAILED
|
||||
* Something went wrong during transcoding. The
|
||||
* texture object will be corrupted.
|
||||
* @exception KTX_UNSUPPORTED_FEATURE
|
||||
* KTX_TF_PVRTC_DECODE_TO_NEXT_POW2 was requested
|
||||
* or the specified transcode target has not been
|
||||
* included in the library being used.
|
||||
* @exception KTX_OUT_OF_MEMORY Not enough memory to carry out transcoding.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_transcodeLzEtc1s(ktxTexture2* This,
|
||||
alpha_content_e alphaContent,
|
||||
ktxTexture2* prototype,
|
||||
ktx_transcode_fmt_e outputFormat,
|
||||
ktx_transcode_flags transcodeFlags)
|
||||
{
|
||||
DECLARE_PRIVATE(priv, This);
|
||||
DECLARE_PRIVATE(protoPriv, prototype);
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
|
||||
assert(This->supercompressionScheme == KTX_SS_BASIS_LZ);
|
||||
|
||||
uint8_t* bgd = priv._supercompressionGlobalData;
|
||||
ktxBasisLzGlobalHeader& bgdh = *reinterpret_cast<ktxBasisLzGlobalHeader*>(bgd);
|
||||
if (!(bgdh.endpointsByteLength && bgdh.selectorsByteLength && bgdh.tablesByteLength)) {
|
||||
debug_printf("ktxTexture_TranscodeBasis: missing endpoints, selectors or tables");
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
// Compute some helpful numbers.
|
||||
//
|
||||
// firstImages contains the indices of the first images for each level to
|
||||
// ease finding the correct slice description when iterating from smallest
|
||||
// level to largest or when randomly accessing them (t.b.c). The last array
|
||||
// entry contains the total number of images, for calculating the offsets
|
||||
// of the endpoints, etc.
|
||||
uint32_t* firstImages = new uint32_t[This->numLevels+1];
|
||||
|
||||
// Temporary invariant value
|
||||
uint32_t layersFaces = This->numLayers * This->numFaces;
|
||||
firstImages[0] = 0;
|
||||
for (uint32_t level = 1; level <= This->numLevels; level++) {
|
||||
// NOTA BENE: numFaces * depth is only reasonable because they can't
|
||||
// both be > 1. I.e there are no 3d cubemaps.
|
||||
firstImages[level] = firstImages[level - 1]
|
||||
+ layersFaces * MAX(This->baseDepth >> (level - 1), 1);
|
||||
}
|
||||
uint32_t& imageCount = firstImages[This->numLevels];
|
||||
|
||||
if (BGD_TABLES_ADDR(0, bgdh, imageCount) + bgdh.tablesByteLength > priv._sgdByteLength) {
|
||||
// Compiler will not allow `goto cleanup;` because "jump bypasses variable initialization."
|
||||
// The static initializations below this and before the loop are presumably the issue
|
||||
// as the compiler is,presumably, inserting code to destruct those at the end of the
|
||||
// function.
|
||||
delete[] firstImages;
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
// FIXME: Do more validation.
|
||||
|
||||
// Prepare low-level transcoder for transcoding slices.
|
||||
basist::basisu_lowlevel_etc1s_transcoder bit;
|
||||
|
||||
// basisu_transcoder_state is used to find the previous frame when
|
||||
// decoding a video P-Frame. It tracks the previous frame for each mip
|
||||
// level. For cube map array textures we need to find the previous frame
|
||||
// for each face so we a state per face. Although providing this is only
|
||||
// needed for video, it is easier to always pass our own.
|
||||
std::vector<basisu_transcoder_state> xcoderStates;
|
||||
xcoderStates.resize(This->isVideo ? This->numFaces : 1);
|
||||
|
||||
bit.decode_palettes(bgdh.endpointCount, BGD_ENDPOINTS_ADDR(bgd, imageCount),
|
||||
bgdh.endpointsByteLength,
|
||||
bgdh.selectorCount, BGD_SELECTORS_ADDR(bgd, bgdh, imageCount),
|
||||
bgdh.selectorsByteLength);
|
||||
|
||||
bit.decode_tables(BGD_TABLES_ADDR(bgd, bgdh, imageCount),
|
||||
bgdh.tablesByteLength);
|
||||
|
||||
// Find matching VkFormat and calculate output sizes.
|
||||
|
||||
const bool isVideo = This->isVideo;
|
||||
|
||||
ktx_uint8_t* pXcodedData = prototype->pData;
|
||||
// Inconveniently, the output buffer size parameter of transcode_image
|
||||
// has to be in pixels for uncompressed output and in blocks for
|
||||
// compressed output. The only reason for humouring the API is so
|
||||
// its buffer size tests provide a real check. An alternative is to
|
||||
// always provide the size in bytes which will always pass.
|
||||
ktx_uint32_t outputBlockByteLength
|
||||
= prototype->_protected->_formatSize.blockSizeInBits / 8;
|
||||
ktx_size_t xcodedDataLength
|
||||
= prototype->dataSize / outputBlockByteLength;
|
||||
ktxLevelIndexEntry* protoLevelIndex;
|
||||
uint64_t levelOffsetWrite;
|
||||
const ktxBasisLzEtc1sImageDesc* imageDescs = BGD_ETC1S_IMAGE_DESCS(bgd);
|
||||
|
||||
// Finally we're ready to transcode the slices.
|
||||
|
||||
// FIXME: Iframe flag needs to be queryable by the application. In Basis
|
||||
// the app can query file_info and image_info from the transcoder which
|
||||
// returns a structure with lots of info about the image.
|
||||
|
||||
protoLevelIndex = protoPriv._levelIndex;
|
||||
levelOffsetWrite = 0;
|
||||
for (int32_t level = This->numLevels - 1; level >= 0; level--) {
|
||||
uint64_t levelOffset = ktxTexture2_levelDataOffset(This, level);
|
||||
uint64_t writeOffset = levelOffsetWrite;
|
||||
uint64_t writeOffsetBlocks = levelOffsetWrite / outputBlockByteLength;
|
||||
uint32_t levelWidth = MAX(1, This->baseWidth >> level);
|
||||
uint32_t levelHeight = MAX(1, This->baseHeight >> level);
|
||||
// ETC1S texel block dimensions
|
||||
const uint32_t bw = 4, bh = 4;
|
||||
uint32_t levelBlocksX = (levelWidth + (bw - 1)) / bw;
|
||||
uint32_t levelBlocksY = (levelHeight + (bh - 1)) / bh;
|
||||
uint32_t depth = MAX(1, This->baseDepth >> level);
|
||||
//uint32_t faceSlices = This->numFaces == 1 ? depth : This->numFaces;
|
||||
uint32_t faceSlices = This->numFaces * depth;
|
||||
uint32_t numImages = This->numLayers * faceSlices;
|
||||
uint32_t image = firstImages[level];
|
||||
uint32_t endImage = image + numImages;
|
||||
ktx_size_t levelImageSizeOut, levelSizeOut;
|
||||
uint32_t stateIndex = 0;
|
||||
|
||||
levelSizeOut = 0;
|
||||
// FIXME: Figure out a way to get the size out of the transcoder.
|
||||
levelImageSizeOut = ktxTexture2_GetImageSize(prototype, level);
|
||||
for (; image < endImage; image++) {
|
||||
const ktxBasisLzEtc1sImageDesc& imageDesc = imageDescs[image];
|
||||
|
||||
basisu_transcoder_state& xcoderState = xcoderStates[stateIndex];
|
||||
// We have face0 [face1 ...] within each layer. Use `stateIndex`
|
||||
// rather than a double loop of layers and faceSlices as this
|
||||
// works for 3d texture and non-array cube maps as well as
|
||||
// cube map arrays without special casing.
|
||||
if (++stateIndex == xcoderStates.size())
|
||||
stateIndex = 0;
|
||||
|
||||
if (alphaContent != eNone)
|
||||
{
|
||||
// The slice descriptions should have alpha information.
|
||||
if (imageDesc.alphaSliceByteOffset == 0
|
||||
|| imageDesc.alphaSliceByteLength == 0)
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
bool status;
|
||||
status = bit.transcode_image(
|
||||
(transcoder_texture_format)outputFormat,
|
||||
pXcodedData + writeOffset,
|
||||
(uint32_t)(xcodedDataLength - writeOffsetBlocks),
|
||||
This->pData,
|
||||
(uint32_t)This->dataSize,
|
||||
levelBlocksX,
|
||||
levelBlocksY,
|
||||
levelWidth,
|
||||
levelHeight,
|
||||
level,
|
||||
(uint32_t)(levelOffset + imageDesc.rgbSliceByteOffset),
|
||||
imageDesc.rgbSliceByteLength,
|
||||
(uint32_t)(levelOffset + imageDesc.alphaSliceByteOffset),
|
||||
imageDesc.alphaSliceByteLength,
|
||||
transcodeFlags,
|
||||
alphaContent != eNone,
|
||||
isVideo,
|
||||
// Our P-Frame flag is in the same bit as
|
||||
// cSliceDescFlagsFrameIsIFrame. We have to
|
||||
// invert it to make it an I-Frame flag.
|
||||
//
|
||||
// API currently doesn't have any way to pass
|
||||
// the I-Frame flag.
|
||||
//imageDesc.imageFlags ^ cSliceDescFlagsFrameIsIFrame,
|
||||
0, // output_row_pitch_in_blocks_or_pixels
|
||||
&xcoderState,
|
||||
0 // output_rows_in_pixels
|
||||
);
|
||||
if (!status) {
|
||||
result = KTX_TRANSCODE_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
writeOffset += levelImageSizeOut;
|
||||
levelSizeOut += levelImageSizeOut;
|
||||
} // end images loop
|
||||
protoLevelIndex[level].byteOffset = levelOffsetWrite;
|
||||
protoLevelIndex[level].byteLength = levelSizeOut;
|
||||
protoLevelIndex[level].uncompressedByteLength = levelSizeOut;
|
||||
levelOffsetWrite += levelSizeOut;
|
||||
assert(levelOffsetWrite == writeOffset);
|
||||
// In case of transcoding to uncompressed.
|
||||
levelOffsetWrite = _KTX_PADN(protoPriv._requiredLevelAlignment,
|
||||
levelOffsetWrite);
|
||||
} // level loop
|
||||
|
||||
result = KTX_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
delete[] firstImages;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
KTX_error_code
|
||||
ktxTexture2_transcodeUastc(ktxTexture2* This,
|
||||
alpha_content_e alphaContent,
|
||||
ktxTexture2* prototype,
|
||||
ktx_transcode_fmt_e outputFormat,
|
||||
ktx_transcode_flags transcodeFlags)
|
||||
{
|
||||
assert(This->supercompressionScheme != KTX_SS_BASIS_LZ);
|
||||
|
||||
ktx_uint8_t* pXcodedData = prototype->pData;
|
||||
ktx_uint32_t outputBlockByteLength
|
||||
= prototype->_protected->_formatSize.blockSizeInBits / 8;
|
||||
ktx_size_t xcodedDataLength
|
||||
= prototype->dataSize / outputBlockByteLength;
|
||||
DECLARE_PRIVATE(protoPriv, prototype);
|
||||
ktxLevelIndexEntry* protoLevelIndex = protoPriv._levelIndex;
|
||||
ktx_size_t levelOffsetWrite = 0;
|
||||
|
||||
basisu_lowlevel_uastc_transcoder uit;
|
||||
// See comment on same declaration in transcodeEtc1s.
|
||||
std::vector<basisu_transcoder_state> xcoderStates;
|
||||
xcoderStates.resize(This->isVideo ? This->numFaces : 1);
|
||||
|
||||
for (ktx_int32_t level = This->numLevels - 1; level >= 0; level--)
|
||||
{
|
||||
ktx_uint32_t depth;
|
||||
uint64_t writeOffset = levelOffsetWrite;
|
||||
uint64_t writeOffsetBlocks = levelOffsetWrite / outputBlockByteLength;
|
||||
ktx_size_t levelImageSizeIn, levelImageOffsetIn;
|
||||
ktx_size_t levelImageSizeOut, levelSizeOut;
|
||||
ktx_uint32_t levelImageCount;
|
||||
uint32_t levelWidth = MAX(1, This->baseWidth >> level);
|
||||
uint32_t levelHeight = MAX(1, This->baseHeight >> level);
|
||||
// UASTC texel block dimensions
|
||||
const uint32_t bw = 4, bh = 4;
|
||||
uint32_t levelBlocksX = (levelWidth + (bw - 1)) / bw;
|
||||
uint32_t levelBlocksY = (levelHeight + (bh - 1)) / bh;
|
||||
uint32_t stateIndex = 0;
|
||||
|
||||
depth = MAX(1, This->baseDepth >> level);
|
||||
|
||||
levelImageCount = This->numLayers * This->numFaces * depth;
|
||||
levelImageSizeIn = ktxTexture_calcImageSize(ktxTexture(This), level,
|
||||
KTX_FORMAT_VERSION_TWO);
|
||||
levelImageSizeOut = ktxTexture_calcImageSize(ktxTexture(prototype),
|
||||
level,
|
||||
KTX_FORMAT_VERSION_TWO);
|
||||
|
||||
levelImageOffsetIn = ktxTexture2_levelDataOffset(This, level);
|
||||
levelSizeOut = 0;
|
||||
bool status;
|
||||
for (uint32_t image = 0; image < levelImageCount; image++) {
|
||||
basisu_transcoder_state& xcoderState = xcoderStates[stateIndex];
|
||||
// See comment before same lines in transcodeEtc1s.
|
||||
if (++stateIndex == xcoderStates.size())
|
||||
stateIndex = 0;
|
||||
|
||||
status = uit.transcode_image(
|
||||
(transcoder_texture_format)outputFormat,
|
||||
pXcodedData + writeOffset,
|
||||
(uint32_t)(xcodedDataLength - writeOffsetBlocks),
|
||||
This->pData,
|
||||
(uint32_t)This->dataSize,
|
||||
levelBlocksX,
|
||||
levelBlocksY,
|
||||
levelWidth,
|
||||
levelHeight,
|
||||
level,
|
||||
(uint32_t)levelImageOffsetIn,
|
||||
(uint32_t)levelImageSizeIn,
|
||||
transcodeFlags,
|
||||
alphaContent != eNone,
|
||||
This->isVideo, // is_video
|
||||
//imageDesc.imageFlags ^ cSliceDescFlagsFrameIsIFrame,
|
||||
0, // output_row_pitch_in_blocks_or_pixels
|
||||
&xcoderState, // pState
|
||||
0, // output_rows_in_pixels,
|
||||
-1, // channel0
|
||||
-1 // channel1
|
||||
);
|
||||
if (!status)
|
||||
return KTX_TRANSCODE_FAILED;
|
||||
writeOffset += levelImageSizeOut;
|
||||
levelSizeOut += levelImageSizeOut;
|
||||
levelImageOffsetIn += levelImageSizeIn;
|
||||
}
|
||||
protoLevelIndex[level].byteOffset = levelOffsetWrite;
|
||||
// writeOffset will be equal to total size of the images in the level.
|
||||
protoLevelIndex[level].byteLength = levelSizeOut;
|
||||
protoLevelIndex[level].uncompressedByteLength = levelSizeOut;
|
||||
levelOffsetWrite += levelSizeOut;
|
||||
}
|
||||
// In case of transcoding to uncompressed.
|
||||
levelOffsetWrite = _KTX_PADN(protoPriv._requiredLevelAlignment,
|
||||
levelOffsetWrite);
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Function to verify a KTX file header
|
||||
*
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author: Georg Kolling, Imagination Technology with modifications
|
||||
* by Mark Callow, HI Corporation.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
#include "vkformat_enum.h"
|
||||
|
||||
bool isProhibitedFormat(VkFormat format);
|
||||
bool isValidFormat(VkFormat format);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief Check a KTX file header.
|
||||
*
|
||||
* As well as checking that the header identifies a KTX file, the function
|
||||
* sanity checks the values and returns information about the texture in a
|
||||
* struct KTX_supplementary_info.
|
||||
*
|
||||
* @param pHeader pointer to the KTX header to check
|
||||
* @param pSuppInfo pointer to a KTX_supplementary_info structure in which to
|
||||
* return information about the texture.
|
||||
*
|
||||
* @author Georg Kolling, Imagination Technology
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
KTX_error_code ktxCheckHeader1_(KTX_header* pHeader,
|
||||
KTX_supplemental_info* pSuppInfo)
|
||||
{
|
||||
ktx_uint8_t identifier_reference[12] = KTX_IDENTIFIER_REF;
|
||||
ktx_uint32_t max_dim;
|
||||
|
||||
assert(pHeader != NULL && pSuppInfo != NULL);
|
||||
|
||||
/* Compare identifier, is this a KTX file? */
|
||||
if (memcmp(pHeader->identifier, identifier_reference, 12) != 0)
|
||||
{
|
||||
return KTX_UNKNOWN_FILE_FORMAT;
|
||||
}
|
||||
|
||||
if (pHeader->endianness == KTX_ENDIAN_REF_REV)
|
||||
{
|
||||
/* Convert endianness of pHeader fields. */
|
||||
_ktxSwapEndian32(&pHeader->glType, 12);
|
||||
|
||||
if (pHeader->glTypeSize != 1 &&
|
||||
pHeader->glTypeSize != 2 &&
|
||||
pHeader->glTypeSize != 4)
|
||||
{
|
||||
/* Only 8-, 16-, and 32-bit types supported so far. */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
else if (pHeader->endianness != KTX_ENDIAN_REF)
|
||||
{
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Check glType and glFormat */
|
||||
pSuppInfo->compressed = 0;
|
||||
if (pHeader->glType == 0 || pHeader->glFormat == 0)
|
||||
{
|
||||
if (pHeader->glType + pHeader->glFormat != 0)
|
||||
{
|
||||
/* either both or none of glType, glFormat must be zero */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
pSuppInfo->compressed = 1;
|
||||
}
|
||||
|
||||
if (pHeader->glFormat == pHeader->glInternalformat) {
|
||||
// glInternalFormat is either unsized (which is no longer and should
|
||||
// never have been supported by libktx) or glFormat is sized.
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Check texture dimensions. KTX files can store 8 types of textures:
|
||||
1D, 2D, 3D, cube, and array variants of these. There is currently
|
||||
no GL extension for 3D array textures. */
|
||||
if ((pHeader->pixelWidth == 0) ||
|
||||
(pHeader->pixelDepth > 0 && pHeader->pixelHeight == 0))
|
||||
{
|
||||
/* texture must have width */
|
||||
/* texture must have height if it has depth */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (pHeader->pixelDepth > 0)
|
||||
{
|
||||
if (pHeader->numberOfArrayElements > 0)
|
||||
{
|
||||
/* No 3D array textures yet. */
|
||||
return KTX_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
pSuppInfo->textureDimension = 3;
|
||||
}
|
||||
else if (pHeader->pixelHeight > 0)
|
||||
{
|
||||
pSuppInfo->textureDimension = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSuppInfo->textureDimension = 1;
|
||||
}
|
||||
|
||||
if (pHeader->numberOfFaces == 6)
|
||||
{
|
||||
if (pSuppInfo->textureDimension != 2)
|
||||
{
|
||||
/* cube map needs 2D faces */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
else if (pHeader->numberOfFaces != 1)
|
||||
{
|
||||
/* numberOfFaces must be either 1 or 6 */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Check number of mipmap levels */
|
||||
if (pHeader->numberOfMipLevels == 0)
|
||||
{
|
||||
pSuppInfo->generateMipmaps = 1;
|
||||
pHeader->numberOfMipLevels = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSuppInfo->generateMipmaps = 0;
|
||||
}
|
||||
|
||||
/* This test works for arrays too because height or depth will be 0. */
|
||||
max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth);
|
||||
if (max_dim < ((ktx_uint32_t)1 << (pHeader->numberOfMipLevels - 1)))
|
||||
{
|
||||
/* Can't have more mip levels than 1 + log2(max(width, height, depth)) */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief Check a KTX2 file header.
|
||||
*
|
||||
* As well as checking that the header identifies a KTX 2 file, the function
|
||||
* sanity checks the values and returns information about the texture in a
|
||||
* struct KTX_supplementary_info.
|
||||
*
|
||||
* @param pHeader pointer to the KTX header to check
|
||||
* @param pSuppInfo pointer to a KTX_supplementary_info structure in which to
|
||||
* return information about the texture.
|
||||
*
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader,
|
||||
KTX_supplemental_info* pSuppInfo)
|
||||
{
|
||||
// supp info is compressed, generateMipmaps and num dimensions. Don't need
|
||||
// compressed as formatSize gives us that. I think the other 2 aren't needed.
|
||||
ktx_uint8_t identifier_reference[12] = KTX2_IDENTIFIER_REF;
|
||||
|
||||
assert(pHeader != NULL && pSuppInfo != NULL);
|
||||
ktx_uint32_t max_dim;
|
||||
|
||||
/* Compare identifier, is this a KTX file? */
|
||||
if (memcmp(pHeader->identifier, identifier_reference, 12) != 0)
|
||||
{
|
||||
return KTX_UNKNOWN_FILE_FORMAT;
|
||||
}
|
||||
|
||||
/* Check format */
|
||||
if (isProhibitedFormat(pHeader->vkFormat))
|
||||
{
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
if (!isValidFormat(pHeader->vkFormat))
|
||||
{
|
||||
return KTX_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
if (pHeader->supercompressionScheme == KTX_SS_BASIS_LZ && pHeader->vkFormat != VK_FORMAT_UNDEFINED)
|
||||
{
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Check texture dimensions. KTX files can store 8 types of textures:
|
||||
1D, 2D, 3D, cube, and array variants of these. There is currently
|
||||
no extension for 3D array textures in any 3D API. */
|
||||
if ((pHeader->pixelWidth == 0) ||
|
||||
(pHeader->pixelDepth > 0 && pHeader->pixelHeight == 0))
|
||||
{
|
||||
/* texture must have width */
|
||||
/* texture must have height if it has depth */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (pHeader->pixelDepth > 0)
|
||||
{
|
||||
if (pHeader->layerCount > 0)
|
||||
{
|
||||
/* No 3D array textures yet. */
|
||||
return KTX_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
pSuppInfo->textureDimension = 3;
|
||||
}
|
||||
else if (pHeader->pixelHeight > 0)
|
||||
{
|
||||
pSuppInfo->textureDimension = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSuppInfo->textureDimension = 1;
|
||||
}
|
||||
|
||||
if (pHeader->faceCount == 6)
|
||||
{
|
||||
if (pSuppInfo->textureDimension != 2)
|
||||
{
|
||||
/* cube map needs 2D faces */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
if (pHeader->pixelDepth != 0)
|
||||
{
|
||||
/* cube map cannot have depth */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
if (pHeader->pixelWidth != pHeader->pixelHeight)
|
||||
{
|
||||
/* cube map needs square faces */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
else if (pHeader->faceCount != 1)
|
||||
{
|
||||
/* numberOfFaces must be either 1 or 6 */
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
// Check number of mipmap levels
|
||||
if (pHeader->levelCount == 0)
|
||||
{
|
||||
pSuppInfo->generateMipmaps = 1;
|
||||
pHeader->levelCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
pSuppInfo->generateMipmaps = 0;
|
||||
}
|
||||
|
||||
// Check supercompression
|
||||
switch (pHeader->supercompressionScheme) {
|
||||
case KTX_SS_NONE:
|
||||
case KTX_SS_BASIS_LZ:
|
||||
case KTX_SS_ZSTD:
|
||||
case KTX_SS_ZLIB:
|
||||
break;
|
||||
default:
|
||||
// Unsupported supercompression
|
||||
return KTX_UNSUPPORTED_FEATURE;
|
||||
}
|
||||
|
||||
// This test works for arrays too because height or depth will be 0.
|
||||
max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth);
|
||||
if (max_dim < ((ktx_uint32_t)1 << (pHeader->levelCount - 1)))
|
||||
{
|
||||
// Can't have more mip levels than 1 + log2(max(width, height, depth))
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
return KTX_SUCCESS;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4: */
|
||||
|
||||
/* $Id: b84f0063f86e9f20473d5a900eecbf1bf57b399c $ */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* @internal
|
||||
* @~English
|
||||
* @file
|
||||
*
|
||||
* Unpack a texture compressed with ETC1
|
||||
*
|
||||
* @author Mark Callow, HI Corporation.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "GL/glcorearb.h"
|
||||
// Not defined in glcorearb.h.
|
||||
#define GL_ETC1_RGB8_OES 0x8D64
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
|
||||
#if SUPPORT_SOFTWARE_ETC_UNPACK
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned char uint8;
|
||||
|
||||
extern void decompressBlockETC2c(uint block_part1, uint block_part2, uint8* img,
|
||||
int width, int height, int startx, int starty, int channels);
|
||||
extern void decompressBlockETC21BitAlphaC(uint block_part1, uint block_part2, uint8* img, uint8* alphaimg,
|
||||
int width, int height, int startx, int starty, int channels);
|
||||
extern void decompressBlockAlphaC(uint8* data, uint8* img,
|
||||
int width, int height, int startx, int starty, int channels);
|
||||
extern void decompressBlockAlpha16bitC(uint8* data, uint8* img,
|
||||
int width, int height, int startx, int starty, int channels);
|
||||
|
||||
extern void setupAlphaTable();
|
||||
|
||||
// This global variable affects the behaviour of decompressBlockAlpha16bitC.
|
||||
extern int formatSigned;
|
||||
|
||||
static void
|
||||
readBigEndian4byteWord(ktx_uint32_t* pBlock, const GLubyte *s)
|
||||
{
|
||||
*pBlock = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
|
||||
}
|
||||
|
||||
|
||||
/* Unpack an ETC1_RGB8_OES format compressed texture */
|
||||
extern "C" KTX_error_code
|
||||
_ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat,
|
||||
ktx_uint32_t activeWidth, ktx_uint32_t activeHeight,
|
||||
GLubyte** dstImage,
|
||||
GLenum* format, GLenum* internalFormat, GLenum* type,
|
||||
GLint R16Formats, GLboolean supportsSRGB)
|
||||
{
|
||||
unsigned int width, height;
|
||||
unsigned int block_part1, block_part2;
|
||||
unsigned int x, y;
|
||||
/*const*/ GLubyte* src = (GLubyte*)srcETC;
|
||||
// AF_11BIT is used to compress R11 & RG11 though its not alpha data.
|
||||
enum {AF_NONE, AF_1BIT, AF_8BIT, AF_11BIT} alphaFormat = AF_NONE;
|
||||
int dstChannels, dstChannelBytes;
|
||||
|
||||
switch (srcFormat) {
|
||||
case GL_COMPRESSED_SIGNED_R11_EAC:
|
||||
if (R16Formats & _KTX_R16_FORMATS_SNORM) {
|
||||
dstChannelBytes = sizeof(GLshort);
|
||||
dstChannels = 1;
|
||||
formatSigned = GL_TRUE;
|
||||
*internalFormat = GL_R16_SNORM;
|
||||
*format = GL_RED;
|
||||
*type = GL_SHORT;
|
||||
alphaFormat = AF_11BIT;
|
||||
} else
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_R11_EAC:
|
||||
if (R16Formats & _KTX_R16_FORMATS_NORM) {
|
||||
dstChannelBytes = sizeof(GLshort);
|
||||
dstChannels = 1;
|
||||
formatSigned = GL_FALSE;
|
||||
*internalFormat = GL_R16;
|
||||
*format = GL_RED;
|
||||
*type = GL_UNSIGNED_SHORT;
|
||||
alphaFormat = AF_11BIT;
|
||||
} else
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_SIGNED_RG11_EAC:
|
||||
if (R16Formats & _KTX_R16_FORMATS_SNORM) {
|
||||
dstChannelBytes = sizeof(GLshort);
|
||||
dstChannels = 2;
|
||||
formatSigned = GL_TRUE;
|
||||
*internalFormat = GL_RG16_SNORM;
|
||||
*format = GL_RG;
|
||||
*type = GL_SHORT;
|
||||
alphaFormat = AF_11BIT;
|
||||
} else
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_RG11_EAC:
|
||||
if (R16Formats & _KTX_R16_FORMATS_NORM) {
|
||||
dstChannelBytes = sizeof(GLshort);
|
||||
dstChannels = 2;
|
||||
formatSigned = GL_FALSE;
|
||||
*internalFormat = GL_RG16;
|
||||
*format = GL_RG;
|
||||
*type = GL_UNSIGNED_SHORT;
|
||||
alphaFormat = AF_11BIT;
|
||||
} else
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
break;
|
||||
|
||||
case GL_ETC1_RGB8_OES:
|
||||
case GL_COMPRESSED_RGB8_ETC2:
|
||||
dstChannelBytes = sizeof(GLubyte);
|
||||
dstChannels = 3;
|
||||
*internalFormat = GL_RGB8;
|
||||
*format = GL_RGB;
|
||||
*type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_RGBA8_ETC2_EAC:
|
||||
dstChannelBytes = sizeof(GLubyte);
|
||||
dstChannels = 4;
|
||||
*internalFormat = GL_RGBA8;
|
||||
*format = GL_RGBA;
|
||||
*type = GL_UNSIGNED_BYTE;
|
||||
alphaFormat = AF_8BIT;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||
dstChannelBytes = sizeof(GLubyte);
|
||||
dstChannels = 4;
|
||||
*internalFormat = GL_RGBA8;
|
||||
*format = GL_RGBA;
|
||||
*type = GL_UNSIGNED_BYTE;
|
||||
alphaFormat = AF_1BIT;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_SRGB8_ETC2:
|
||||
if (supportsSRGB) {
|
||||
dstChannelBytes = sizeof(GLubyte);
|
||||
dstChannels = 3;
|
||||
*internalFormat = GL_SRGB8;
|
||||
*format = GL_RGB;
|
||||
*type = GL_UNSIGNED_BYTE;
|
||||
} else
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
|
||||
if (supportsSRGB) {
|
||||
dstChannelBytes = sizeof(GLubyte);
|
||||
dstChannels = 4;
|
||||
*internalFormat = GL_SRGB8_ALPHA8;
|
||||
*format = GL_RGBA;
|
||||
*type = GL_UNSIGNED_BYTE;
|
||||
alphaFormat = AF_8BIT;
|
||||
} else
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
break;
|
||||
|
||||
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
|
||||
if (supportsSRGB) {
|
||||
dstChannelBytes = sizeof(GLubyte);
|
||||
dstChannels = 4;
|
||||
*internalFormat = GL_SRGB8_ALPHA8;
|
||||
*format = GL_RGBA;
|
||||
*type = GL_UNSIGNED_BYTE;
|
||||
alphaFormat = AF_1BIT;
|
||||
} else
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // Upper levels should pass only one of the above srcFormats.
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE; // For Release configurations.
|
||||
}
|
||||
|
||||
/* active_{width,height} show how many pixels contain active data,
|
||||
* (the rest are just for making sure we have a 2*a x 4*b size).
|
||||
*/
|
||||
|
||||
/* Compute the full width & height. */
|
||||
width = ((activeWidth+3)/4)*4;
|
||||
height = ((activeHeight+3)/4)*4;
|
||||
|
||||
/* printf("Width = %d, Height = %d\n", width, height); */
|
||||
/* printf("active pixel area: top left %d x %d area.\n", activeWidth, activeHeight); */
|
||||
|
||||
*dstImage = (GLubyte*)malloc(dstChannels*dstChannelBytes*width*height);
|
||||
if (!*dstImage) {
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (alphaFormat != AF_NONE)
|
||||
setupAlphaTable();
|
||||
|
||||
// NOTE: none of the decompress functions actually use the <height> parameter
|
||||
if (alphaFormat == AF_11BIT) {
|
||||
// One or two 11-bit alpha channels for R or RG.
|
||||
for (y=0; y < height/4; y++) {
|
||||
for (x=0; x < width/4; x++) {
|
||||
decompressBlockAlpha16bitC(src, *dstImage, width, height, 4*x, 4*y, dstChannels);
|
||||
src += 8;
|
||||
if (srcFormat == GL_COMPRESSED_RG11_EAC || srcFormat == GL_COMPRESSED_SIGNED_RG11_EAC) {
|
||||
decompressBlockAlpha16bitC(src, *dstImage + dstChannelBytes, width, height, 4*x, 4*y, dstChannels);
|
||||
src += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y=0; y < height/4; y++) {
|
||||
for (x=0; x < width/4; x++) {
|
||||
// Decode alpha channel for RGBA
|
||||
if (alphaFormat == AF_8BIT) {
|
||||
decompressBlockAlphaC(src, *dstImage + 3, width, height, 4*x, 4*y, dstChannels);
|
||||
src += 8;
|
||||
}
|
||||
// Decode color dstChannels
|
||||
readBigEndian4byteWord(&block_part1, src);
|
||||
src += 4;
|
||||
readBigEndian4byteWord(&block_part2, src);
|
||||
src += 4;
|
||||
if (alphaFormat == AF_1BIT)
|
||||
decompressBlockETC21BitAlphaC(block_part1, block_part2, *dstImage, 0, width, height, 4*x, 4*y, dstChannels);
|
||||
else
|
||||
decompressBlockETC2c(block_part1, block_part2, *dstImage, width, height, 4*x, 4*y, dstChannels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ok, now write out the active pixels to the destination image.
|
||||
* (But only if the active pixels differ from the total pixels)
|
||||
*/
|
||||
|
||||
if( !(height == activeHeight && width == activeWidth) ) {
|
||||
int dstPixelBytes = dstChannels * dstChannelBytes;
|
||||
int dstRowBytes = dstPixelBytes * width;
|
||||
int activeRowBytes = activeWidth * dstPixelBytes;
|
||||
GLubyte *newimg = (GLubyte*)malloc(dstPixelBytes * activeWidth * activeHeight);
|
||||
unsigned int xx, yy;
|
||||
int zz;
|
||||
|
||||
if (!newimg) {
|
||||
free(*dstImage);
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Convert from total area to active area: */
|
||||
|
||||
for (yy = 0; yy < activeHeight; yy++) {
|
||||
for (xx = 0; xx < activeWidth; xx++) {
|
||||
for (zz = 0; zz < dstPixelBytes; zz++) {
|
||||
newimg[ yy*activeRowBytes + xx*dstPixelBytes + zz ] = (*dstImage)[ yy*dstRowBytes + xx*dstPixelBytes + zz];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(*dstImage);
|
||||
*dstImage = newimg;
|
||||
}
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* SUPPORT_SOFTWARE_ETC_UNPACK */
|
||||
@@ -0,0 +1,395 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Implementation of ktxStream for FILE.
|
||||
*
|
||||
* @author Maksim Kolesin, Under Development
|
||||
* @author Georg Kolling, Imagination Technology
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
/* I need these on Linux. Why? */
|
||||
#define __USE_LARGEFILE 1 // For declaration of ftello, etc.
|
||||
#define __USE_POSIX 1 // For declaration of fileno.
|
||||
#define _POSIX_SOURCE 1 // For both the above in Emscripten.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h> // For stat.h on Windows
|
||||
#define __USE_MISC 1 // For declaration of S_IF...
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
#include "filestream.h"
|
||||
|
||||
// Gotta love Windows :-(
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_WIN64)
|
||||
#define ftello _ftelli64
|
||||
#define fseeko _fseeki64
|
||||
#else
|
||||
#define ftello ftell
|
||||
#define fseeko fseek
|
||||
#endif
|
||||
#define fileno _fileno
|
||||
#define fstat _fstat
|
||||
#define stat _stat
|
||||
#define S_IFIFO _S_IFIFO
|
||||
#define S_IFSOCK 0xC000
|
||||
typedef unsigned short mode_t;
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#define S_IFSOCK 0xC000
|
||||
#endif
|
||||
|
||||
#define KTX_FILE_STREAM_MAX (1 << (sizeof(ktx_off_t) - 1) - 1)
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Read bytes from a ktxFileStream.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream from which to read.
|
||||
* @param [out] dst pointer to a block of memory with a size
|
||||
* of at least @p size bytes, converted to a void*.
|
||||
* @param [in,out] count pointer to total count of bytes to be read.
|
||||
* On completion set to number of bytes read.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p dst is @c NULL or @p src is @c NULL.
|
||||
* @exception KTX_FILE_READ_ERROR an error occurred while reading the file.
|
||||
* @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxFileStream_read(ktxStream* str, void* dst, const ktx_size_t count)
|
||||
{
|
||||
ktx_size_t nread;
|
||||
|
||||
if (!str || !dst)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeFile);
|
||||
|
||||
if ((nread = fread(dst, 1, count, str->data.file)) != count) {
|
||||
if (feof(str->data.file)) {
|
||||
return KTX_FILE_UNEXPECTED_EOF;
|
||||
} else {
|
||||
return KTX_FILE_READ_ERROR;
|
||||
}
|
||||
}
|
||||
str->readpos += count;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Skip bytes in a ktxFileStream.
|
||||
*
|
||||
* @param [in] str pointer to a ktxStream object.
|
||||
* @param [in] count number of bytes to be skipped.
|
||||
*
|
||||
* In order to support applications reading from stdin, read characters
|
||||
* rather than using seek functions.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str is @c NULL or @p count is less than zero.
|
||||
* @exception KTX_INVALID_OPERATION skipping @p count bytes would go beyond EOF.
|
||||
* @exception KTX_FILE_READ_ERROR an error occurred while reading the file.
|
||||
* @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request.
|
||||
* @p count is set to the number of bytes
|
||||
* skipped.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxFileStream_skip(ktxStream* str, const ktx_size_t count)
|
||||
{
|
||||
if (!str)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeFile);
|
||||
|
||||
for (ktx_uint32_t i = 0; i < count; i++) {
|
||||
int ret = getc(str->data.file);
|
||||
if (ret == EOF) {
|
||||
if (feof(str->data.file)) {
|
||||
return KTX_FILE_UNEXPECTED_EOF;
|
||||
} else {
|
||||
return KTX_FILE_READ_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
str->readpos += count;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Write bytes to a ktxFileStream.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream that is the destination of the
|
||||
* write.
|
||||
* @param [in] src pointer to the array of elements to be written,
|
||||
* converted to a const void*.
|
||||
* @param [in] size size in bytes of each element to be written.
|
||||
* @param [in] count number of elements, each one with a @p size of size
|
||||
* bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str is @c NULL or @p src is @c NULL.
|
||||
* @exception KTX_FILE_OVERFLOW the requested write would caused the file to
|
||||
* exceed the maximum supported file size.
|
||||
* @exception KTX_FILE_WRITE_ERROR a system error occurred while writing the
|
||||
* file.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxFileStream_write(ktxStream* str, const void *src,
|
||||
const ktx_size_t size,
|
||||
const ktx_size_t count)
|
||||
{
|
||||
if (!str || !src)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeFile);
|
||||
|
||||
if (fwrite(src, size, count, str->data.file) != count) {
|
||||
if (errno == EFBIG || errno == EOVERFLOW)
|
||||
return KTX_FILE_OVERFLOW;
|
||||
else
|
||||
return KTX_FILE_WRITE_ERROR;
|
||||
}
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Get the current read/write position in a ktxFileStream.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream to query.
|
||||
* @param [in,out] off pointer to variable to receive the offset value.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_FILE_ISPIPE file descriptor underlying stream is associated
|
||||
* with a pipe or FIFO so does not have a
|
||||
* file-position indicator.
|
||||
* @exception KTX_INVALID_VALUE @p str or @p pos is @c NULL.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxFileStream_getpos(ktxStream* str, ktx_off_t* pos)
|
||||
{
|
||||
ktx_off_t ftellval;
|
||||
|
||||
if (!str || !pos)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeFile);
|
||||
|
||||
if (str->data.file == stdin) {
|
||||
*pos = str->readpos;
|
||||
} else {
|
||||
/* The cast quiets an Xcode warning when building for "Generic iOS Device".
|
||||
* I'm not sure why.
|
||||
*/
|
||||
ftellval = (ktx_off_t)ftello(str->data.file);
|
||||
if (ftellval < 0) {
|
||||
switch (errno) {
|
||||
case ESPIPE: return KTX_FILE_ISPIPE;
|
||||
case EOVERFLOW: return KTX_FILE_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
*pos = ftellval;
|
||||
}
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Set the current read/write position in a ktxFileStream.
|
||||
*
|
||||
* Offset of 0 is the start of the file. This function operates
|
||||
* like Linux > 3.1's @c lseek() when it is passed a @c whence
|
||||
* of @c SEEK_DATA as it returns an error if the seek would
|
||||
* go beyond the end of the file.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream whose r/w position is to be set.
|
||||
* @param [in] off pointer to the offset value to set.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* Throws the same exceptions as ktxFileStream_getsize() for the reasons given
|
||||
* there plus the following:
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str is @c NULL.
|
||||
* @exception KTX_INVALID_OPERATION @p pos is > the size of the file or an
|
||||
* fseek error occurred.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxFileStream_setpos(ktxStream* str, ktx_off_t pos)
|
||||
{
|
||||
ktx_size_t fileSize;
|
||||
KTX_error_code result;
|
||||
|
||||
if (!str)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeFile);
|
||||
|
||||
if (str->data.file == stdin) {
|
||||
if (pos > str->readpos)
|
||||
return str->skip(str, pos - str->readpos);
|
||||
else
|
||||
return KTX_FILE_ISPIPE;
|
||||
}
|
||||
|
||||
result = str->getsize(str, &fileSize);
|
||||
|
||||
if (result != KTX_SUCCESS) {
|
||||
// Device is likely not seekable.
|
||||
return result;
|
||||
}
|
||||
|
||||
if (pos > (ktx_off_t)fileSize)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
if (fseeko(str->data.file, pos, SEEK_SET) < 0)
|
||||
return KTX_FILE_SEEK_ERROR;
|
||||
else
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Get the size of a ktxFileStream in bytes.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream whose size is to be queried.
|
||||
* @param [in,out] size pointer to a variable in which size will be written.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_FILE_OVERFLOW size is too large to be returned in a
|
||||
* @c ktx_size_t.
|
||||
* @exception KTX_FILE_ISPIPE file descriptor underlying stream is associated
|
||||
* with a pipe or FIFO so does not have a
|
||||
* file-position indicator.
|
||||
* @exception KTX_FILE_READ_ERROR a system error occurred while getting the
|
||||
* size.
|
||||
* @exception KTX_INVALID_VALUE @p str or @p size is @c NULL.
|
||||
* @exception KTX_INVALID_OPERATION stream is a tty.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxFileStream_getsize(ktxStream* str, ktx_size_t* size)
|
||||
{
|
||||
struct stat statbuf;
|
||||
int statret;
|
||||
|
||||
if (!str || !size)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeFile);
|
||||
|
||||
// Need to flush so that fstat will return the current size.
|
||||
// Can ignore return value. The only error that can happen is to tell you
|
||||
// it was a NOP because the file is read only.
|
||||
#if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(__MINGW64__) && !defined(_UCRT)
|
||||
// Bug in VS2013 msvcrt. fflush on FILE open for READ changes file offset
|
||||
// to 4096.
|
||||
if (str->data.file->_flag & _IOWRT)
|
||||
(void)fflush(str->data.file);
|
||||
#else
|
||||
(void)fflush(str->data.file);
|
||||
#endif
|
||||
statret = fstat(fileno(str->data.file), &statbuf);
|
||||
if (statret < 0) {
|
||||
switch (errno) {
|
||||
case EOVERFLOW: return KTX_FILE_OVERFLOW;
|
||||
case EIO:
|
||||
default:
|
||||
return KTX_FILE_READ_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
mode_t ftype = statbuf.st_mode & S_IFMT;
|
||||
if (ftype == S_IFIFO || ftype == S_IFSOCK)
|
||||
return KTX_FILE_ISPIPE;
|
||||
|
||||
if (statbuf.st_mode & S_IFCHR)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
*size = (ktx_size_t)statbuf.st_size; /* See _getpos for why this cast. */
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Initialize a ktxFileStream.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream to initialize.
|
||||
* @param [in] file pointer to the underlying FILE object.
|
||||
* @param [in] closeFileOnDestruct if not false, stdio file pointer will be closed when ktxStream
|
||||
* is destructed.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p stream is @c NULL or @p file is @c NULL.
|
||||
*/
|
||||
KTX_error_code ktxFileStream_construct(ktxStream* str, FILE* file,
|
||||
ktx_bool_t closeFileOnDestruct)
|
||||
{
|
||||
if (!str || !file)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
str->data.file = file;
|
||||
str->readpos = 0;
|
||||
str->type = eStreamTypeFile;
|
||||
str->read = ktxFileStream_read;
|
||||
str->skip = ktxFileStream_skip;
|
||||
str->write = ktxFileStream_write;
|
||||
str->getpos = ktxFileStream_getpos;
|
||||
str->setpos = ktxFileStream_setpos;
|
||||
str->getsize = ktxFileStream_getsize;
|
||||
str->destruct = ktxFileStream_destruct;
|
||||
str->closeOnDestruct = closeFileOnDestruct;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Destruct the stream, potentially closing the underlying FILE.
|
||||
*
|
||||
* This only closes the underyling FILE if the @c closeOnDestruct parameter to
|
||||
* ktxFileStream_construct() was not @c KTX_FALSE.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream whose FILE is to potentially
|
||||
* be closed.
|
||||
*/
|
||||
void
|
||||
ktxFileStream_destruct(ktxStream* str)
|
||||
{
|
||||
assert(str && str->type == eStreamTypeFile);
|
||||
|
||||
if (str->closeOnDestruct)
|
||||
fclose(str->data.file);
|
||||
str->data.file = 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Author: Maksim Kolesin from original code
|
||||
* by Mark Callow and Georg Kolling
|
||||
*/
|
||||
|
||||
#ifndef FILESTREAM_H
|
||||
#define FILESTREAM_H
|
||||
|
||||
#include "ktx.h"
|
||||
|
||||
/*
|
||||
* ktxFileInit: Initialize a ktxStream to a ktxFileStream with a FILE object
|
||||
*/
|
||||
KTX_error_code ktxFileStream_construct(ktxStream* str, FILE* file,
|
||||
ktx_bool_t closeFileOnDestruct);
|
||||
|
||||
void ktxFileStream_destruct(ktxStream* str);
|
||||
|
||||
#endif /* FILESTREAM_H */
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2019-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Struct for returning size information about an image format.
|
||||
*
|
||||
* @author Mark Callow, github.com/MarkCallow
|
||||
*/
|
||||
|
||||
#ifndef _FORMATSIZE_H_
|
||||
#define _FORMATSIZE_H_
|
||||
|
||||
#include "ktx.h"
|
||||
|
||||
typedef enum ktxFormatSizeFlagBits {
|
||||
KTX_FORMAT_SIZE_PACKED_BIT = 0x00000001,
|
||||
KTX_FORMAT_SIZE_COMPRESSED_BIT = 0x00000002,
|
||||
KTX_FORMAT_SIZE_PALETTIZED_BIT = 0x00000004,
|
||||
KTX_FORMAT_SIZE_DEPTH_BIT = 0x00000008,
|
||||
KTX_FORMAT_SIZE_STENCIL_BIT = 0x00000010,
|
||||
KTX_FORMAT_SIZE_YUVSDA_BIT = 0x00000020,
|
||||
} ktxFormatSizeFlagBits;
|
||||
|
||||
typedef ktx_uint32_t ktxFormatSizeFlags;
|
||||
|
||||
/**
|
||||
* @brief Structure for holding size information for a texture format.
|
||||
*/
|
||||
typedef struct ktxFormatSize {
|
||||
ktxFormatSizeFlags flags;
|
||||
unsigned int paletteSizeInBits; // For KTX1.
|
||||
unsigned int blockSizeInBits;
|
||||
unsigned int blockWidth; // in texels
|
||||
unsigned int blockHeight; // in texels
|
||||
unsigned int blockDepth; // in texels
|
||||
unsigned int minBlocksX; // Minimum required number of blocks
|
||||
unsigned int minBlocksY;
|
||||
} ktxFormatSize;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* _FORMATSIZE_H_ */
|
||||
+2438
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2017-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief List of OpenGL {,ES} functions used by libktx.
|
||||
*/
|
||||
|
||||
// There is no way for the pre-processor to uppercase stringized macro args
|
||||
// so we have to explicitly give the types.
|
||||
|
||||
#define required 1 // Present in all GL versions. Load failure is an error.
|
||||
#define not_required 0 // May not be present. Code must check before calling.
|
||||
|
||||
GL_FUNCTION(PFNGLBINDTEXTUREPROC, glBindTexture, required)
|
||||
GL_FUNCTION(PFNGLCOMPRESSEDTEXIMAGE1DPROC, glCompressedTexImage1D, not_required)
|
||||
GL_FUNCTION(PFNGLCOMPRESSEDTEXIMAGE2DPROC, glCompressedTexImage2D, required)
|
||||
GL_FUNCTION(PFNGLCOMPRESSEDTEXIMAGE3DPROC, glCompressedTexImage3D, not_required)
|
||||
GL_FUNCTION(PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC, glCompressedTexSubImage1D, not_required)
|
||||
GL_FUNCTION(PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC, glCompressedTexSubImage2D, required)
|
||||
GL_FUNCTION(PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC, glCompressedTexSubImage3D, not_required)
|
||||
GL_FUNCTION(PFNGLDELETETEXTURESPROC, glDeleteTextures, required)
|
||||
GL_FUNCTION(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap, not_required)
|
||||
GL_FUNCTION(PFNGLGENTEXTURESPROC, glGenTextures, required)
|
||||
GL_FUNCTION(PFNGLGETERRORPROC, glGetError, required)
|
||||
GL_FUNCTION(PFNGLGETINTEGERVPROC, glGetIntegerv, required)
|
||||
GL_FUNCTION(PFNGLGETSTRINGPROC, glGetString, required)
|
||||
GL_FUNCTION(PFNGLGETSTRINGIPROC, glGetStringi, not_required)
|
||||
GL_FUNCTION(PFNGLPIXELSTOREIPROC, glPixelStorei, required)
|
||||
GL_FUNCTION(PFNGLTEXIMAGE1DPROC, glTexImage1D, not_required)
|
||||
GL_FUNCTION(PFNGLTEXIMAGE2DPROC, glTexImage2D, required)
|
||||
GL_FUNCTION(PFNGLTEXIMAGE3DPROC, glTexImage3D, not_required)
|
||||
GL_FUNCTION(PFNGLTEXPARAMETERIPROC, glTexParameteri, required)
|
||||
GL_FUNCTION(PFNGLTEXPARAMETERIVPROC, glTexParameteriv, required)
|
||||
GL_FUNCTION(PFNGLTEXSTORAGE1DPROC, glTexStorage1D, not_required)
|
||||
GL_FUNCTION(PFNGLTEXSTORAGE2DPROC, glTexStorage2D, not_required)
|
||||
GL_FUNCTION(PFNGLTEXSTORAGE3DPROC, glTexStorage3D, not_required)
|
||||
GL_FUNCTION(PFNGLTEXSUBIMAGE1DPROC, glTexSubImage1D, not_required)
|
||||
GL_FUNCTION(PFNGLTEXSUBIMAGE2DPROC, glTexSubImage2D, required)
|
||||
GL_FUNCTION(PFNGLTEXSUBIMAGE3DPROC, glTexSubImage3D, not_required)
|
||||
|
||||
#undef required
|
||||
#undef not_required
|
||||
@@ -0,0 +1,238 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2017-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Retrieve OpenGL function pointers needed by libktx
|
||||
*/
|
||||
|
||||
#define UNIX 0
|
||||
#define MACOS 0
|
||||
#define WINDOWS 0
|
||||
#define IOS 0
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef WINDOWS
|
||||
#define WINDOWS 1
|
||||
#endif
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
|
||||
#undef UNIX
|
||||
#define UNIX 1
|
||||
#endif
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
#undef UNIX
|
||||
#define UNIX 1
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__x86_64__)
|
||||
#undef MACOS
|
||||
#define MACOS 1
|
||||
#endif
|
||||
#if defined(__APPLE__) && (defined(__arm64__) || defined (__arm__))
|
||||
#undef IOS
|
||||
#define IOS 1
|
||||
#endif
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#define WEB 1
|
||||
#endif
|
||||
#if (IOS + MACOS + UNIX + WINDOWS + WEB) > 1
|
||||
#error "Multiple OS\'s defined"
|
||||
#endif
|
||||
|
||||
#if WINDOWS
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#define NO_SHORTCUTS
|
||||
#include "gl_funcs.h"
|
||||
|
||||
#if WINDOWS
|
||||
#define GetOpenGLModuleHandle(flags) ktxFindOpenGL()
|
||||
static HMODULE ktxOpenGLModuleHandle;
|
||||
static PFNGLGETPROCADDRESS pfnWglGetProcAddress;
|
||||
|
||||
PFNVOIDFUNCTION
|
||||
defaultGLGetProcAddress(const char* proc)
|
||||
{
|
||||
PFNVOIDFUNCTION pfnGLProc = NULL;
|
||||
|
||||
if (pfnWglGetProcAddress)
|
||||
pfnGLProc = pfnWglGetProcAddress(proc);
|
||||
if (!pfnGLProc) {
|
||||
pfnGLProc = (PFNVOIDFUNCTION)GetProcAddress(ktxOpenGLModuleHandle,
|
||||
proc);
|
||||
}
|
||||
return pfnGLProc;
|
||||
}
|
||||
#elif MACOS || UNIX || IOS
|
||||
// Using NULL returns a handle that can be used to search the process that
|
||||
// loaded us and any other libraries it has loaded. That's all we need to
|
||||
// search as the app is responsible for creating the GL context so it must
|
||||
// be there.
|
||||
#define GetOpenGLModuleHandle(flags) dlopen(NULL, flags)
|
||||
static void* ktxOpenGLModuleHandle;
|
||||
|
||||
PFNVOIDFUNCTION
|
||||
defaultGLGetProcAddress(const char* proc)
|
||||
{
|
||||
return dlsym(ktxOpenGLModuleHandle, proc);
|
||||
}
|
||||
#elif WEB
|
||||
extern void* emscripten_GetProcAddress(const char *name_);
|
||||
#define GetOpenGLModuleHandle(flag) (void*)0x0000ffff // Value doesn't matter.
|
||||
void* ktxOpenGLModuleHandle;
|
||||
|
||||
#define defaultGLGetProcAddress ((PFNGLGETPROCADDRESS)emscripten_GetProcAddress)
|
||||
#else
|
||||
#error "Don\'t know how to load symbols on this OS."
|
||||
#endif
|
||||
|
||||
static bool openGLLoaded = false;
|
||||
static const char* noloadmsg = "Could not load OpenGL command: %s!\n";
|
||||
|
||||
/* Define pointers for functions libktx is using. */
|
||||
struct glFuncPtrs gl;
|
||||
|
||||
#define GL_FUNCTION(type, func, required) \
|
||||
gl.func = (type)pfnGLGetProcAddress(#func); \
|
||||
if ( !gl.func && required) { \
|
||||
fprintf(stderr, noloadmsg, #func); \
|
||||
return KTX_NOT_FOUND; \
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
static HMODULE
|
||||
ktxFindOpenGL() {
|
||||
HMODULE module = 0;
|
||||
BOOL found;
|
||||
// Use GetModule not LoadLibrary so we only succeed if the process
|
||||
// has already loaded some OpenGL library.
|
||||
// Check current module to see if we are statically linked to GL.
|
||||
found = GetModuleHandleExA(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
(LPCSTR)ktxFindOpenGL,
|
||||
&module
|
||||
);
|
||||
if (found) {
|
||||
if (GetProcAddress(module, "glGetError") != NULL)
|
||||
return module;
|
||||
}
|
||||
// Not statically linked. See what dll the process has loaded.
|
||||
// Emulators probably also have opengl32.lib loaded so check that last.
|
||||
found = GetModuleHandleExA(
|
||||
0,
|
||||
"libGLESv2.dll",
|
||||
&module
|
||||
);
|
||||
if (found) return module;
|
||||
found = GetModuleHandleExA(
|
||||
0,
|
||||
"libGLES_CM.dll",
|
||||
&module
|
||||
);
|
||||
if (found) return module;
|
||||
found = GetModuleHandleExA(
|
||||
0,
|
||||
"opengl32.dll",
|
||||
&module
|
||||
);
|
||||
|
||||
if (found) {
|
||||
// Need wglGetProcAddr for non-OpenGL-2 functions.
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcast-function-type-mismatch"
|
||||
#endif
|
||||
pfnWglGetProcAddress =
|
||||
(PFNGLGETPROCADDRESS)GetProcAddress(module,
|
||||
"wglGetProcAddress");
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
if (pfnWglGetProcAddress != NULL)
|
||||
return module;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ktx_error_code_e
|
||||
ktxLoadOpenGLLibrary(void)
|
||||
{
|
||||
if (openGLLoaded)
|
||||
return KTX_SUCCESS;
|
||||
|
||||
// Look for OpenGL module and set up default GetProcAddress.
|
||||
ktxOpenGLModuleHandle = GetOpenGLModuleHandle(RTLD_LAZY);
|
||||
if (ktxOpenGLModuleHandle == NULL) {
|
||||
fprintf(stderr, "OpenGL lib not linked or loaded by application.\n");
|
||||
// Normal use is for this constructor to be called by an
|
||||
// application that has completed OpenGL initialization. In that
|
||||
// case the only cause for failure would be a coding error in our
|
||||
// library loading. The only other cause would be an application
|
||||
// calling GLUpload without having initialized OpenGL.
|
||||
#if defined(DEBUG)
|
||||
abort();
|
||||
#else
|
||||
return KTX_LIBRARY_NOT_LINKED; // So release version doesn't crash.
|
||||
#endif
|
||||
}
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup ktx\_glloader
|
||||
* @~English
|
||||
* @brief Load pointers for the GL functions used by the ktxTexture\*\_GLUpload functions.
|
||||
*
|
||||
* Should be called by an application before its first call to a
|
||||
* ktxTexture\*\_GLUpload function, passing a pointer to the GLGetProcAddress function
|
||||
* provided by whatever OpenGL framework it is using. For backward
|
||||
* compatibility, the ktxTexture\*\_GLUpload functions call this with a NULL pointer causing an
|
||||
* attempt to load the pointers from the program module using
|
||||
* @c dlsym (GNU/Linux, macOS), @c wglGetProcAddr and @c GetProcAddr (Windows)
|
||||
* or @c emscripten_GetProcAddress (Web). This works with the vast majority of
|
||||
* OpenGL implementations but issues have been seen on Fedora systems
|
||||
* particularly with NVIDIA hardware. For full robustness, applications should
|
||||
* call this function.
|
||||
*
|
||||
* @param [in] pfnGLGetProcAddress pointer to function for retrieving pointers
|
||||
* to GL functions. If NULL, retrieval is
|
||||
* attempted using system dependent generic
|
||||
* functions.
|
||||
*/
|
||||
ktx_error_code_e
|
||||
ktxLoadOpenGL(PFNGLGETPROCADDRESS pfnGLGetProcAddress)
|
||||
{
|
||||
if (openGLLoaded)
|
||||
return KTX_SUCCESS;
|
||||
|
||||
if (!pfnGLGetProcAddress) {
|
||||
ktx_error_code_e result = ktxLoadOpenGLLibrary();
|
||||
if (result != KTX_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
pfnGLGetProcAddress = defaultGLGetProcAddress;
|
||||
}
|
||||
|
||||
// Load function pointers
|
||||
|
||||
#include "gl_funclist.inl"
|
||||
|
||||
openGLLoaded = true;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
#undef GL_FUNCTION
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2017-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Declare pointers for OpenGL {,ES} functions.
|
||||
*
|
||||
* Dynamically retrieving pointers avoids apps or shared library builds having to link with OpenGL {,ES}
|
||||
* and avoids the need for compiling different versions of the libary for different OpenGL {,ES} versions.
|
||||
*/
|
||||
|
||||
#ifndef _GL_FUNCS_H_
|
||||
#define _GL_FUNCS_H_
|
||||
|
||||
#undef GL_GLEXT_PROTOTYPES // Just to be sure.
|
||||
#include "GL/glcorearb.h"
|
||||
#include "ktx.h"
|
||||
|
||||
extern ktx_error_code_e ktxLoadOpenGLLibrary(void);
|
||||
|
||||
#define GL_FUNCTION(type, fun, required) type fun;
|
||||
|
||||
extern struct glFuncPtrs {
|
||||
#include "gl_funclist.inl"
|
||||
} gl;
|
||||
|
||||
#undef GL_FUNCTION
|
||||
|
||||
#if !defined(NO_SHORTCUTS)
|
||||
// Macros to allow standard, i.e always present functions, to be called
|
||||
// by their prototype names.
|
||||
#define glBindTexture gl.glBindTexture
|
||||
#define glCompressedTexImage2D gl.glCompressedTexImage2D
|
||||
#define glCompressedTexSubImage2D gl.glCompressedTexSubImage2D
|
||||
#define glDeleteTextures gl.glDeleteTextures
|
||||
#define glGenTextures gl.glGenTextures
|
||||
#define glGetError gl.glGetError
|
||||
#define glGetIntegerv gl.glGetIntegerv
|
||||
#define glGetString(x) (const char*)gl.glGetString(x)
|
||||
#define glPixelStorei gl.glPixelStorei
|
||||
#define glTexImage2D gl.glTexImage2D
|
||||
#define glTexSubImage2D gl.glTexSubImage2D
|
||||
#define glTexParameteri gl.glTexParameteri
|
||||
#define glTexParameteriv gl.glTexParameteriv
|
||||
#endif
|
||||
|
||||
#endif /* _GL_FUNCS_H_ */
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
** Copyright 2025 The Khronos Group Inc.
|
||||
**
|
||||
** SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "GL/glcorearb.h"
|
||||
#include "GL/glext.h"
|
||||
#define GL_APIENTRY APIENTRY // Keep following included file happy.
|
||||
#include "GLES2/gl2ext.h" // For the ASTC 3D values
|
||||
|
||||
// The unsuffixed names are deprecated so not in glcorearb.h and it defines macros
|
||||
// which hide their definitions in glext.h. Rather than include gl.h define these in
|
||||
// terms of the equivalent extension names which are also in glext.h.
|
||||
#define GL_SR8 GL_SR8_EXT
|
||||
#define GL_SRG8 GL_SRG8_EXT
|
||||
// These are from GLES2/gl2.h.
|
||||
#define GL_LUMINANCE 0x1909
|
||||
#define GL_LUMINANCE_ALPHA 0x190A
|
||||
|
||||
// s/\(^[A-Z]\)/GL_\1/
|
||||
// s/\(GL_[A-Z0-9_]*\) .*$/ case \1: return "\1";/
|
||||
|
||||
const char* glFormatString(GLenum format)
|
||||
{
|
||||
static char retstr[11];
|
||||
|
||||
switch (format) {
|
||||
case 0: return "0 (Compressed)";
|
||||
case GL_DEPTH_COMPONENT: return "GL_DEPTH_COMPONENT";
|
||||
case GL_DEPTH_STENCIL: return "GL_DEPTH_STENCIL";
|
||||
case GL_STENCIL_INDEX: return "GL_STENCIL_INDEX";
|
||||
case GL_RED: return "GL_RED";
|
||||
case GL_RG: return "GL_RG";
|
||||
case GL_RGB: return "GL_RGB";
|
||||
case GL_RGBA: return "GL_RGBA";
|
||||
case GL_GREEN: return "GL_GREEN";
|
||||
case GL_BLUE: return "GL_BLUE";
|
||||
case GL_BGR: return "GL_BGR";
|
||||
case GL_BGRA: return "GL_BGRA";
|
||||
case GL_RED_INTEGER: return "GL_RED_INTEGER";
|
||||
case GL_GREEN_INTEGER: return "GL_GREEN_INTEGER";
|
||||
case GL_BLUE_INTEGER: return "GL_BLUE_INTEGER";
|
||||
case GL_RG_INTEGER: return "GL_RG_INTEGER";
|
||||
case GL_RGB_INTEGER: return "GL_RGB_INTEGER";
|
||||
case GL_RGBA_INTEGER: return "GL_RGBA_INTEGER";
|
||||
case GL_BGR_INTEGER: return "GL_BGR_INTEGER";
|
||||
case GL_BGRA_INTEGER: return "GL_BGRA_INTEGER";
|
||||
case GL_SRGB: return "GL_SRGB";
|
||||
case GL_SRGB_ALPHA: return "GL_SRGB_ALPHA";
|
||||
// Deprecated values.
|
||||
case GL_ALPHA: return "GL_ALPHA";
|
||||
case GL_LUMINANCE: return "GL_LUMINANCE";
|
||||
case GL_LUMINANCE_ALPHA: return "GL_LUMINANCE_ALPHA";
|
||||
default:
|
||||
(void)snprintf(retstr, sizeof(retstr), "%#x", format);
|
||||
return retstr;
|
||||
}
|
||||
}
|
||||
|
||||
const char* glInternalformatString(GLenum format)
|
||||
{
|
||||
static char retstr[11];
|
||||
|
||||
switch (format) {
|
||||
case GL_R8: return "GL_R8";
|
||||
case GL_R8_SNORM: return "GL_R8_SNORM";
|
||||
case GL_R16: return "GL_R16";
|
||||
case GL_R16_SNORM: return "GL_R16_SNORM";
|
||||
case GL_RG8: return "GL_RG8";
|
||||
case GL_RG8_SNORM: return "GL_RG8_SNORM";
|
||||
case GL_RG16: return "GL_RG16";
|
||||
case GL_RG16_SNORM: return "GL_RG16_SNORM";
|
||||
case GL_R3_G3_B2: return "GL_R3_G3_B2";
|
||||
case GL_RGB4: return "GL_RGB4";
|
||||
case GL_RGB5: return "GL_RGB5";
|
||||
case GL_RGB565: return "GL_RGB565";
|
||||
case GL_RGB8: return "GL_RGB8";
|
||||
case GL_RGB8_SNORM: return "GL_RGB8_SNORM";
|
||||
case GL_RGB10: return "GL_RGB10";
|
||||
case GL_RGB12: return "GL_RGB12";
|
||||
case GL_RGB16: return "GL_RGB16";
|
||||
case GL_RGB16_SNORM: return "GL_RGB16_SNORM";
|
||||
case GL_RGBA2: return "GL_RGBA2";
|
||||
case GL_RGBA4: return "GL_RGBA4";
|
||||
case GL_RGB5_A1: return "GL_RGB5_A1";
|
||||
case GL_RGBA8: return "GL_RGBA8";
|
||||
case GL_RGBA8_SNORM: return "GL_RGBA8_SNORM";
|
||||
case GL_RGB10_A2: return "GL_RGB10_A2";
|
||||
case GL_RGB10_A2UI: return "GL_RGB10_A2UI";
|
||||
case GL_RGBA12: return "GL_RGBA12";
|
||||
case GL_RGBA16: return "GL_RGBA16";
|
||||
case GL_RGBA16_SNORM: return "GL_RGBA16_SNORM";
|
||||
case GL_SR8: return "GL_SR8";
|
||||
case GL_SRG8: return "GL_SRG8";
|
||||
case GL_SRGB8: return "GL_SRGB8";
|
||||
case GL_SRGB8_ALPHA8: return "GL_SRGB8_ALPHA8";
|
||||
case GL_R16F: return "GL_R16F";
|
||||
case GL_RG16F: return "GL_RG16F";
|
||||
case GL_RGB16F: return "GL_RGB16F";
|
||||
case GL_RGBA16F: return "GL_RGBA16F";
|
||||
case GL_R32F: return "GL_R32F";
|
||||
case GL_RG32F: return "GL_RG32F";
|
||||
case GL_RGB32F: return "GL_RGB32F";
|
||||
case GL_RGBA32F: return "GL_RGBA32F";
|
||||
case GL_R11F_G11F_B10F: return "GL_R11F_G11F_B10F";
|
||||
case GL_RGB9_E5: return "GL_RGB9_E5";
|
||||
case GL_R8I: return "GL_R8I";
|
||||
case GL_R8UI: return "GL_R8UI";
|
||||
case GL_R16I: return "GL_R16I";
|
||||
case GL_R16UI: return "GL_R16UI";
|
||||
case GL_R32I: return "GL_R32I";
|
||||
case GL_R32UI: return "GL_R32UI";
|
||||
case GL_RG8I: return "GL_RG8I";
|
||||
case GL_RG8UI: return "GL_RG8UI";
|
||||
case GL_RG16I: return "GL_RG16I";
|
||||
case GL_RG16UI: return "GL_RG16UI";
|
||||
case GL_RG32I: return "GL_RG32I";
|
||||
case GL_RG32UI: return "GL_RG32UI";
|
||||
case GL_RGB8I: return "GL_RGB8I";
|
||||
case GL_RGB8UI: return "GL_RGB8UI";
|
||||
case GL_RGB16I: return "GL_RGB16I";
|
||||
case GL_RGB16UI: return "GL_RGB16UI";
|
||||
case GL_RGB32I: return "GL_RGB32I";
|
||||
case GL_RGB32UI: return "GL_RGB32UI";
|
||||
case GL_RGBA8I: return "GL_RGBA8I";
|
||||
case GL_RGBA8UI: return "GL_RGBA8UI";
|
||||
case GL_RGBA16I: return "GL_RGBA16I";
|
||||
case GL_RGBA16UI: return "GL_RGBA16UI";
|
||||
case GL_RGBA32I: return "GL_RGBA32I";
|
||||
case GL_RGBA32UI: return "GL_RGBA32UI";
|
||||
case GL_DEPTH_COMPONENT16: return "GL_DEPTH_COMPONENT16";
|
||||
case GL_DEPTH_COMPONENT24: return "GL_DEPTH_COMPONENT24";
|
||||
case GL_DEPTH_COMPONENT32: return "GL_DEPTH_COMPONENT32";
|
||||
case GL_DEPTH_COMPONENT32F: return "GL_DEPTH_COMPONENT32F";
|
||||
case GL_DEPTH24_STENCIL8: return "GL_DEPTH24_STENCIL8";
|
||||
case GL_DEPTH32F_STENCIL8: return "GL_DEPTH32F_STENCIL8";
|
||||
case GL_STENCIL_INDEX1: return "GL_STENCIL_INDEX1";
|
||||
case GL_STENCIL_INDEX4: return "GL_STENCIL_INDEX4";
|
||||
case GL_STENCIL_INDEX8: return "GL_STENCIL_INDEX8";
|
||||
case GL_STENCIL_INDEX16: return "GL_STENCIL_INDEX16";
|
||||
case GL_COMPRESSED_RED: return "GL_COMPRESSED_RED";
|
||||
case GL_COMPRESSED_RG: return "GL_COMPRESSED_RG";
|
||||
case GL_COMPRESSED_RGB: return "GL_COMPRESSED_RGB";
|
||||
case GL_COMPRESSED_RGBA: return "GL_COMPRESSED_RGBA";
|
||||
case GL_COMPRESSED_SRGB: return "GL_COMPRESSED_SRGB";
|
||||
case GL_COMPRESSED_SRGB_ALPHA: return "GL_COMPRESSED_SRGB_ALPHA";
|
||||
case GL_COMPRESSED_RED_RGTC1: return "GL_COMPRESSED_RED_RGTC1";
|
||||
case GL_COMPRESSED_SIGNED_RED_RGTC1: return "GL_COMPRESSED_SIGNED_RED_RGTC1";
|
||||
case GL_COMPRESSED_RG_RGTC2: return "GL_COMPRESSED_RG_RGTC2";
|
||||
case GL_COMPRESSED_SIGNED_RG_RGTC2: return "GL_COMPRESSED_SIGNED_RG_RGTC2";
|
||||
case GL_COMPRESSED_RGBA_BPTC_UNORM: return "GL_COMPRESSED_RGBA_BPTC_UNORM";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM";
|
||||
case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT";
|
||||
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT";
|
||||
case GL_COMPRESSED_RGB8_ETC2: return "GL_COMPRESSED_RGB8_ETC2";
|
||||
case GL_COMPRESSED_SRGB8_ETC2: return "GL_COMPRESSED_SRGB8_ETC2";
|
||||
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2";
|
||||
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2";
|
||||
case GL_COMPRESSED_RGBA8_ETC2_EAC: return "GL_COMPRESSED_RGBA8_ETC2_EAC";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC";
|
||||
case GL_COMPRESSED_R11_EAC: return "GL_COMPRESSED_R11_EAC";
|
||||
case GL_COMPRESSED_SIGNED_R11_EAC: return "GL_COMPRESSED_SIGNED_R11_EAC";
|
||||
case GL_COMPRESSED_RG11_EAC: return "GL_COMPRESSED_RG11_EAC";
|
||||
case GL_COMPRESSED_SIGNED_RG11_EAC: return "GL_COMPRESSED_SIGNED_RG11_EAC";
|
||||
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: return "GL_COMPRESSED_RGBA_ASTC_4x4_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: return "GL_COMPRESSED_RGBA_ASTC_5x4_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: return "GL_COMPRESSED_RGBA_ASTC_5x5_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: return "GL_COMPRESSED_RGBA_ASTC_6x5_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: return "GL_COMPRESSED_RGBA_ASTC_6x6_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: return "GL_COMPRESSED_RGBA_ASTC_8x5_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: return "GL_COMPRESSED_RGBA_ASTC_8x6_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: return "GL_COMPRESSED_RGBA_ASTC_8x8_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: return "GL_COMPRESSED_RGBA_ASTC_10x5_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: return "GL_COMPRESSED_RGBA_ASTC_10x6_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: return "GL_COMPRESSED_RGBA_ASTC_10x8_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return "GL_COMPRESSED_RGBA_ASTC_10x10_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return "GL_COMPRESSED_RGBA_ASTC_12x10_KHR";
|
||||
case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return "GL_COMPRESSED_RGBA_ASTC_12x12_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR";
|
||||
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
|
||||
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
|
||||
case GL_COMPRESSED_RGB_FXT1_3DFX: return "GL_COMPRESSED_RGB_FXT1_3DFX";
|
||||
case GL_COMPRESSED_RGBA_FXT1_3DFX: return "GL_COMPRESSED_RGBA_FXT1_3DFX";
|
||||
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: return "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT";
|
||||
case GL_COMPRESSED_RGBA_ASTC_3x3x3_OES: return "GL_COMPRESSED_RGBA_ASTC_3x3x3_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_4x3x3_OES: return "GL_COMPRESSED_RGBA_ASTC_4x3x3_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_4x4x3_OES: return "GL_COMPRESSED_RGBA_ASTC_4x4x3_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_4x4x4_OES: return "GL_COMPRESSED_RGBA_ASTC_4x4x4_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x4x4_OES: return "GL_COMPRESSED_RGBA_ASTC_5x4x4_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x5x4_OES: return "GL_COMPRESSED_RGBA_ASTC_5x5x4_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_5x5x5_OES: return "GL_COMPRESSED_RGBA_ASTC_5x5x5_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x5x5_OES: return "GL_COMPRESSED_RGBA_ASTC_6x5x5_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x6x5_OES: return "GL_COMPRESSED_RGBA_ASTC_6x6x5_OES";
|
||||
case GL_COMPRESSED_RGBA_ASTC_6x6x6_OES: return "GL_COMPRESSED_RGBA_ASTC_6x6x6_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES";
|
||||
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES";
|
||||
case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: return "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG";
|
||||
case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: return "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG";
|
||||
case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: return "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG";
|
||||
case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: return "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG";
|
||||
case GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT: return "GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT";
|
||||
case GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT: return "GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG";
|
||||
case GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG";
|
||||
case GL_ETC1_RGB8_OES: return "GL_ETC1_RGB8_OES";
|
||||
// Deprecated values.
|
||||
case GL_ALPHA8_EXT: return "GL_ALPHA8_EXT";
|
||||
case GL_LUMINANCE4_ALPHA4_EXT: return "GL_LUMINANCE4_ALPHA4_EXT";
|
||||
case GL_LUMINANCE8_ALPHA8_EXT: return "GL_LUMINANCE8_ALPHA8_EXT";
|
||||
case GL_LUMINANCE8_EXT: return "GL_LUMINANCE8_EXT";
|
||||
default:
|
||||
(void)snprintf(retstr, sizeof(retstr), "%#x", format);
|
||||
return retstr;
|
||||
}
|
||||
}
|
||||
|
||||
const char* glTypeString(GLenum type)
|
||||
{
|
||||
static char retstr[11];
|
||||
|
||||
switch (type) {
|
||||
case 0: return "0 (Compressed)";
|
||||
case GL_UNSIGNED_BYTE: return "GL_UNSIGNED_BYTE";
|
||||
case GL_BYTE: return "GL_BYTE";
|
||||
case GL_UNSIGNED_SHORT: return "GL_UNSIGNED_SHORT";
|
||||
case GL_SHORT: return "GL_SHORT";
|
||||
case GL_UNSIGNED_INT: return "GL_UNSIGNED_INT";
|
||||
case GL_INT: return "GL_INT";
|
||||
case GL_HALF_FLOAT: return "GL_HALF_FLOAT";
|
||||
case GL_FLOAT: return "GL_FLOAT";
|
||||
case GL_UNSIGNED_BYTE_3_3_2: return "GL_UNSIGNED_BYTE_3_3_2";
|
||||
case GL_UNSIGNED_BYTE_2_3_3_REV: return "GL_UNSIGNED_BYTE_2_3_3_REV";
|
||||
case GL_UNSIGNED_SHORT_5_6_5: return "GL_UNSIGNED_SHORT_5_6_5";
|
||||
case GL_UNSIGNED_SHORT_5_6_5_REV: return "GL_UNSIGNED_SHORT_5_6_5_REV";
|
||||
case GL_UNSIGNED_SHORT_4_4_4_4: return "GL_UNSIGNED_SHORT_4_4_4_4";
|
||||
case GL_UNSIGNED_SHORT_4_4_4_4_REV: return "GL_UNSIGNED_SHORT_4_4_4_4_REV";
|
||||
case GL_UNSIGNED_SHORT_5_5_5_1: return "GL_UNSIGNED_SHORT_5_5_5_1";
|
||||
case GL_UNSIGNED_SHORT_1_5_5_5_REV: return "GL_UNSIGNED_SHORT_1_5_5_5_REV";
|
||||
case GL_UNSIGNED_INT_8_8_8_8: return "GL_UNSIGNED_INT_8_8_8_8";
|
||||
case GL_UNSIGNED_INT_8_8_8_8_REV: return "GL_UNSIGNED_INT_8_8_8_8_REV";
|
||||
case GL_UNSIGNED_INT_10_10_10_2: return "GL_UNSIGNED_INT_10_10_10_2";
|
||||
case GL_UNSIGNED_INT_2_10_10_10_REV: return "GL_UNSIGNED_INT_2_10_10_10_REV";
|
||||
case GL_UNSIGNED_INT_24_8: return "GL_UNSIGNED_INT_24_8";
|
||||
case GL_UNSIGNED_INT_10F_11F_11F_REV: return "GL_UNSIGNED_INT_10F_11F_11F_REV";
|
||||
case GL_UNSIGNED_INT_5_9_9_9_REV: return "GL_UNSIGNED_INT_5_9_9_9_REV";
|
||||
case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return "GL_FLOAT_32_UNSIGNED_INT_24_8_REV";
|
||||
default:
|
||||
(void)snprintf(retstr, sizeof(retstr), "%#x", type);
|
||||
return retstr;
|
||||
}
|
||||
}
|
||||
|
||||
+1087
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,628 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Functions for creating and using a hash list of key-value
|
||||
* pairs.
|
||||
*
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
// This is to avoid compile warnings. strlen is defined as returning
|
||||
// size_t and is used by the uthash macros. This avoids having to
|
||||
// make changes to uthash and a bunch of casts in this file. The
|
||||
// casts would be required because the key and value lengths in KTX
|
||||
// are specified as 4 byte quantities so we can't change _keyAndValue
|
||||
// below to use size_t.
|
||||
#define strlen(x) ((unsigned int)strlen(x))
|
||||
|
||||
#include "uthash.h"
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @struct ktxKVListEntry
|
||||
* @brief Hash list entry structure
|
||||
*/
|
||||
typedef struct ktxKVListEntry {
|
||||
unsigned int keyLen; /*!< Length of the key */
|
||||
char* key; /*!< Pointer to key string */
|
||||
unsigned int valueLen; /*!< Length of the value */
|
||||
void* value; /*!< Pointer to the value */
|
||||
UT_hash_handle hh; /*!< handle used by UT hash */
|
||||
} ktxKVListEntry;
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Construct an empty hash list for storing key-value pairs.
|
||||
*
|
||||
* @param [in] pHead pointer to the location to write the list head.
|
||||
*/
|
||||
void
|
||||
ktxHashList_Construct(ktxHashList* pHead)
|
||||
{
|
||||
*pHead = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Construct a hash list by copying another.
|
||||
*
|
||||
* @param [in] pHead pointer to head of the list.
|
||||
* @param [in] orig head of the original hash list.
|
||||
*/
|
||||
void
|
||||
ktxHashList_ConstructCopy(ktxHashList* pHead, ktxHashList orig)
|
||||
{
|
||||
ktxHashListEntry* entry = orig;
|
||||
*pHead = NULL;
|
||||
for (; entry != NULL; entry = ktxHashList_Next(entry)) {
|
||||
(void)ktxHashList_AddKVPair(pHead,
|
||||
entry->key, entry->valueLen, entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Destruct a hash list.
|
||||
*
|
||||
* All memory associated with the hash list's keys and values
|
||||
* is freed.
|
||||
*
|
||||
* @param [in] pHead pointer to the hash list to be destroyed.
|
||||
*/
|
||||
void
|
||||
ktxHashList_Destruct(ktxHashList* pHead)
|
||||
{
|
||||
ktxKVListEntry* kv;
|
||||
ktxKVListEntry* head = *pHead;
|
||||
|
||||
for(kv = head; kv != NULL;) {
|
||||
ktxKVListEntry* tmp = (ktxKVListEntry*)kv->hh.next;
|
||||
HASH_DELETE(hh, head, kv);
|
||||
free(kv);
|
||||
kv = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Create an empty hash list for storing key-value pairs.
|
||||
*
|
||||
* @param [in,out] ppHl address of a variable in which to set a pointer to
|
||||
* the newly created hash list.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
* @exception KTX_OUT_OF_MEMORY if not enough memory.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_Create(ktxHashList** ppHl)
|
||||
{
|
||||
ktxHashList* hl = (ktxHashList*)malloc(sizeof (ktxKVListEntry*));
|
||||
if (hl == NULL)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
|
||||
ktxHashList_Construct(hl);
|
||||
*ppHl = hl;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Create a copy of a hash list.
|
||||
*
|
||||
* @param [in,out] ppHl address of a variable in which to set a pointer to
|
||||
* the newly created hash list.
|
||||
* @param [in] orig head of the ktxHashList to copy.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
* @exception KTX_OUT_OF_MEMORY if not enough memory.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_CreateCopy(ktxHashList** ppHl, ktxHashList orig)
|
||||
{
|
||||
ktxHashList* hl = (ktxHashList*)malloc(sizeof (ktxKVListEntry*));
|
||||
if (hl == NULL)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
|
||||
ktxHashList_ConstructCopy(hl, orig);
|
||||
*ppHl = hl;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Destroy a hash list.
|
||||
*
|
||||
* All memory associated with the hash list's keys and values
|
||||
* is freed. The hash list is also freed.
|
||||
*
|
||||
* @param [in] pHead pointer to the hash list to be destroyed.
|
||||
*/
|
||||
void
|
||||
ktxHashList_Destroy(ktxHashList* pHead)
|
||||
{
|
||||
ktxHashList_Destruct(pHead);
|
||||
free(pHead);
|
||||
}
|
||||
|
||||
#if !__clang__ && __GNUC__ // Grumble clang grumble
|
||||
// These are in uthash.h macros. I don't want to change that file.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Add a key value pair to a hash list.
|
||||
*
|
||||
* The value can be empty, i.e, its length can be 0.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
* @param [in] key pointer to the UTF8 NUL-terminated string to be used as the key.
|
||||
* @param [in] valueLen the number of bytes of data in @p value.
|
||||
* @param [in] value pointer to the bytes of data constituting the value.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
* @exception KTX_INVALID_VALUE if @p pHead, @p key or @p value are NULL, @p key is an
|
||||
* empty string or @p valueLen == 0.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_AddKVPair(ktxHashList* pHead, const char* key, unsigned int valueLen, const void* value)
|
||||
{
|
||||
if (pHead && key && (valueLen == 0 || value)) {
|
||||
unsigned int keyLen = (unsigned int)strlen(key) + 1;
|
||||
ktxKVListEntry* kv;
|
||||
|
||||
if (keyLen == 1)
|
||||
return KTX_INVALID_VALUE; /* Empty string */
|
||||
|
||||
/* Allocate all the memory as a block */
|
||||
kv = (ktxKVListEntry*)malloc(sizeof(ktxKVListEntry) + keyLen + valueLen);
|
||||
/* Put key first */
|
||||
kv->key = (char *)kv + sizeof(ktxKVListEntry);
|
||||
kv->keyLen = keyLen;
|
||||
memcpy(kv->key, key, keyLen);
|
||||
/* then value */
|
||||
kv->valueLen = valueLen;
|
||||
if (valueLen > 0) {
|
||||
kv->value = kv->key + keyLen;
|
||||
memcpy(kv->value, value, valueLen);
|
||||
} else {
|
||||
kv->value = 0;
|
||||
}
|
||||
|
||||
HASH_ADD_KEYPTR( hh, *pHead, kv->key, kv->keyLen-1, kv);
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Delete a key value pair in a hash list.
|
||||
*
|
||||
* Is a nop if the key is not in the hash.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
* @param [in] key pointer to the UTF8 NUL-terminated string to be used as the key.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
* @exception KTX_INVALID_VALUE if @p pHead is NULL or @p key is an empty
|
||||
* string.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_DeleteKVPair(ktxHashList* pHead, const char* key)
|
||||
{
|
||||
if (pHead && key) {
|
||||
ktxKVListEntry* kv;
|
||||
|
||||
HASH_FIND_STR( *pHead, key, kv ); /* kv: pointer to target entry. */
|
||||
if (kv != NULL)
|
||||
HASH_DEL(*pHead, kv);
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Delete an entry from a hash list.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
* @param [in] pEntry pointer to the ktxHashListEntry to delete.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
* @exception KTX_INVALID_VALUE if @p pHead is NULL or @p key is an empty
|
||||
* string.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_DeleteEntry(ktxHashList* pHead, ktxHashListEntry* pEntry)
|
||||
{
|
||||
if (pHead && pEntry) {
|
||||
HASH_DEL(*pHead, pEntry);
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Looks up a key in a hash list and returns the entry.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
* @param [in] key pointer to a UTF8 NUL-terminated string to find.
|
||||
* @param [in,out] ppEntry @p *ppEntry is set to the point at the
|
||||
* ktxHashListEntry.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE if @p This, @p key or @p pValueLen or @p ppValue
|
||||
* is NULL.
|
||||
* @exception KTX_NOT_FOUND an entry matching @p key was not found.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_FindEntry(ktxHashList* pHead, const char* key,
|
||||
ktxHashListEntry** ppEntry)
|
||||
{
|
||||
if (pHead && key) {
|
||||
ktxKVListEntry* kv;
|
||||
|
||||
HASH_FIND_STR( *pHead, key, kv ); /* kv: output pointer */
|
||||
|
||||
if (kv) {
|
||||
*ppEntry = kv;
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return KTX_NOT_FOUND;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Looks up a key in a hash list and returns the value.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
* @param [in] key pointer to a UTF8 NUL-terminated string to find.
|
||||
* @param [in,out] pValueLen @p *pValueLen is set to the number of bytes of
|
||||
* data in the returned value.
|
||||
* @param [in,out] ppValue @p *ppValue is set to the point to the value for
|
||||
* @p key.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE if @p This, @p key or @p pValueLen or @p ppValue
|
||||
* is NULL.
|
||||
* @exception KTX_NOT_FOUND an entry matching @p key was not found.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_FindValue(ktxHashList *pHead, const char* key, unsigned int* pValueLen, void** ppValue)
|
||||
{
|
||||
if (pValueLen && ppValue) {
|
||||
ktxHashListEntry* pEntry;
|
||||
KTX_error_code result;
|
||||
|
||||
result = ktxHashList_FindEntry(pHead, key, &pEntry);
|
||||
if (result == KTX_SUCCESS) {
|
||||
ktxHashListEntry_GetValue(pEntry, pValueLen, ppValue);
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return result;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
#if !__clang__ && __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Returns the next entry in a ktxHashList.
|
||||
*
|
||||
* Use for iterating through the list:
|
||||
* @code
|
||||
* ktxHashListEntry* entry;
|
||||
* for (entry = listHead; entry != NULL; entry = ktxHashList_Next(entry)) {
|
||||
* ...
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* Note
|
||||
*
|
||||
* @param [in] entry pointer to a hash list entry. Note that a ktxHashList*,
|
||||
* i.e. the list head, is also a pointer to an entry so
|
||||
* can be passed to this function.
|
||||
*
|
||||
* @return a pointer to the next entry or NULL.
|
||||
*
|
||||
*/
|
||||
ktxHashListEntry*
|
||||
ktxHashList_Next(ktxHashListEntry* entry)
|
||||
{
|
||||
if (entry) {
|
||||
return ((ktxKVListEntry*)entry)->hh.next;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Serialize a hash list to a block of data suitable for writing
|
||||
* to a file.
|
||||
*
|
||||
* The caller is responsible for freeing the data block returned by this
|
||||
* function.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
* @param [in,out] pKvdLen @p *pKvdLen is set to the number of bytes of
|
||||
* data in the returned data block.
|
||||
* @param [in,out] ppKvd @p *ppKvd is set to the point to the block of
|
||||
* memory containing the serialized data or
|
||||
* NULL. if the hash list is empty.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE if @p This, @p pKvdLen or @p ppKvd is NULL.
|
||||
* @exception KTX_OUT_OF_MEMORY there was not enough memory to serialize the
|
||||
* data.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_Serialize(ktxHashList* pHead,
|
||||
unsigned int* pKvdLen, unsigned char** ppKvd)
|
||||
{
|
||||
|
||||
if (pHead && pKvdLen && ppKvd) {
|
||||
ktxKVListEntry* kv;
|
||||
unsigned int bytesOfKeyValueData = 0;
|
||||
unsigned int keyValueLen;
|
||||
unsigned char* sd;
|
||||
char padding[4] = {0, 0, 0, 0};
|
||||
|
||||
for (kv = *pHead; kv != NULL; kv = kv->hh.next) {
|
||||
/* sizeof(sd) is to make space to write keyAndValueByteSize */
|
||||
keyValueLen = kv->keyLen + kv->valueLen + sizeof(ktx_uint32_t);
|
||||
/* Add valuePadding */
|
||||
keyValueLen = _KTX_PAD4(keyValueLen);
|
||||
bytesOfKeyValueData += keyValueLen;
|
||||
}
|
||||
|
||||
if (bytesOfKeyValueData == 0) {
|
||||
*pKvdLen = 0;
|
||||
*ppKvd = NULL;
|
||||
} else {
|
||||
sd = malloc(bytesOfKeyValueData);
|
||||
if (!sd)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
|
||||
*pKvdLen = bytesOfKeyValueData;
|
||||
*ppKvd = sd;
|
||||
|
||||
for (kv = *pHead; kv != NULL; kv = kv->hh.next) {
|
||||
int padLen;
|
||||
|
||||
keyValueLen = kv->keyLen + kv->valueLen;
|
||||
*(ktx_uint32_t*)sd = keyValueLen;
|
||||
sd += sizeof(ktx_uint32_t);
|
||||
memcpy(sd, kv->key, kv->keyLen);
|
||||
sd += kv->keyLen;
|
||||
if (kv->valueLen > 0)
|
||||
memcpy(sd, kv->value, kv->valueLen);
|
||||
sd += kv->valueLen;
|
||||
padLen = _KTX_PAD4_LEN(keyValueLen);
|
||||
memcpy(sd, padding, padLen);
|
||||
sd += padLen;
|
||||
}
|
||||
}
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
|
||||
int sort_by_key_codepoint(ktxKVListEntry* a, ktxKVListEntry* b) {
|
||||
return strcmp(a->key, b->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Sort a hash list in order of the UTF8 codepoints.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE if @p This is NULL.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_Sort(ktxHashList* pHead)
|
||||
{
|
||||
if (pHead) {
|
||||
//ktxKVListEntry* kv = (ktxKVListEntry*)pHead;
|
||||
|
||||
HASH_SORT(*pHead, sort_by_key_codepoint);
|
||||
return KTX_SUCCESS;
|
||||
} else {
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashList @public
|
||||
* @~English
|
||||
* @brief Construct a hash list from a block of serialized key-value
|
||||
* data read from a file.
|
||||
* @note The bytes of the 32-bit key-value lengths within the serialized data
|
||||
* are expected to be in native endianness.
|
||||
*
|
||||
* @param [in] pHead pointer to the head of the target hash list.
|
||||
* @param [in] kvdLen the length of the serialized key-value data.
|
||||
* @param [in] pKvd pointer to the serialized key-value data.
|
||||
* table.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
*
|
||||
* @exception KTX_INVALID_OPERATION if @p pHead does not point to an empty list.
|
||||
* @exception KTX_INVALID_VALUE if @p pKvd or @p pHt is NULL or kvdLen == 0.
|
||||
* @exception KTX_OUT_OF_MEMORY there was not enough memory to create the hash
|
||||
* table.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashList_Deserialize(ktxHashList* pHead, unsigned int kvdLen, void* pKvd)
|
||||
{
|
||||
char* src = pKvd;
|
||||
KTX_error_code result;
|
||||
|
||||
if (kvdLen == 0 || pKvd == NULL || pHead == NULL)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
if (*pHead != NULL)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
result = KTX_SUCCESS;
|
||||
while (result == KTX_SUCCESS && src < (char *)pKvd + kvdLen) {
|
||||
if (src + 6 > (char *)pKvd + kvdLen) {
|
||||
// Not enough space for another entry
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
char* key;
|
||||
unsigned int keyLen, valueLen;
|
||||
void* value;
|
||||
ktx_uint32_t keyAndValueByteSize = *((ktx_uint32_t*)src);
|
||||
|
||||
if (src + 4 + keyAndValueByteSize > (char *)pKvd + kvdLen) {
|
||||
// Not enough space for this entry
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
src += sizeof(keyAndValueByteSize);
|
||||
key = src;
|
||||
keyLen = 0;
|
||||
|
||||
while (keyLen < keyAndValueByteSize && key[keyLen] != '\0') keyLen++;
|
||||
|
||||
if (keyLen == keyAndValueByteSize || key[keyLen] != '\0') {
|
||||
// Missing NULL terminator or no value
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (keyLen >= 3 && key[0] == '\xEF' && key[1] == '\xBB' && key[2] == '\xBF') {
|
||||
// Forbidden BOM
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
|
||||
keyLen += 1;
|
||||
value = key + keyLen;
|
||||
|
||||
valueLen = keyAndValueByteSize - keyLen;
|
||||
result = ktxHashList_AddKVPair(pHead, key, valueLen,
|
||||
valueLen > 0 ? value : NULL);
|
||||
if (result == KTX_SUCCESS) {
|
||||
src += _KTX_PAD4(keyAndValueByteSize);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashListEntry @public
|
||||
* @~English
|
||||
* @brief Return the key of a ktxHashListEntry
|
||||
*
|
||||
* @param [in] This The target hash list entry.
|
||||
* @param [in,out] pKeyLen @p *pKeyLen is set to the byte length of
|
||||
* the returned key.
|
||||
* @param [in,out] ppKey @p *ppKey is set to the point to the value of
|
||||
* @p the key.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE if @p pKvd or @p pHt is NULL or kvdLen == 0.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashListEntry_GetKey(ktxHashListEntry* This,
|
||||
unsigned int* pKeyLen, char** ppKey)
|
||||
{
|
||||
if (pKeyLen && ppKey) {
|
||||
ktxKVListEntry* kv = (ktxKVListEntry*)This;
|
||||
*pKeyLen = kv->keyLen;
|
||||
*ppKey = kv->key;
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxHashListEntry @public
|
||||
* @~English
|
||||
* @brief Return the value from a ktxHashListEntry
|
||||
*
|
||||
* @param [in] This The target hash list entry.
|
||||
* @param [in,out] pValueLen @p *pValueLen is set to the number of bytes of
|
||||
* data in the returned value.
|
||||
* @param [in,out] ppValue @p *ppValue is set to point to the value of
|
||||
* of the target entry.
|
||||
*
|
||||
* @return KTX_SUCCESS or one of the following error codes.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE if @p pKvd or @p pHt is NULL or kvdLen == 0.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxHashListEntry_GetValue(ktxHashListEntry* This,
|
||||
unsigned int* pValueLen, void** ppValue)
|
||||
{
|
||||
if (pValueLen && ppValue) {
|
||||
ktxKVListEntry* kv = (ktxKVListEntry*)This;
|
||||
*pValueLen = kv->valueLen;
|
||||
*ppValue = kv->valueLen > 0 ? kv->value : NULL;
|
||||
return KTX_SUCCESS;
|
||||
} else
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
+1380
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
; Copyright 2019-2020 Mark Callow
|
||||
; SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
; Export internal functions used by internal test programs and the
|
||||
; validator. Using this file avoids having to decorate those internal
|
||||
; functions or updating such decorations as the tests evolve. Updating
|
||||
; this feels less obnoxious.
|
||||
|
||||
LIBRARY
|
||||
EXPORTS
|
||||
?basis_get_bytes_per_block_or_pixel@basist@@YAIW4transcoder_texture_format@1@@Z
|
||||
?basis_transcoder_format_is_uncompressed@basist@@YA_NW4transcoder_texture_format@1@@Z
|
||||
?basis_get_uncompressed_bytes_per_pixel@basist@@YAIW4transcoder_texture_format@1@@Z
|
||||
?validate_header@basisu_transcoder@basist@@QEBA_NPEBXI@Z
|
||||
?get_total_images@basisu_transcoder@basist@@QEBAIPEBXI@Z
|
||||
?get_image_level_desc@basisu_transcoder@basist@@QEBA_NPEBXIIIAEAI11@Z
|
||||
?get_image_info@basisu_transcoder@basist@@QEBA_NPEBXIAEAUbasisu_image_info@2@I@Z
|
||||
?get_image_level_info@basisu_transcoder@basist@@QEBA_NPEBXIAEAUbasisu_image_level_info@2@II@Z
|
||||
?start_transcoding@basisu_transcoder@basist@@QEAA_NPEBXI@Z
|
||||
?transcode_image_level@basisu_transcoder@basist@@QEBA_NPEBXIIIPEAXIW4transcoder_texture_format@2@IIPEAUbasisu_transcoder_state@2@I@Z
|
||||
createDFDCompressed
|
||||
createDFDDepthStencil
|
||||
createDFDUnpacked
|
||||
createDFDPacked
|
||||
findMapping
|
||||
getPrimaries
|
||||
interpretDFD
|
||||
isProhibitedFormat
|
||||
isValidFormat
|
||||
ktxCheckHeader1_
|
||||
ktxMemStream_construct
|
||||
ktxMemStream_construct_ro
|
||||
ktxMemStream_destruct
|
||||
ktxMemStream_getdata
|
||||
ktxTexture_calcImageSize
|
||||
ktxTexture_calcLevelSize
|
||||
ktxTexture1_Destroy
|
||||
ktxTexture1_SetImageFromMemory
|
||||
ktxTexture1_WriteToMemory
|
||||
ktxTexture1_calcLevelOffset
|
||||
ktxTexture1_destruct
|
||||
ktxTexture1_glTypeSize
|
||||
ktxTexture2_GetImageOffset
|
||||
ktxTexture2_calcLevelOffset
|
||||
ktxTexture2_destruct
|
||||
reconstructDFDBytesPlanesFromSamples
|
||||
stringToVkFormat
|
||||
vk2dfd
|
||||
vkFormatString
|
||||
vkFormatTypeSize
|
||||
@@ -0,0 +1,50 @@
|
||||
; Copyright 2019-2020 Mark Callow
|
||||
; SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
; Export internal functions used by internal test programs and the
|
||||
; validator. Using this file avoids having to decorate those internal
|
||||
; functions or updating such decorations as the tests evolve. Updating
|
||||
; this feels less obnoxious.
|
||||
|
||||
LIBRARY libktx
|
||||
EXPORTS
|
||||
_ZN6basist34basis_get_bytes_per_block_or_pixelENS_25transcoder_texture_formatE
|
||||
_ZN6basist39basis_transcoder_format_is_uncompressedENS_25transcoder_texture_formatE
|
||||
_ZN6basist38basis_get_uncompressed_bytes_per_pixelENS_25transcoder_texture_formatE
|
||||
_ZNK6basist17basisu_transcoder15validate_headerEPKvj
|
||||
_ZNK6basist17basisu_transcoder16get_total_imagesEPKvj
|
||||
_ZNK6basist17basisu_transcoder20get_image_level_descEPKvjjjRjS3_S3_
|
||||
_ZNK6basist17basisu_transcoder14get_image_infoEPKvjRNS_17basisu_image_infoEj
|
||||
_ZNK6basist17basisu_transcoder20get_image_level_infoEPKvjRNS_23basisu_image_level_infoEjj
|
||||
_ZN6basist17basisu_transcoder17start_transcodingEPKvj
|
||||
_ZNK6basist17basisu_transcoder21transcode_image_levelEPKvjjjPvjNS_25transcoder_texture_formatEjjPNS_23basisu_transcoder_stateEj
|
||||
createDFDCompressed
|
||||
createDFDDepthStencil
|
||||
createDFDUnpacked
|
||||
createDFDPacked
|
||||
findMapping
|
||||
getPrimaries
|
||||
interpretDFD
|
||||
isProhibitedFormat
|
||||
isValidFormat
|
||||
ktxCheckHeader1_
|
||||
ktxMemStream_construct
|
||||
ktxMemStream_construct_ro
|
||||
ktxMemStream_destruct
|
||||
ktxMemStream_getdata
|
||||
ktxTexture_calcImageSize
|
||||
ktxTexture_calcLevelSize
|
||||
ktxTexture1_Destroy
|
||||
ktxTexture1_SetImageFromMemory
|
||||
ktxTexture1_WriteToMemory
|
||||
ktxTexture1_calcLevelOffset
|
||||
ktxTexture1_destruct
|
||||
ktxTexture1_glTypeSize
|
||||
ktxTexture2_GetImageOffset
|
||||
ktxTexture2_calcLevelOffset
|
||||
ktxTexture2_destruct
|
||||
reconstructDFDBytesPlanesFromSamples
|
||||
stringToVkFormat
|
||||
vk2dfd
|
||||
vkFormatString
|
||||
vkFormatTypeSize
|
||||
@@ -0,0 +1,30 @@
|
||||
; Copyright 2019-2020 Mark Callow
|
||||
; SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
; Export internal functions used by internal test programs and the
|
||||
; validator. Using this file avoids having to decorate those internal
|
||||
; functions or updating such decorations as the tests evolve. Updating
|
||||
; this feels less obnoxious.
|
||||
|
||||
LIBRARY
|
||||
EXPORTS
|
||||
??1Resampler@basisu@@QEAA@XZ
|
||||
??0Resampler@basisu@@QEAA@HHHHW4Boundary_Op@01@MMPEBDPEAUContrib_List@01@2MMMM@Z
|
||||
?put_line@Resampler@basisu@@QEAA_NPEBM@Z
|
||||
?get_line@Resampler@basisu@@QEAAPEBMXZ
|
||||
?calc@image_metrics@basisu@@QEAAXAEBVimage@2@0II_N1@Z
|
||||
?compute_ssim@basisu@@YA?AV?$vec@$03M@1@AEBVimage@1@0_N1@Z
|
||||
?increase_capacity@elemental_vector@basisu@@QEAA_NI_NIP6AXPEAX1I@Z0@Z
|
||||
?swizzle_to_rgba@@YAXPEAE0I_KQEAW4swizzle_e@@@Z
|
||||
appendLibId
|
||||
dfdToStringChannelId
|
||||
dfdToStringColorModel
|
||||
dfdToStringColorPrimaries
|
||||
dfdToStringDescriptorType
|
||||
dfdToStringFlagsBit
|
||||
dfdToStringSampleDatatypeQualifiersBit
|
||||
dfdToStringTransferFunction
|
||||
dfdToStringVendorID
|
||||
dfdToStringVersionNumber
|
||||
ktxBUImageFlagsBitString
|
||||
ktxTexture2_constructCopy
|
||||
@@ -0,0 +1,30 @@
|
||||
; Copyright 2019-2020 Mark Callow
|
||||
; SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
; Export internal functions used by internal test programs and the
|
||||
; validator. Using this file avoids having to decorate those internal
|
||||
; functions or updating such decorations as the tests evolve. Updating
|
||||
; this feels less obnoxious.
|
||||
|
||||
LIBRARY libktx
|
||||
EXPORTS
|
||||
_ZN6basisu9ResamplerD1Ev
|
||||
_ZN6basisu9ResamplerC1EiiiiNS0_11Boundary_OpEffPKcPNS0_12Contrib_ListES5_ffff
|
||||
_ZN6basisu9Resampler8put_lineEPKf
|
||||
_ZN6basisu9Resampler8get_lineEv
|
||||
_ZN6basisu13image_metrics4calcERKNS_5imageES3_jjbb
|
||||
_ZN6basisu12compute_ssimERKNS_5imageES2_bb
|
||||
_ZN6basisu16elemental_vector17increase_capacityEjbjPFvPvS1_jEb
|
||||
_Z15swizzle_to_rgbaPhS_jyP9swizzle_e
|
||||
appendLibId
|
||||
dfdToStringChannelId
|
||||
dfdToStringColorModel
|
||||
dfdToStringColorPrimaries
|
||||
dfdToStringDescriptorType
|
||||
dfdToStringFlagsBit
|
||||
dfdToStringSampleDatatypeQualifiersBit
|
||||
dfdToStringTransferFunction
|
||||
dfdToStringVendorID
|
||||
dfdToStringVersionNumber
|
||||
ktxBUImageFlagsBitString
|
||||
ktxTexture2_constructCopy
|
||||
@@ -0,0 +1,348 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Author: Mark Callow from original code by Georg Kolling
|
||||
*/
|
||||
|
||||
#ifndef KTXINT_H
|
||||
#define KTXINT_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* Define this to include the ETC unpack software in the library. */
|
||||
#ifndef SUPPORT_SOFTWARE_ETC_UNPACK
|
||||
/* Include for all GL versions because have seen OpenGL ES 3
|
||||
* implementaions that do not support ETC1 (ARM Mali emulator v1.0)!
|
||||
*/
|
||||
#define SUPPORT_SOFTWARE_ETC_UNPACK 1
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#define QUOTE(x) #x
|
||||
#define STR(x) QUOTE(x)
|
||||
|
||||
#define KTX2_IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }
|
||||
#define KTX2_HEADER_SIZE (80)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief used to pass GL context capabilites to subroutines.
|
||||
*/
|
||||
#define _KTX_NO_R16_FORMATS 0x0
|
||||
#define _KTX_R16_FORMATS_NORM 0x1
|
||||
#define _KTX_R16_FORMATS_SNORM 0x2
|
||||
#define _KTX_ALL_R16_FORMATS (_KTX_R16_FORMATS_NORM | _KTX_R16_FORMATS_SNORM)
|
||||
extern GLint _ktxR16Formats;
|
||||
extern GLboolean _ktxSupportsSRGB;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief KTX file header.
|
||||
*
|
||||
* See the KTX specification for descriptions.
|
||||
*/
|
||||
typedef struct KTX_header {
|
||||
ktx_uint8_t identifier[12];
|
||||
ktx_uint32_t endianness;
|
||||
ktx_uint32_t glType;
|
||||
ktx_uint32_t glTypeSize;
|
||||
ktx_uint32_t glFormat;
|
||||
ktx_uint32_t glInternalformat;
|
||||
ktx_uint32_t glBaseInternalformat;
|
||||
ktx_uint32_t pixelWidth;
|
||||
ktx_uint32_t pixelHeight;
|
||||
ktx_uint32_t pixelDepth;
|
||||
ktx_uint32_t numberOfArrayElements;
|
||||
ktx_uint32_t numberOfFaces;
|
||||
ktx_uint32_t numberOfMipLevels;
|
||||
ktx_uint32_t bytesOfKeyValueData;
|
||||
} KTX_header;
|
||||
|
||||
/* This will cause compilation to fail if the struct size doesn't match */
|
||||
typedef int KTX_header_SIZE_ASSERT [sizeof(KTX_header) == KTX_HEADER_SIZE];
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief 32-bit KTX 2 index entry.
|
||||
*/
|
||||
typedef struct ktxIndexEntry32 {
|
||||
ktx_uint32_t byteOffset; /*!< Offset of item from start of file. */
|
||||
ktx_uint32_t byteLength; /*!< Number of bytes of data in the item. */
|
||||
} ktxIndexEntry32;
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief 64-bit KTX 2 index entry.
|
||||
*/
|
||||
typedef struct ktxIndexEntry64 {
|
||||
ktx_uint64_t byteOffset; /*!< Offset of item from start of file. */
|
||||
ktx_uint64_t byteLength; /*!< Number of bytes of data in the item. */
|
||||
} ktxIndexEntry64;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief KTX 2 file header.
|
||||
*
|
||||
* See the KTX 2 specification for descriptions.
|
||||
*/
|
||||
typedef struct KTX_header2 {
|
||||
ktx_uint8_t identifier[12];
|
||||
ktx_uint32_t vkFormat;
|
||||
ktx_uint32_t typeSize;
|
||||
ktx_uint32_t pixelWidth;
|
||||
ktx_uint32_t pixelHeight;
|
||||
ktx_uint32_t pixelDepth;
|
||||
ktx_uint32_t layerCount;
|
||||
ktx_uint32_t faceCount;
|
||||
ktx_uint32_t levelCount;
|
||||
ktx_uint32_t supercompressionScheme;
|
||||
ktxIndexEntry32 dataFormatDescriptor;
|
||||
ktxIndexEntry32 keyValueData;
|
||||
ktxIndexEntry64 supercompressionGlobalData;
|
||||
} KTX_header2;
|
||||
|
||||
/* This will cause compilation to fail if the struct size doesn't match */
|
||||
typedef int KTX_header2_SIZE_ASSERT [sizeof(KTX_header2) == KTX2_HEADER_SIZE];
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief KTX 2 level index entry.
|
||||
*/
|
||||
typedef struct ktxLevelIndexEntry {
|
||||
ktx_uint64_t byteOffset; /*!< Offset of level from start of file. */
|
||||
ktx_uint64_t byteLength;
|
||||
/*!< Number of bytes of compressed image data in the level. */
|
||||
ktx_uint64_t uncompressedByteLength;
|
||||
/*!< Number of bytes of uncompressed image data in the level. */
|
||||
} ktxLevelIndexEntry;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief Structure for supplemental information about the texture.
|
||||
*
|
||||
* _ktxCheckHeader returns supplemental information about the texture in this
|
||||
* structure that is derived during checking of the file header.
|
||||
*/
|
||||
typedef struct KTX_supplemental_info
|
||||
{
|
||||
ktx_uint8_t compressed;
|
||||
ktx_uint8_t generateMipmaps;
|
||||
ktx_uint16_t textureDimension;
|
||||
} KTX_supplemental_info;
|
||||
/**
|
||||
* @internal
|
||||
* @var ktx_uint8_t KTX_supplemental_info::compressed
|
||||
* @~English
|
||||
* @brief KTX_TRUE, if this a compressed texture, KTX_FALSE otherwise?
|
||||
*/
|
||||
/**
|
||||
* @internal
|
||||
* @var ktx_uint8_t KTX_supplemental_info::generateMipmaps
|
||||
* @~English
|
||||
* @brief KTX_TRUE, if mipmap generation is required, KTX_FALSE otherwise.
|
||||
*/
|
||||
/**
|
||||
* @internal
|
||||
* @var ktx_uint16_t KTX_supplemental_info::textureDimension
|
||||
* @~English
|
||||
* @brief The number of dimensions, 1, 2 or 3, of data in the texture image.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @internal
|
||||
* CheckHeader1
|
||||
*
|
||||
* Reads the KTX file header and performs some sanity checking on the values
|
||||
*/
|
||||
KTX_error_code ktxCheckHeader1_(KTX_header* pHeader,
|
||||
KTX_supplemental_info* pSuppInfo);
|
||||
|
||||
/*
|
||||
* @internal
|
||||
* CheckHeader2
|
||||
*
|
||||
* Reads the KTX 2 file header and performs some sanity checking on the values
|
||||
*/
|
||||
KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader,
|
||||
KTX_supplemental_info* pSuppInfo);
|
||||
|
||||
/*
|
||||
* SwapEndian16: Swaps endianness in an array of 16-bit values
|
||||
*/
|
||||
void _ktxSwapEndian16(ktx_uint16_t* pData16, ktx_size_t count);
|
||||
|
||||
/*
|
||||
* SwapEndian32: Swaps endianness in an array of 32-bit values
|
||||
*/
|
||||
void _ktxSwapEndian32(ktx_uint32_t* pData32, ktx_size_t count);
|
||||
|
||||
/*
|
||||
* SwapEndian32: Swaps endianness in an array of 64-bit values
|
||||
*/
|
||||
void _ktxSwapEndian64(ktx_uint64_t* pData64, ktx_size_t count);
|
||||
|
||||
/*
|
||||
* UnpackETC: uncompresses an ETC compressed texture image
|
||||
*/
|
||||
KTX_error_code _ktxUnpackETC(const GLubyte* srcETC, const GLenum srcFormat,
|
||||
ktx_uint32_t active_width, ktx_uint32_t active_height,
|
||||
GLubyte** dstImage,
|
||||
GLenum* format, GLenum* internalFormat, GLenum* type,
|
||||
GLint R16Formats, GLboolean supportsSRGB);
|
||||
|
||||
/*
|
||||
* @internal
|
||||
* ktxCompressZLIBBounds
|
||||
*
|
||||
* Returns upper bound for compresses data using miniz (ZLIB)
|
||||
*/
|
||||
ktx_size_t ktxCompressZLIBBounds(ktx_size_t srcLength);
|
||||
|
||||
/*
|
||||
* @internal
|
||||
* ktxCompressZLIBInt
|
||||
*
|
||||
* Compresses data using miniz (ZLIB)
|
||||
*/
|
||||
KTX_error_code ktxCompressZLIBInt(unsigned char* pDest,
|
||||
ktx_size_t* pDestLength,
|
||||
const unsigned char* pSrc,
|
||||
ktx_size_t srcLength,
|
||||
ktx_uint32_t level);
|
||||
|
||||
/*
|
||||
* @internal
|
||||
* ktxUncompressZLIBInt
|
||||
*
|
||||
* Uncompresses data using miniz (ZLIB)
|
||||
*/
|
||||
KTX_error_code ktxUncompressZLIBInt(unsigned char* pDest,
|
||||
ktx_size_t* pDestLength,
|
||||
const unsigned char* pSrc,
|
||||
ktx_size_t srcLength);
|
||||
|
||||
/*
|
||||
* Pad nbytes to next multiple of n
|
||||
*/
|
||||
#define _KTX_PADN(n, nbytes) (ktx_uint32_t)(n * ceilf((float)(nbytes) / n))
|
||||
/*
|
||||
* Calculate bytes of of padding needed to reach next multiple of n.
|
||||
*/
|
||||
/* Equivalent to (n * ceil(nbytes / n)) - nbytes */
|
||||
#define _KTX_PADN_LEN(n, nbytes) \
|
||||
(ktx_uint32_t)((n * ceilf((float)(nbytes) / n)) - (nbytes))
|
||||
|
||||
/*
|
||||
* Pad nbytes to next multiple of 4
|
||||
*/
|
||||
#define _KTX_PAD4(nbytes) _KTX_PADN(4, nbytes)
|
||||
/*
|
||||
* Calculate bytes of of padding needed to reach next multiple of 4.
|
||||
*/
|
||||
#define _KTX_PAD4_LEN(nbytes) _KTX_PADN_LEN(4, nbytes)
|
||||
|
||||
/*
|
||||
* Pad nbytes to next multiple of 8
|
||||
*/
|
||||
#define _KTX_PAD8(nbytes) _KTX_PADN(8, nbytes)
|
||||
/*
|
||||
* Calculate bytes of of padding needed to reach next multiple of 8.
|
||||
*/
|
||||
#define _KTX_PAD8_LEN(nbytes) _KTX_PADN_LEN(8, nbytes)
|
||||
|
||||
/*
|
||||
* Pad nbytes to KTX_GL_UNPACK_ALIGNMENT
|
||||
*/
|
||||
#define _KTX_PAD_UNPACK_ALIGN(nbytes) \
|
||||
_KTX_PADN(KTX_GL_UNPACK_ALIGNMENT, nbytes)
|
||||
/*
|
||||
* Calculate bytes of of padding needed to reach KTX_GL_UNPACK_ALIGNMENT.
|
||||
*/
|
||||
#define _KTX_PAD_UNPACK_ALIGN_LEN(nbytes) \
|
||||
_KTX_PADN_LEN(KTX_GL_UNPACK_ALIGNMENT, nbytes)
|
||||
|
||||
/*
|
||||
======================================
|
||||
Internal utility functions
|
||||
======================================
|
||||
*/
|
||||
|
||||
KTX_error_code printKTX2Info2(ktxStream* src, KTX_header2* header);
|
||||
|
||||
/*
|
||||
* fopen a file identified by a UTF-8 path.
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// For Windows, we convert the UTF-8 path and mode to UTF-16 path and use
|
||||
// _wfopen which correctly handles unicode characters.
|
||||
static inline FILE* ktxFOpenUTF8(char const* path, char const* mode) {
|
||||
int wpLen = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
|
||||
int wmLen = MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
|
||||
FILE* fp = NULL;
|
||||
if (wpLen > 0 && wmLen > 0)
|
||||
{
|
||||
wchar_t* wpath = (wchar_t*)malloc(wpLen * sizeof(wchar_t));
|
||||
wchar_t* wmode = (wchar_t*)malloc(wmLen * sizeof(wchar_t));
|
||||
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, wpLen);
|
||||
MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, wmLen);
|
||||
// Returned errno_t value is also set in the global errno.
|
||||
// Apps use that for error detail as libktx only returns
|
||||
// KTX_FILE_OPEN_FAILED.
|
||||
(void)_wfopen_s(&fp, wpath, wmode);
|
||||
free(wpath);
|
||||
free(wmode);
|
||||
return fp;
|
||||
} else {
|
||||
assert(KTX_FALSE
|
||||
&& "ktxFOpenUTF8 called with zero length path or mode.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// For other platforms there is no need for any conversion, they
|
||||
// support UTF-8 natively.
|
||||
static inline FILE* ktxFOpenUTF8(char const* path, char const* mode) {
|
||||
return fopen(path, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* KTXINT_H */
|
||||
@@ -0,0 +1,418 @@
|
||||
@mainpage
|
||||
|
||||
<!--
|
||||
Can't put at start. Doxygen requires page title on first line.
|
||||
Copyright 2019-2020 Mark Callow
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
libktx is a small library of functions for creating and reading KTX (Khronos
|
||||
TeXture) files, version 1 and 2 and instantiating OpenGL® and OpenGL® ES
|
||||
textures and Vulkan images from them. KTX version 2 files can contain images
|
||||
supercompressed with _zstd_ or _zlib_. They can also contain images in the Basis
|
||||
Universal formats. libktx can deflate and inflate zstd and zlib compressed
|
||||
images, can encode and transcode the Basis Universal formats and can
|
||||
encode ASTC formats.
|
||||
|
||||
For information about the KTX format see the
|
||||
<a href="https://registry.khronos.org/KTX/specs/2.0/ktxspec.v2.html">
|
||||
formal specification.</a>
|
||||
|
||||
@authors
|
||||
<a href="http://github.com/MarkCallow">Mark Callow</a>,
|
||||
formerly at <a href="http://www.hicorp.co.jp">HI Corporation</a>\n
|
||||
Mátyás Császár and Daniel Rákos, <a href="https://www.rastergrid.com/">RasterGrid</a>\n
|
||||
Wasim Abbas, <a href="https://www.arm.com/">Arm</a>\n
|
||||
Andreas Atteneder, Independent\n
|
||||
Georg Kolling, <a href="http://www.imgtec.com">Imagination Technology</a>\n
|
||||
Jacob Ström, <a href="http://www.ericsson.com">Ericsson AB</a>
|
||||
|
||||
@snippet{doc} version.h API version
|
||||
|
||||
$Date$
|
||||
|
||||
# Usage Overview {#overview}
|
||||
|
||||
The following `ktxTexture` examples work for both KTX and KTX2 textures. The
|
||||
texture type is determined from the file contents.
|
||||
|
||||
## Reading a KTX file for non-GL and non-Vulkan Use {#readktx}
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <ktx.h>
|
||||
|
||||
ktxTexture* texture;
|
||||
KTX_error_code result;
|
||||
ktx_size_t offset;
|
||||
ktx_uint8_t* image;
|
||||
ktx_uint32_t level, layer, faceSlice;
|
||||
|
||||
result = ktxTexture_CreateFromNamedFile("mytex3d.ktx",
|
||||
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
||||
&texture);
|
||||
|
||||
// Retrieve information about the texture from fields in the ktxTexture
|
||||
// such as:
|
||||
ktx_uint32_t numLevels = texture->numLevels;
|
||||
ktx_uint32_t baseWidth = texture->baseWidth;
|
||||
ktx_bool_t isArray = texture->isArray;
|
||||
|
||||
// Retrieve a pointer to the image for a specific mip level, array layer
|
||||
// & face or depth slice.
|
||||
level = 1; layer = 0; faceSlice = 3;
|
||||
result = ktxTexture_GetImageOffset(texture, level, layer, faceSlice, &offset);
|
||||
image = ktxTexture_GetData(texture) + offset;
|
||||
// ...
|
||||
// Do something with the texture image.
|
||||
// ...
|
||||
ktxTexture_Destroy(texture);
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
## Creating a GL texture object from a KTX file. {#createGL}
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <ktx.h>
|
||||
|
||||
ktxTexture* kTexture;
|
||||
KTX_error_code result;
|
||||
ktx_size_t offset;
|
||||
ktx_uint8_t* image;
|
||||
ktx_uint32_t level, layer, faceSlice;
|
||||
GLuint texture = 0;
|
||||
GLenum target, glerror;
|
||||
|
||||
result = ktxTexture_CreateFromNamedFile("mytex3d.ktx",
|
||||
KTX_TEXTURE_CREATE_NO_FLAGS,
|
||||
&kTexture);
|
||||
|
||||
// Before the first call to ktxTexture_GLUpload make libktx load its
|
||||
// function pointers for the GL functions it uses. The parameter is a
|
||||
// pointer to the GLGetProcAddress function provided by whatever OpenGL
|
||||
// framework the application is using. The example shown is for SDL.
|
||||
//
|
||||
// Note 1: This is unrelated to any GL function pointers the app may be
|
||||
// using.
|
||||
// Note 2: When this is not called, libktx has fallback mechanisms to
|
||||
// find the pointers which work on the vast majority of
|
||||
// platforms. The only known failures have occurred on Fedora.
|
||||
result = ktxLoadOpenGL((PFNGLGETPROCADDRESS)SDL_GL_GetProcAddress);
|
||||
|
||||
glGenTextures(1, &texture); // Optional. GLUpload can generate a texture.
|
||||
result = ktxTexture_GLUpload(kTexture, &texture, &target, &glerror);
|
||||
ktxTexture_Destroy(kTexture);
|
||||
// ...
|
||||
// GL rendering using the texture
|
||||
// ...
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
## Creating a Vulkan image object from a KTX file. {#createVulkan}
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <ktxvulkan.h>
|
||||
|
||||
ktxTexture* kTexture;
|
||||
KTX_error_code result;
|
||||
ktx_size_t offset;
|
||||
ktx_uint8_t* image;
|
||||
ktx_uint32_t level, layer, faceSlice;
|
||||
ktxVulkanDeviceInfo vdi;
|
||||
ktxVulkanTexture texture;
|
||||
|
||||
// Set up Vulkan physical device (gpu), logical device (device), queue
|
||||
// and command pool. Save the handles to these in a struct called vkctx.
|
||||
// ktx VulkanDeviceInfo is used to pass these with the expectation that
|
||||
// apps are likely to upload a large number of textures.
|
||||
ktxVulkanDeviceInfo_Construct(&vdi, vkctx.gpu, vkctx.device,
|
||||
vkctx.queue, vkctx.commandPool, nullptr);
|
||||
|
||||
ktxresult = ktxTexture_CreateFromNamedFile("mytex3d.ktx",
|
||||
KTX_TEXTURE_CREATE_NO_FLAGS,
|
||||
&kTexture);
|
||||
|
||||
ktxresult = ktxTexture_VkUploadEx(kTexture, &vdi, &texture,
|
||||
VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
ktxTexture_Destroy(kTexture);
|
||||
ktxVulkanDeviceInfo_Destruct(&vdi);
|
||||
// ...
|
||||
// Vulkan rendering using the texture
|
||||
// ...
|
||||
// When done using the image in Vulkan...
|
||||
ktxVulkanTexture_Destruct(&texture, vkctx.device, nullptr);
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
## Extracting Metadata {#subsection}
|
||||
|
||||
Once a ktxTexture object has been created, metadata can be easily found
|
||||
and extracted. The following can be added to any of the above.
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
char* pValue;
|
||||
uint32_t valueLen;
|
||||
if (KTX_SUCCESS == ktxHashList_FindValue(&kTexture->kvDataHead,
|
||||
KTX_ORIENTATION_KEY,
|
||||
&valueLen, (void**)&pValue))
|
||||
{
|
||||
char s, t;
|
||||
|
||||
if (sscanf(pValue, KTX_ORIENTATION2_FMT, &s, &t) == 2) {
|
||||
...
|
||||
}
|
||||
}
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
## Writing a KTX or KTX2 file {#writektx}
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <ktx.h>
|
||||
#include <vkformat_enum.h>
|
||||
|
||||
ktxTexture2* texture; // For KTX2
|
||||
//ktxTexture1* texture; // For KTX
|
||||
ktxTextureCreateInfo createInfo;
|
||||
KTX_error_code result;
|
||||
ktx_uint32_t level, layer, faceSlice;
|
||||
FILE* src;
|
||||
ktx_size_t srcSize;
|
||||
|
||||
createInfo.glInternalformat = GL_RGB8; // Ignored if creating a ktxTexture2.
|
||||
createInfo.vkFormat = VK_FORMAT_R8G8B8_UNORM; // Ignored if creating a ktxTexture1.
|
||||
createInfo.baseWidth = 2048;
|
||||
createInfo.baseHeight = 1024;
|
||||
createInfo.baseDepth = 16;
|
||||
createInfo.numDimensions = 3.
|
||||
// Note: it is not necessary to provide a full mipmap pyramid.
|
||||
createInfo.numLevels = log2(createInfo.baseWidth) + 1
|
||||
createInfo.numLayers = 1;
|
||||
createInfo.numFaces = 1;
|
||||
createInfo.isArray = KTX_FALSE;
|
||||
createInfo.generateMipmaps = KTX_FALSE;
|
||||
|
||||
// Call ktxTexture1_Create to create a KTX texture.
|
||||
result = ktxTexture2_Create(&createInfo,
|
||||
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
||||
&texture);
|
||||
|
||||
src = // Open a stdio FILE* on the baseLevel image, slice 0.
|
||||
srcSize = // Query size of the file.
|
||||
level = 0;
|
||||
layer = 0;
|
||||
faceSlice = 0;
|
||||
result = ktxTexture_SetImageFromMemory(ktxTexture(texture),
|
||||
level, layer, faceSlice,
|
||||
src, srcSize);
|
||||
// Repeat for the other 15 slices of the base level and all other levels
|
||||
// up to createInfo.numLevels.
|
||||
|
||||
ktxTexture_WriteToNamedFile(ktxTexture(texture), "mytex3d.ktx");
|
||||
ktxTexture_Destroy(ktxTexture(texture));
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
## Modifying a KTX file {#modifyktx}
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <ktx.h>
|
||||
|
||||
ktxTexture* texture;
|
||||
KTX_error_code result;
|
||||
ktx_size_t offset;
|
||||
ktx_uint8_t* image;
|
||||
ktx_uint32_t level, layer, faceSlice;
|
||||
|
||||
result = ktxTexture_CreateFromNamedFile("mytex3d.ktx",
|
||||
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
|
||||
&texture);
|
||||
// The file is closed after all the data has been read.
|
||||
|
||||
// It is the responsibilty of the application to make sure its
|
||||
// modifications are valid.
|
||||
texture->generateMipmaps = KTX_TRUE;
|
||||
|
||||
ktxTexture_WriteToNamedFile(texture, "mytex3d.ktx");
|
||||
ktxTexture_Destroy(texture);
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
## Writing a Basis-compressed Universal Texture
|
||||
|
||||
Basis compression supports two universal texture formats: _BasisLZ/ETC1S_ and _UASTC_. The latter gives higher quality at a larger file size. Textures can be compressed to either format using `ktxTexture2_CompressBasisEx` as shown in this example.
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <ktx.h>
|
||||
#include <vkformat_enum.h>
|
||||
|
||||
ktxTexture2* texture;
|
||||
ktxTextureCreateInfo createInfo;
|
||||
KTX_error_code result;
|
||||
ktx_uint32_t level, layer, faceSlice;
|
||||
FILE* src;
|
||||
ktx_size_t srcSize;
|
||||
ktxBasisParams params = {0};
|
||||
params.structSize = sizeof(params);
|
||||
|
||||
createInfo.glInternalformat = 0; //Ignored as we'll create a KTX2 texture.
|
||||
createInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
createInfo.baseWidth = 2048;
|
||||
createInfo.baseHeight = 1024;
|
||||
createInfo.baseDepth = 16;
|
||||
createInfo.numDimensions = 3.
|
||||
// Note: it is not necessary to provide a full mipmap pyramid.
|
||||
createInfo.numLevels = log2(createInfo.baseWidth) + 1
|
||||
createInfo.numLayers = 1;
|
||||
createInfo.numFaces = 1;
|
||||
createInfo.isArray = KTX_FALSE;
|
||||
createInfo.generateMipmaps = KTX_FALSE;
|
||||
|
||||
result = ktxTexture2_Create(&createInfo,
|
||||
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
||||
&texture);
|
||||
|
||||
src = // Open the file for the baseLevel image, slice 0 and
|
||||
// read it into memory.
|
||||
srcSize = // Query size of the file.
|
||||
level = 0;
|
||||
layer = 0;
|
||||
faceSlice = 0;
|
||||
result = ktxTexture_SetImageFromMemory(ktxTexture(texture),
|
||||
level, layer, faceSlice,
|
||||
src, srcSize);
|
||||
// Repeat for the other 15 slices of the base level and all other levels
|
||||
// up to createInfo.numLevels.
|
||||
|
||||
// For BasisLZ/ETC1S
|
||||
params.compressionLevel = KTX_ETC1S_DEFAULT_COMPRESSION_LEVEL;
|
||||
// For UASTC
|
||||
params.uastc = KTX_TRUE;
|
||||
// Set other BasisLZ/ETC1S or UASTC params to change default quality settings.
|
||||
result = ktxtexture2_CompressBasisEx(texture, ¶ms);
|
||||
|
||||
ktxTexture_WriteToNamedFile(ktxTexture(texture), "mytex3d.ktx2");
|
||||
ktxTexture_Destroy(ktxTexture(texture));
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
There is a shortcut that can be used when compressing to BasisLZ/ETC1S. Remove
|
||||
the declaration and initialization of `params` in the previous example and
|
||||
replace `ktxtexture2_CompressBasisEx` with
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
// Quality range is 1 - 255. 0 gets the default quality, currently 128.
|
||||
// The qualityLevel field in ktxBasisParams is set from this.
|
||||
int quality = 0;
|
||||
result = ktxTexture2_CompressBasis(texture, quality);
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
|
||||
## Transcoding a BasisLZ/ETC1S or UASTC-compressed Texture
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <ktx.h>
|
||||
|
||||
ktxTexture2* texture;
|
||||
KTX_error_code result;
|
||||
|
||||
result = ktxTexture_CreateFromNamedFile("mytex3d_basis.ktx2",
|
||||
KTX_TEXTURE_CREATE_NO_FLAGS,
|
||||
(ktxTexture**)&kTexture);
|
||||
// or
|
||||
//result = ktxTexture2_CreateFromNamedFile("mytex3d_basis.ktx2",
|
||||
// KTX_TEXTURE_CREATE_NO_FLAGS,
|
||||
// &kTexture);
|
||||
|
||||
if (ktxTexture2_NeedsTranscoding(texture)) {
|
||||
ktx_texture_transcode_fmt_e tf;
|
||||
|
||||
// Using VkGetPhysicalDeviceFeatures or GL_COMPRESSED_TEXTURE_FORMATS or
|
||||
// extension queries, determine what compressed texture formats are
|
||||
// supported and pick a format. For example
|
||||
vk::PhysicalDeviceFeatures deviceFeatures;
|
||||
vkctx.gpu.getFeatures(&deviceFeatures);
|
||||
khr_df_model_e colorModel = ktxTexture2_GetColorModel_e(texture);
|
||||
if (colorModel == KHR_DF_MODEL_UASTC
|
||||
&& deviceFeatures.textureCompressionASTC_LDR) {
|
||||
tf = KTX_TTF_ASTC_4x4_RGBA;
|
||||
} else if (colorModel == KHR_DF_MODEL_ETC1S
|
||||
&& deviceFeatures.textureCompressionETC2) {
|
||||
tf = KTX_TTF_ETC;
|
||||
} else if (deviceFeatures.textureCompressionASTC_LDR) {
|
||||
tf = KTX_TTF_ASTC_4x4_RGBA;
|
||||
} else if (deviceFeatures.textureCompressionETC2)
|
||||
tf = KTX_TTF_ETC2_RGBA;
|
||||
else if (deviceFeatures.textureCompressionBC)
|
||||
tf = KTX_TTF_BC3_RGBA;
|
||||
else {
|
||||
message << "Vulkan implementation does not support any available transcode target.";
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
|
||||
result = ktxTexture2_TranscodeBasis(texture, tf, 0);
|
||||
|
||||
// Then use VkUpload or GLUpload to create a texture object on the GPU.
|
||||
}
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
## Writing an ASTC-Compressed Texture
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
#include <ktx.h>
|
||||
#include <vkformat_enum.h>
|
||||
|
||||
ktxTexture2* texture;
|
||||
ktxTextureCreateInfo createInfo;
|
||||
KTX_error_code result;
|
||||
ktx_uint32_t level, layer, faceSlice;
|
||||
FILE* src;
|
||||
ktx_size_t srcSize;
|
||||
ktxAstcParams params = {0};
|
||||
params.structSize = sizeof(params);
|
||||
|
||||
createInfo.glInternalformat = 0; //Ignored as we'll create a KTX2 texture.
|
||||
createInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
createInfo.baseWidth = 2048;
|
||||
createInfo.baseHeight = 1024;
|
||||
createInfo.baseDepth = 16;
|
||||
createInfo.numDimensions = 3.
|
||||
// Note: it is not necessary to provide a full mipmap pyramid.
|
||||
createInfo.numLevels = log2(createInfo.baseWidth) + 1
|
||||
createInfo.numLayers = 1;
|
||||
createInfo.numFaces = 1;
|
||||
createInfo.isArray = KTX_FALSE;
|
||||
createInfo.generateMipmaps = KTX_FALSE;
|
||||
|
||||
result = ktxTexture2_Create(&createInfo,
|
||||
KTX_TEXTURE_CREATE_ALLOC_STORAGE,
|
||||
&texture);
|
||||
|
||||
src = // Open the file for the baseLevel image, slice 0 and
|
||||
// read it into memory.
|
||||
srcSize = // Query size of the file.
|
||||
level = 0;
|
||||
layer = 0;
|
||||
faceSlice = 0;
|
||||
result = ktxTexture_SetImageFromMemory(ktxTexture(texture),
|
||||
level, layer, faceSlice,
|
||||
src, srcSize);
|
||||
// Repeat for the other 15 slices of the base level and all other levels
|
||||
// up to createInfo.numLevels.
|
||||
|
||||
params.threadCount = 1;
|
||||
params.blockDimension = KTX_PACK_ASTC_BLOCK_DIMENSION_6x6;
|
||||
params.mode = KTX_PACK_ASTC_ENCODER_MODE_LDR;
|
||||
params.qualityLevel = KTX_PACK_ASTC_QUALITY_LEVEL_MEDIUM;
|
||||
result = ktxtexture2_CompressAstcEx(texture, ¶ms);
|
||||
|
||||
ktxTexture_WriteToNamedFile(ktxTexture(texture), "mytex3d.ktx2");
|
||||
ktxTexture_Destroy(ktxTexture(texture));
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
There is a shortcut that can be used when the only `params` field you want to
|
||||
modify is the `qualityLevel`. Remove the declaration and initialization of
|
||||
`params` in the previous example and replace `ktxtexture2_CompressAstcEx` with
|
||||
|
||||
~~~~~~~~~~~~~~~~{.c}
|
||||
// Quality range is 0 - 100. 0 is fastest/lowest. 100 is slowest/highest.
|
||||
int quality = KTX_PACK_ASTC_QUALITY_LEVEL_MEDIUM;
|
||||
result = ktxTexture2_CompressAstc(texture, quality);
|
||||
~~~~~~~~~~~~~~~~
|
||||
@@ -0,0 +1,561 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Implementation of ktxStream for memory.
|
||||
*
|
||||
* @author Maksim Kolesin, Under Development
|
||||
* @author Georg Kolling, Imagination Technology
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
#include "memstream.h"
|
||||
|
||||
/**
|
||||
* @brief Default allocation size for a ktxMemStream.
|
||||
*/
|
||||
#define KTX_MEM_DEFAULT_ALLOCATED_SIZE 256
|
||||
|
||||
/**
|
||||
* @brief Structure to store information about data allocated for ktxMemStream.
|
||||
*/
|
||||
struct ktxMem
|
||||
{
|
||||
const ktx_uint8_t* robytes;/*!< pointer to read-only data */
|
||||
ktx_uint8_t* bytes; /*!< pointer to rw data. */
|
||||
ktx_size_t alloc_size; /*!< allocated size of the memory block. */
|
||||
ktx_size_t used_size; /*!< bytes used. Effectively the write position. */
|
||||
ktx_off_t pos; /*!< read/write position. */
|
||||
};
|
||||
|
||||
static KTX_error_code ktxMem_expand(ktxMem* pMem, const ktx_size_t size);
|
||||
|
||||
/**
|
||||
* @brief Initialize a ktxMem struct for read-write.
|
||||
*
|
||||
* Memory for the stream data is allocated internally but the
|
||||
* caller is responsible for freeing the memory. A pointer to
|
||||
* the memory can be obtained with ktxMem_getdata().
|
||||
*
|
||||
* @sa ktxMem_getdata.
|
||||
*
|
||||
* @param [in] pMem pointer to the @c ktxMem to initialize.
|
||||
*/
|
||||
static KTX_error_code
|
||||
ktxMem_construct(ktxMem* pMem)
|
||||
{
|
||||
pMem->pos = 0;
|
||||
pMem->alloc_size = 0;
|
||||
pMem->robytes = 0;
|
||||
pMem->bytes = 0;
|
||||
pMem->used_size = 0;
|
||||
return ktxMem_expand(pMem, KTX_MEM_DEFAULT_ALLOCATED_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create & initialize a ktxMem struct for read-write.
|
||||
*
|
||||
* @sa ktxMem_construct.
|
||||
*
|
||||
* @param [in,out] ppMem pointer to the location in which to return
|
||||
* a pointer to the newly created @c ktxMem.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, KTX_OUT_OF_MEMORY on error.
|
||||
*
|
||||
* @exception KTX_OUT_OF_MEMORY System failed to allocate sufficient pMemory.
|
||||
*/
|
||||
static KTX_error_code
|
||||
ktxMem_create(ktxMem** ppMem)
|
||||
{
|
||||
ktxMem* pNewMem = (ktxMem*)malloc(sizeof(ktxMem));
|
||||
if (pNewMem) {
|
||||
KTX_error_code result = ktxMem_construct(pNewMem);
|
||||
if (result == KTX_SUCCESS)
|
||||
*ppMem = pNewMem;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize a ktxMem struct for read-only.
|
||||
*
|
||||
* @param [in] pMem pointer to the @c ktxMem to initialize.
|
||||
* @param [in] bytes pointer to the data to be read.
|
||||
* @param [in] numBytes number of bytes of data.
|
||||
*/
|
||||
static void
|
||||
ktxMem_construct_ro(ktxMem* pMem, const void* bytes, ktx_size_t numBytes)
|
||||
{
|
||||
pMem->pos = 0;
|
||||
pMem->robytes = bytes;
|
||||
pMem->bytes = 0;
|
||||
pMem->used_size = numBytes;
|
||||
pMem->alloc_size = numBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create & initialize a ktxMem struct for read-only.
|
||||
*
|
||||
* @sa ktxMem_construct.
|
||||
*
|
||||
* @param [in,out] ppMem pointer to the location in which to return
|
||||
* a pointer to the newly created @c ktxMem.
|
||||
* @param [in] bytes pointer to the data to be read.
|
||||
* @param [in] numBytes number of bytes of data.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, KTX_OUT_OF_MEMORY on error.
|
||||
*
|
||||
* @exception KTX_OUT_OF_MEMORY System failed to allocate sufficient pMemory.
|
||||
*/
|
||||
static KTX_error_code
|
||||
ktxMem_create_ro(ktxMem** ppMem, const void* bytes, ktx_size_t numBytes)
|
||||
{
|
||||
ktxMem* pNewMem = (ktxMem*)malloc(sizeof(ktxMem));
|
||||
if (pNewMem) {
|
||||
ktxMem_construct_ro(pNewMem, bytes, numBytes);
|
||||
*ppMem = pNewMem;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ktxMem_destruct not needed as ktxMem_construct caller is reponsible
|
||||
* for freeing the data written.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Free the memory of a struct ktxMem.
|
||||
*
|
||||
* @param pMem pointer to ktxMem to free.
|
||||
*/
|
||||
static void
|
||||
ktxMem_destroy(ktxMem* pMem, ktx_bool_t freeData)
|
||||
{
|
||||
assert(pMem != NULL);
|
||||
if (freeData) {
|
||||
free(pMem->bytes);
|
||||
}
|
||||
free(pMem);
|
||||
}
|
||||
|
||||
#ifdef KTXMEM_CLEAR_USED
|
||||
/**
|
||||
* @brief Clear the data of a memory stream.
|
||||
*
|
||||
* @param pMem pointer to ktxMem to clear.
|
||||
*/
|
||||
static void
|
||||
ktxMem_clear(ktxMem* pMem)
|
||||
{
|
||||
assert(pMem != NULL);
|
||||
memset(pMem, 0, sizeof(ktxMem));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Expand a ktxMem to fit to a new size.
|
||||
*
|
||||
* @param [in] pMem pointer to ktxMem struct to expand.
|
||||
* @param [in] newsize minimum new size required.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, KTX_OUT_OF_MEMORY on error.
|
||||
*
|
||||
* @exception KTX_OUT_OF_MEMORY System failed to allocate sufficient pMemory.
|
||||
*/
|
||||
static KTX_error_code
|
||||
ktxMem_expand(ktxMem *pMem, const ktx_size_t newsize)
|
||||
{
|
||||
ktx_size_t new_alloc_size;
|
||||
|
||||
assert(pMem != NULL && newsize != 0);
|
||||
|
||||
new_alloc_size = pMem->alloc_size == 0 ?
|
||||
KTX_MEM_DEFAULT_ALLOCATED_SIZE : pMem->alloc_size;
|
||||
while (new_alloc_size < newsize) {
|
||||
ktx_size_t alloc_size = new_alloc_size;
|
||||
new_alloc_size <<= 1;
|
||||
if (new_alloc_size < alloc_size) {
|
||||
/* Overflow. Set to maximum size. newsize can't be larger. */
|
||||
new_alloc_size = (ktx_size_t)-1L;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_alloc_size == pMem->alloc_size)
|
||||
return KTX_SUCCESS;
|
||||
|
||||
if (!pMem->bytes)
|
||||
pMem->bytes = (ktx_uint8_t*)malloc(new_alloc_size);
|
||||
else
|
||||
pMem->bytes = (ktx_uint8_t*)realloc(pMem->bytes, new_alloc_size);
|
||||
|
||||
if (!pMem->bytes)
|
||||
{
|
||||
pMem->alloc_size = 0;
|
||||
pMem->used_size = 0;
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
pMem->alloc_size = new_alloc_size;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Read bytes from a ktxMemStream.
|
||||
*
|
||||
* @param [in] str pointer to ktxMem struct, converted to a void*, that
|
||||
* specifies an input stream.
|
||||
* @param [in,out] dst pointer to memory where to copy read bytes.
|
||||
* @param [in,out] count pointer to number of bytes to read.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str or @p dst is @c NULL or @p str->data is
|
||||
* @c NULL.
|
||||
* @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxMemStream_read(ktxStream* str, void* dst, const ktx_size_t count)
|
||||
{
|
||||
ktxMem* mem;
|
||||
ktx_off_t newpos;
|
||||
const ktx_uint8_t* bytes;
|
||||
|
||||
|
||||
if (!str || (mem = str->data.mem)== 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
newpos = mem->pos + count;
|
||||
/* The first clause checks for overflow. */
|
||||
if (newpos < mem->pos || (ktx_size_t)newpos > mem->used_size)
|
||||
return KTX_FILE_UNEXPECTED_EOF;
|
||||
|
||||
bytes = mem->robytes ? mem->robytes : mem->bytes;
|
||||
memcpy(dst, bytes + mem->pos, count);
|
||||
mem->pos = newpos;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Skip bytes in a ktxMemStream.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream on which to operate.
|
||||
* @param [in] count number of bytes to skip.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, KTX_INVALID_VALUE on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str or @p mem is @c NULL or sufficient
|
||||
* data is not available in ktxMem.
|
||||
* @exception KTX_FILE_UNEXPECTED_EOF not enough data to satisfy the request.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxMemStream_skip(ktxStream* str, const ktx_size_t count)
|
||||
{
|
||||
ktxMem* mem;
|
||||
ktx_off_t newpos;
|
||||
|
||||
if (!str || (mem = str->data.mem) == 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
newpos = mem->pos + count;
|
||||
/* The first clause checks for overflow. */
|
||||
if (newpos < mem->pos || (ktx_size_t)newpos > mem->used_size)
|
||||
return KTX_FILE_UNEXPECTED_EOF;
|
||||
|
||||
mem->pos = newpos;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Write bytes to a ktxMemStream.
|
||||
*
|
||||
* @param [out] str pointer to the ktxStream that specifies the destination.
|
||||
* @param [in] src pointer to the array of elements to be written,
|
||||
* converted to a const void*.
|
||||
* @param [in] size size in bytes of each element to be written.
|
||||
* @param [in] count number of elements, each one with a @p size of size
|
||||
* bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_FILE_OVERFLOW write would result in file exceeding the
|
||||
* maximum permissible size.
|
||||
* @exception KTX_INVALID_OPERATION @p str is a read-only stream.
|
||||
* @exception KTX_INVALID_VALUE @p dst is @c NULL or @p mem is @c NULL.
|
||||
* @exception KTX_OUT_OF_MEMORY See ktxMem_expand() for causes.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxMemStream_write(ktxStream* str, const void* src,
|
||||
const ktx_size_t size, const ktx_size_t count)
|
||||
{
|
||||
ktxMem* mem;
|
||||
KTX_error_code rc = KTX_SUCCESS;
|
||||
ktx_size_t new_size;
|
||||
|
||||
if (!str || (mem = str->data.mem) == 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
if (mem->robytes)
|
||||
return KTX_INVALID_OPERATION; /* read-only */
|
||||
|
||||
new_size = mem->pos + (size*count);
|
||||
//if (new_size < mem->used_size)
|
||||
if ((ktx_off_t)new_size < mem->pos)
|
||||
return KTX_FILE_OVERFLOW;
|
||||
|
||||
if (mem->alloc_size < new_size) {
|
||||
rc = ktxMem_expand(mem, new_size);
|
||||
if (rc != KTX_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
|
||||
memcpy(mem->bytes + mem->pos, src, size*count);
|
||||
mem->pos += size*count;
|
||||
if (mem->pos > (ktx_off_t)mem->used_size)
|
||||
mem->used_size = mem->pos;
|
||||
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Get the current read/write position in a ktxMemStream.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream to query.
|
||||
* @param [in,out] off pointer to variable to receive the offset value.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str or @p pos is @c NULL.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxMemStream_getpos(ktxStream* str, ktx_off_t* const pos)
|
||||
{
|
||||
if (!str || !pos)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeMemory);
|
||||
|
||||
*pos = str->data.mem->pos;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Set the current read/write position in a ktxMemStream.
|
||||
*
|
||||
* Offset of 0 is the start of the file.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream whose r/w position is to be set.
|
||||
* @param [in] off pointer to the offset value to set.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str is @c NULL.
|
||||
* @exception KTX_INVALID_OPERATION @p pos > size of the allocated memory.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxMemStream_setpos(ktxStream* str, ktx_off_t pos)
|
||||
{
|
||||
if (!str)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeMemory);
|
||||
|
||||
if (pos < 0 || (ktx_size_t)pos > str->data.mem->alloc_size)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
str->data.mem->pos = pos;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Get a pointer to a ktxMemStream's data.
|
||||
*
|
||||
* Gets a pointer to data that has been written to the stream. Returned
|
||||
* pointer will be 0 if stream is read-only.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream whose data pointer is to
|
||||
* be queried.
|
||||
* @param [in,out] ppBytes pointer to a variable in which the data pointer
|
||||
* will be written.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str or @p ppBytes is @c NULL.
|
||||
*/
|
||||
KTX_error_code ktxMemStream_getdata(ktxStream* str, ktx_uint8_t** ppBytes)
|
||||
{
|
||||
if (!str || !ppBytes)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeMemory);
|
||||
|
||||
*ppBytes = str->data.mem->bytes;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Get the size of a ktxMemStream in bytes.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream whose size is to be queried.
|
||||
* @param [in,out] size pointer to a variable in which size will be written.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str or @p pSize is @c NULL.
|
||||
*/
|
||||
static
|
||||
KTX_error_code ktxMemStream_getsize(ktxStream* str, ktx_size_t* pSize)
|
||||
{
|
||||
if (!str || !pSize)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
assert(str->type == eStreamTypeMemory);
|
||||
|
||||
*pSize = str->data.mem->used_size;
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Setup ktxMemStream function pointers.
|
||||
*/
|
||||
void
|
||||
ktxMemStream_setup(ktxStream* str)
|
||||
{
|
||||
str->type = eStreamTypeMemory;
|
||||
str->read = ktxMemStream_read;
|
||||
str->skip = ktxMemStream_skip;
|
||||
str->write = ktxMemStream_write;
|
||||
str->getpos = ktxMemStream_getpos;
|
||||
str->setpos = ktxMemStream_setpos;
|
||||
str->getsize = ktxMemStream_getsize;
|
||||
str->destruct = ktxMemStream_destruct;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Initialize a read-write ktxMemStream.
|
||||
*
|
||||
* Memory is allocated as data is written. The caller of this is
|
||||
* responsible for freeing this memory unless @a freeOnDestruct
|
||||
* is not KTX_FALSE.
|
||||
*
|
||||
* @param [in] str pointer to a ktxStream struct to initialize.
|
||||
* @param [in] freeOnDestruct If not KTX_FALSE memory holding the data will
|
||||
* be freed by the destructor.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str is @c NULL.
|
||||
* @exception KTX_OUT_OF_MEMORY system failed to allocate sufficient memory.
|
||||
*/
|
||||
KTX_error_code ktxMemStream_construct(ktxStream* str,
|
||||
ktx_bool_t freeOnDestruct)
|
||||
{
|
||||
ktxMem* mem;
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
|
||||
if (!str)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
result = ktxMem_create(&mem);
|
||||
|
||||
if (KTX_SUCCESS == result) {
|
||||
str->data.mem = mem;
|
||||
ktxMemStream_setup(str);
|
||||
str->closeOnDestruct = freeOnDestruct;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Initialize a read-only ktxMemStream.
|
||||
*
|
||||
* @param [in] str pointer to a ktxStream struct to initialize.
|
||||
* @param [in] bytes pointer to an array of bytes containing the data.
|
||||
* @param [in] numBytes size of array of data for ktxMemStream.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p str or @p mem is @c NULL or @p numBytes
|
||||
* is 0.
|
||||
* or @p size is less than 0.
|
||||
* @exception KTX_OUT_OF_MEMORY system failed to allocate sufficient memory.
|
||||
*/
|
||||
KTX_error_code ktxMemStream_construct_ro(ktxStream* str,
|
||||
const ktx_uint8_t* bytes,
|
||||
const ktx_size_t numBytes)
|
||||
{
|
||||
ktxMem* mem;
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
|
||||
if (!str || !bytes || numBytes == 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
result = ktxMem_create_ro(&mem, bytes, numBytes);
|
||||
|
||||
if (KTX_SUCCESS == result) {
|
||||
str->data.mem = mem;
|
||||
ktxMemStream_setup(str);
|
||||
str->closeOnDestruct = KTX_FALSE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Free the memory used by a ktxMemStream.
|
||||
*
|
||||
* This only frees the memory used to store the data written to the stream,
|
||||
* if the @c freeOnDestruct parameter to ktxMemStream_construct() was not
|
||||
* @c KTX_FALSE. Otherwise it is the responsibility of the caller of
|
||||
* ktxMemStream_construct() and a pointer to this memory should be retrieved
|
||||
* using ktxMemStream_getdata() before calling this function.
|
||||
*
|
||||
* @sa ktxMemStream_construct, ktxMemStream_getdata.
|
||||
*
|
||||
* @param [in] str pointer to the ktxStream whose memory is
|
||||
* to be freed.
|
||||
*/
|
||||
void
|
||||
ktxMemStream_destruct(ktxStream* str)
|
||||
{
|
||||
assert(str && str->type == eStreamTypeMemory);
|
||||
|
||||
ktxMem_destroy(str->data.mem, str->closeOnDestruct);
|
||||
str->data.mem = NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Interface of ktxStream for memory.
|
||||
*
|
||||
* @author Maksim Kolesin
|
||||
* @author Georg Kolling, Imagination Technology
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
#ifndef MEMSTREAM_H
|
||||
#define MEMSTREAM_H
|
||||
|
||||
#include "ktx.h"
|
||||
|
||||
/*
|
||||
* Initialize a ktxStream to a ktxMemStream with internally
|
||||
* allocated memory. Can be read or written.
|
||||
*/
|
||||
KTX_error_code ktxMemStream_construct(ktxStream* str,
|
||||
ktx_bool_t freeOnDestruct);
|
||||
/*
|
||||
* Initialize a ktxStream to a read-only ktxMemStream reading
|
||||
* from an array of bytes.
|
||||
*/
|
||||
KTX_error_code ktxMemStream_construct_ro(ktxStream* str,
|
||||
const ktx_uint8_t* pBytes,
|
||||
const ktx_size_t size);
|
||||
void ktxMemStream_destruct(ktxStream* str);
|
||||
|
||||
KTX_error_code ktxMemStream_getdata(ktxStream* str, ktx_uint8_t** ppBytes);
|
||||
|
||||
#endif /* MEMSTREAM_H */
|
||||
@@ -0,0 +1,149 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2023-2023 The Khronos Group Inc.
|
||||
* Copyright 2023-2023 RasterGrid Kft.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Wrapper functions for ZLIB compression/decompression using miniz.
|
||||
*
|
||||
* @author Daniel Rakos, RasterGrid
|
||||
*/
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if !KTX_FEATURE_WRITE
|
||||
// The reader does not link with the basisu components that already include a
|
||||
// definition of miniz so we include it here explicitly.
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
|
||||
#endif
|
||||
#include "basisu/encoder/basisu_miniz.h"
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#else
|
||||
// Otherwise we only declare the interfaces and link with the basisu version.
|
||||
// This is needed because while miniz is defined as a header in basisu it's
|
||||
// not declaring the functions as static or inline, hence causing multiple
|
||||
// conflicting definitions at link-time.
|
||||
namespace buminiz {
|
||||
typedef unsigned long mz_ulong;
|
||||
enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
|
||||
mz_ulong mz_compressBound(mz_ulong source_len);
|
||||
int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
|
||||
int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
using namespace buminiz;
|
||||
|
||||
extern "C" {
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief Returns upper bound for compresses data using miniz (ZLIB).
|
||||
*
|
||||
* @param srcLength source data length
|
||||
*
|
||||
* @author Daniel Rakos, RasterGrid
|
||||
*/
|
||||
ktx_size_t ktxCompressZLIBBounds(ktx_size_t srcLength) {
|
||||
return mz_compressBound((mz_ulong)srcLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief Compresses data using miniz (ZLIB)
|
||||
*
|
||||
* @param pDest destination data buffer
|
||||
* @param pDestLength destination data buffer size
|
||||
* (filled with written byte count on success)
|
||||
* @param pSrc source data buffer
|
||||
* @param srcLength source data size
|
||||
* @param level compression level (between 1 and 9)
|
||||
*
|
||||
* @author Daniel Rakos, RasterGrid
|
||||
*/
|
||||
KTX_error_code ktxCompressZLIBInt(unsigned char* pDest,
|
||||
ktx_size_t* pDestLength,
|
||||
const unsigned char* pSrc,
|
||||
ktx_size_t srcLength,
|
||||
ktx_uint32_t level) {
|
||||
if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE;
|
||||
mz_ulong mzCompressedSize = (mz_ulong)*pDestLength;
|
||||
int status = mz_compress2(pDest, &mzCompressedSize, pSrc, (mz_ulong)srcLength, level);
|
||||
switch (status) {
|
||||
case MZ_OK:
|
||||
*pDestLength = mzCompressedSize;
|
||||
return KTX_SUCCESS;
|
||||
case MZ_PARAM_ERROR:
|
||||
return KTX_INVALID_VALUE;
|
||||
case MZ_BUF_ERROR:
|
||||
#ifdef DEBUG
|
||||
assert(false && "Deflate dstSize too small.");
|
||||
#endif
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
case MZ_MEM_ERROR:
|
||||
#ifdef DEBUG
|
||||
assert(false && "Deflate workspace too small.");
|
||||
#endif
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
default:
|
||||
// The remaining errors look like they should only
|
||||
// occur during decompression but just in case.
|
||||
#ifdef DEBUG
|
||||
assert(true);
|
||||
#endif
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief Uncompresses data using miniz (ZLIB)
|
||||
*
|
||||
* @param pDest destination data buffer
|
||||
* @param pDestLength destination data buffer size
|
||||
* (filled with written byte count on success)
|
||||
* @param pSrc source data buffer
|
||||
* @param srcLength source data size
|
||||
*
|
||||
* @author Daniel Rakos, RasterGrid
|
||||
*/
|
||||
KTX_error_code ktxUncompressZLIBInt(unsigned char* pDest,
|
||||
ktx_size_t* pDestLength,
|
||||
const unsigned char* pSrc,
|
||||
ktx_size_t srcLength) {
|
||||
if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE;
|
||||
mz_ulong mzUncompressedSize = (mz_ulong)*pDestLength;
|
||||
int status = mz_uncompress(pDest, &mzUncompressedSize, pSrc, (mz_ulong)srcLength);
|
||||
switch (status) {
|
||||
case MZ_OK:
|
||||
*pDestLength = mzUncompressedSize;
|
||||
return KTX_SUCCESS;
|
||||
case MZ_BUF_ERROR:
|
||||
return KTX_DECOMPRESS_LENGTH_ERROR; // buffer too small
|
||||
case MZ_MEM_ERROR:
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
default:
|
||||
return KTX_FILE_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+1164
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,154 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Functions to return a string corresponding to various enumerations.
|
||||
*
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
#include "ktx.h"
|
||||
#include "basis_sgd.h"
|
||||
|
||||
static const char* const errorStrings[] = {
|
||||
"Operation succeeded.", /* KTX_SUCCESS */
|
||||
"File data is inconsistent with KTX spec.", /* KTX_FILE_DATA_ERROR */
|
||||
"File is a pipe; seek operations not possible.", /* KTX_FILE_ISPIPE */
|
||||
"File open failed.", /* KTX_FILE_OPEN_FAILED */
|
||||
"Operation would exceed the max file size.", /* KTX_FILE_OVERFLOW */
|
||||
"File read error.", /* KTX_FILE_READ_ERROR */
|
||||
"File seek error.", /* KTX_FILE_SEEK_ERROR */
|
||||
"File does not have enough data for request.", /* KTX_FILE_UNEXPECTED_EOF */
|
||||
"File write error.", /* KTX_FILE_WRITE_ERROR */
|
||||
"GL error occurred.", /* KTX_GL_ERROR */
|
||||
"Operation not allowed in the current state.", /* KTX_INVALID_OPERATION */
|
||||
"Invalid parameter value.", /* KTX_INVALID_VALUE */
|
||||
"Metadata key or loader-required GPU function not found.", /* KTX_NOT_FOUND */
|
||||
"Out of memory.", /* KTX_OUT_OF_MEMORY */
|
||||
"Transcoding of block compressed texture failed.",/* KTX_TRANSCODE_FAILED */
|
||||
"Not a KTX file.", /* KTX_UNKNOWN_FILE_FORMAT */
|
||||
"Texture type not supported.", /* KTX_UNSUPPORTED_TEXTURE_TYPE */
|
||||
"Feature not included in in-use library or not yet implemented.", /* KTX_UNSUPPORTED_FEATURE */
|
||||
"Library dependency (OpenGL or Vulkan) not linked into application.", /* KTX_LIBRARY_NOT_LINKED */
|
||||
"Decompressed byte count does not match expected byte size", /* KTX_DECOMPRESS_LENGTH_ERROR */
|
||||
"Checksum mismatch when decompressing" /* KTX_DECOMPRESS_CHECKSUM_ERROR */
|
||||
};
|
||||
/* This will cause compilation to fail if number of messages and codes doesn't match */
|
||||
typedef int errorStrings_SIZE_ASSERT[sizeof(errorStrings) / sizeof(char*) - 1 == KTX_ERROR_MAX_ENUM];
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Return a string corresponding to a KTX error code.
|
||||
*
|
||||
* @param error the error code for which to return a string
|
||||
*
|
||||
* @return pointer to the message string.
|
||||
*
|
||||
* @internal Use UTF-8 for translated message strings.
|
||||
*
|
||||
* @author Mark Callow
|
||||
*/
|
||||
const char* ktxErrorString(KTX_error_code error)
|
||||
{
|
||||
if (error < 0 || error > KTX_ERROR_MAX_ENUM)
|
||||
return "Unrecognized error code";
|
||||
return errorStrings[error];
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Return a string corresponding to a transcode format enumeration.
|
||||
*
|
||||
* @param format the transcode format for which to return a string.
|
||||
*
|
||||
* @return pointer to the message string.
|
||||
*
|
||||
* @internal Use UTF-8 for translated message strings.
|
||||
*
|
||||
* @author Mark Callow
|
||||
*/
|
||||
const char* ktxTranscodeFormatString(ktx_transcode_fmt_e format)
|
||||
{
|
||||
switch (format) {
|
||||
case KTX_TTF_ETC1_RGB: return "ETC1_RGB";
|
||||
case KTX_TTF_ETC2_RGBA: return "ETC2_RGBA";
|
||||
case KTX_TTF_BC1_RGB: return "BC1_RGB";
|
||||
case KTX_TTF_BC3_RGBA: return "BC3_RGBA";
|
||||
case KTX_TTF_BC4_R: return "BC4_R";
|
||||
case KTX_TTF_BC5_RG: return "BC5_RG";
|
||||
case KTX_TTF_BC7_RGBA: return "BC7_RGBA";
|
||||
case KTX_TTF_PVRTC1_4_RGB: return "PVRTC1_4_RGB";
|
||||
case KTX_TTF_PVRTC1_4_RGBA: return "PVRTC1_4_RGBA";
|
||||
case KTX_TTF_ASTC_4x4_RGBA: return "ASTC_4x4_RGBA";
|
||||
case KTX_TTF_RGBA32: return "RGBA32";
|
||||
case KTX_TTF_RGB565: return "RGB565";
|
||||
case KTX_TTF_BGR565: return "BGR565";
|
||||
case KTX_TTF_RGBA4444: return "RGBA4444";
|
||||
case KTX_TTF_PVRTC2_4_RGB: return "PVRTC2_4_RGB";
|
||||
case KTX_TTF_PVRTC2_4_RGBA: return "PVRTC2_4_RGBA";
|
||||
case KTX_TTF_ETC2_EAC_R11: return "ETC2_EAC_R11";
|
||||
case KTX_TTF_ETC2_EAC_RG11: return "ETC2_EAC_RG11";
|
||||
case KTX_TTF_ETC: return "ETC";
|
||||
case KTX_TTF_BC1_OR_3: return "BC1 or BC3";
|
||||
default: return "Unrecognized format";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Return a string corresponding to a supercompressionScheme enumeration.
|
||||
*
|
||||
* @param scheme the supercompression scheme for which to return a string.
|
||||
*
|
||||
* @return pointer to the message string.
|
||||
*
|
||||
* @internal Use UTF-8 for translated message strings.
|
||||
*
|
||||
* @author Mark Callow
|
||||
*/
|
||||
const char *
|
||||
ktxSupercompressionSchemeString(ktxSupercmpScheme scheme)
|
||||
{
|
||||
switch (scheme) {
|
||||
case KTX_SS_NONE: return "KTX_SS_NONE";
|
||||
case KTX_SS_BASIS_LZ: return "KTX_SS_BASIS_LZ";
|
||||
case KTX_SS_ZSTD: return "KTX_SS_ZSTD";
|
||||
case KTX_SS_ZLIB: return "KTX_SS_ZLIB";
|
||||
default:
|
||||
if (scheme < KTX_SS_BEGIN_VENDOR_RANGE
|
||||
|| scheme >= KTX_SS_BEGIN_RESERVED)
|
||||
return "Invalid scheme value";
|
||||
else
|
||||
return "Vendor or reserved scheme";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @~English
|
||||
* @brief Return a string corresponding to a bu_image_flags bit.
|
||||
*
|
||||
* @param bit_index the bu_image_flag bit to test.
|
||||
* @param bit_value the bu_image_flag bit value.
|
||||
*
|
||||
* @return pointer to the message string or NULL otherwise.
|
||||
*
|
||||
* @internal Use UTF-8 for translated message strings.
|
||||
*/
|
||||
const char* ktxBUImageFlagsBitString(ktx_uint32_t bit_index, bool bit_value)
|
||||
{
|
||||
if (!bit_value)
|
||||
return NULL;
|
||||
|
||||
switch (1u << bit_index) {
|
||||
case ETC1S_P_FRAME: return "ETC1S_P_FRAME";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/* $Id: 02ea6de2d8db512ca3af08f48b98ab5f6c35e7e5 $ */
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
#include "ktx.h"
|
||||
|
||||
/*
|
||||
* SwapEndian16: Swaps endianness in an array of 16-bit values
|
||||
*/
|
||||
void
|
||||
_ktxSwapEndian16(khronos_uint16_t* pData16, ktx_size_t count)
|
||||
{
|
||||
for (ktx_size_t i = 0; i < count; ++i)
|
||||
{
|
||||
khronos_uint16_t x = *pData16;
|
||||
*pData16++ = (x << 8) | (x >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SwapEndian32: Swaps endianness in an array of 32-bit values
|
||||
*/
|
||||
void
|
||||
_ktxSwapEndian32(khronos_uint32_t* pData32, ktx_size_t count)
|
||||
{
|
||||
for (ktx_size_t i = 0; i < count; ++i)
|
||||
{
|
||||
khronos_uint32_t x = *pData32;
|
||||
*pData32++ = (x << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SwapEndian364: Swaps endianness in an array of 32-bit values
|
||||
*/
|
||||
void
|
||||
_ktxSwapEndian64(khronos_uint64_t* pData64, ktx_size_t count)
|
||||
{
|
||||
for (ktx_size_t i = 0; i < count; ++i)
|
||||
{
|
||||
khronos_uint64_t x = *pData64;
|
||||
*pData64++ = (x << 56) | ((x & 0xFF00) << 40) | ((x & 0xFF0000) << 24)
|
||||
| ((x & 0xFF000000) << 8 ) | ((x & 0xFF00000000) >> 8)
|
||||
| ((x & 0xFF0000000000) >> 24)
|
||||
| ((x & 0xFF000000000000) << 40) | (x >> 56);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,882 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/*
|
||||
* Copyright 2018-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief ktxTexture implementation.
|
||||
*
|
||||
* @author Mark Callow, github.com/MarkCallow
|
||||
*/
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#define inline __inline
|
||||
#endif // __cplusplus
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
#include "formatsize.h"
|
||||
#include "filestream.h"
|
||||
#include "memstream.h"
|
||||
#include "texture1.h"
|
||||
#include "texture2.h"
|
||||
#include "unused.h"
|
||||
|
||||
ktx_size_t ktxTexture_GetDataSize(ktxTexture* This);
|
||||
|
||||
static ktx_uint32_t padRow(ktx_uint32_t* rowBytes);
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Construct (initialize) a ktxTexture base class instance.
|
||||
*
|
||||
* @param[in] This pointer to a ktxTexture-sized block of memory to
|
||||
* initialize.
|
||||
* @param[in] createInfo pointer to a ktxTextureCreateInfo struct with
|
||||
* information describing the texture.
|
||||
* @param[in] formatSize pointer to a ktxFormatSize giving size information
|
||||
* about the texture's elements.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a
|
||||
* valid OpenGL internal format value.
|
||||
* @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2
|
||||
* or 3.
|
||||
* @exception KTX_INVALID_VALUE One of <tt>base{Width,Height,Depth}</tt> in
|
||||
* @p createInfo is 0.
|
||||
* @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6.
|
||||
* @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The <tt>base{Width,Height,Depth}</tt> specified
|
||||
* in @p createInfo are inconsistent with
|
||||
* @c numDimensions.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* @p createInfo is requesting a 3D array or
|
||||
* 3D cubemap texture.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* @p createInfo is requesting a cubemap with
|
||||
* non-square or non-2D images.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* @p createInfo is requesting more mip levels
|
||||
* than needed for the specified
|
||||
* <tt>base{Width,Height,Depth}</tt>.
|
||||
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture_construct(ktxTexture* This,
|
||||
const ktxTextureCreateInfo* const createInfo,
|
||||
ktxFormatSize* formatSize)
|
||||
{
|
||||
DECLARE_PROTECTED(ktxTexture);
|
||||
|
||||
memset(This, 0, sizeof(*This));
|
||||
This->_protected = (struct ktxTexture_protected*)malloc(sizeof(*prtctd));
|
||||
if (!This->_protected)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
prtctd = This->_protected;
|
||||
memset(prtctd, 0, sizeof(*prtctd));
|
||||
memcpy(&prtctd->_formatSize, formatSize, sizeof(prtctd->_formatSize));
|
||||
|
||||
This->isCompressed = (formatSize->flags & KTX_FORMAT_SIZE_COMPRESSED_BIT);
|
||||
|
||||
This->orientation.x = KTX_ORIENT_X_RIGHT;
|
||||
This->orientation.y = KTX_ORIENT_Y_DOWN;
|
||||
This->orientation.z = KTX_ORIENT_Z_OUT;
|
||||
|
||||
/* Check texture dimensions. KTX files can store 8 types of textures:
|
||||
* 1D, 2D, 3D, cube, and array variants of these.
|
||||
*/
|
||||
if (createInfo->numDimensions < 1 || createInfo->numDimensions > 3)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
if (createInfo->baseWidth == 0 || createInfo->baseHeight == 0
|
||||
|| createInfo->baseDepth == 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
switch (createInfo->numDimensions) {
|
||||
case 1:
|
||||
if (createInfo->baseHeight > 1 || createInfo->baseDepth > 1)
|
||||
return KTX_INVALID_OPERATION;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (createInfo->baseDepth > 1)
|
||||
return KTX_INVALID_OPERATION;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
/* 3D array textures and 3D cubemaps are not supported by either
|
||||
* OpenGL or Vulkan.
|
||||
*/
|
||||
if (createInfo->isArray || createInfo->numFaces != 1
|
||||
|| createInfo->numLayers != 1)
|
||||
return KTX_INVALID_OPERATION;
|
||||
break;
|
||||
}
|
||||
This->numDimensions = createInfo->numDimensions;
|
||||
This->baseWidth = createInfo->baseWidth;
|
||||
This->baseDepth = createInfo->baseDepth;
|
||||
This->baseHeight = createInfo->baseHeight;
|
||||
|
||||
if (createInfo->numLayers == 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
This->numLayers = createInfo->numLayers;
|
||||
This->isArray = createInfo->isArray;
|
||||
|
||||
if (createInfo->numFaces == 6) {
|
||||
if (This->numDimensions != 2) {
|
||||
/* cube map needs 2D faces */
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
if (createInfo->baseWidth != createInfo->baseHeight) {
|
||||
/* cube maps require square images */
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
This->isCubemap = KTX_TRUE;
|
||||
} else if (createInfo->numFaces != 1) {
|
||||
/* numFaces must be either 1 or 6 */
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
This->numFaces = createInfo->numFaces;
|
||||
|
||||
/* Check number of mipmap levels */
|
||||
if (createInfo->numLevels == 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
This->numLevels = createInfo->numLevels;
|
||||
This->generateMipmaps = createInfo->generateMipmaps;
|
||||
|
||||
if (createInfo->numLevels > 1) {
|
||||
GLuint max_dim = MAX(MAX(createInfo->baseWidth, createInfo->baseHeight),
|
||||
createInfo->baseDepth);
|
||||
if (max_dim < ((GLuint)1 << (This->numLevels - 1)))
|
||||
{
|
||||
/* Can't have more mip levels than 1 + log2(max(width, height, depth)) */
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
ktxHashList_Construct(&This->kvDataHead);
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Construct (initialize) the part of a ktxTexture base class that is
|
||||
* not related to the stream contents.
|
||||
*
|
||||
* @param[in] This pointer to a ktxTexture-sized block of memory to
|
||||
* initialize.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture_constructFromStream(ktxTexture* This, ktxStream* pStream,
|
||||
ktxTextureCreateFlags createFlags)
|
||||
{
|
||||
ktxStream* stream;
|
||||
UNUSED(createFlags); // Reference to keep compiler happy.
|
||||
|
||||
assert(This != NULL);
|
||||
assert(pStream->data.mem != NULL);
|
||||
assert(pStream->type == eStreamTypeFile
|
||||
|| pStream->type == eStreamTypeMemory
|
||||
|| pStream->type == eStreamTypeCustom);
|
||||
|
||||
This->_protected = (struct ktxTexture_protected *)
|
||||
malloc(sizeof(struct ktxTexture_protected));
|
||||
stream = ktxTexture_getStream(This);
|
||||
// Copy stream info into struct for later use.
|
||||
*stream = *pStream;
|
||||
|
||||
This->orientation.x = KTX_ORIENT_X_RIGHT;
|
||||
This->orientation.y = KTX_ORIENT_Y_DOWN;
|
||||
This->orientation.z = KTX_ORIENT_Z_OUT;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Free the memory associated with the texture contents
|
||||
*
|
||||
* @param[in] This pointer to the ktxTextureInt whose texture contents are
|
||||
* to be freed.
|
||||
*/
|
||||
void
|
||||
ktxTexture_destruct(ktxTexture* This)
|
||||
{
|
||||
ktxStream stream = *(ktxTexture_getStream(This));
|
||||
|
||||
if (stream.data.file != NULL)
|
||||
stream.destruct(&stream);
|
||||
if (This->kvDataHead != NULL)
|
||||
ktxHashList_Destruct(&This->kvDataHead);
|
||||
if (This->kvData != NULL)
|
||||
free(This->kvData);
|
||||
if (This->pData != NULL)
|
||||
free(This->pData);
|
||||
free(This->_protected);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup reader Reader
|
||||
* @brief Read KTX-formatted data.
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef enum { KTX1, KTX2 } ktxFileType_;
|
||||
typedef union {
|
||||
KTX_header ktx;
|
||||
KTX_header2 ktx2;
|
||||
} ktxHeaderUnion_;
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Determine if stream data is KTX1 or KTX2.
|
||||
*
|
||||
* @param pStream pointer to the ktxStream to examine.
|
||||
* @param pFileType pointer to a ktxFileType enum where the type of the data
|
||||
* will be written.
|
||||
* @param pHeader pointer to a ktxHeaderUnion where the header info. will be
|
||||
* written.
|
||||
*/
|
||||
static KTX_error_code
|
||||
ktxDetermineFileType_(ktxStream* pStream, ktxFileType_* pFileType,
|
||||
ktxHeaderUnion_* pHeader)
|
||||
{
|
||||
ktx_uint8_t ktx_ident_ref[12] = KTX_IDENTIFIER_REF;
|
||||
ktx_uint8_t ktx2_ident_ref[12] = KTX2_IDENTIFIER_REF;
|
||||
KTX_error_code result;
|
||||
|
||||
assert(pStream != NULL && pFileType != NULL);
|
||||
assert(pStream->data.mem != NULL);
|
||||
assert(pStream->type == eStreamTypeFile
|
||||
|| pStream->type == eStreamTypeMemory
|
||||
|| pStream->type == eStreamTypeCustom);
|
||||
|
||||
result = pStream->read(pStream, pHeader, sizeof(ktx2_ident_ref));
|
||||
if (result == KTX_SUCCESS) {
|
||||
#if BIG_ENDIAN
|
||||
// byte swap the heaader fields
|
||||
#endif
|
||||
// Compare identifier, is this a KTX or KTX2 file?
|
||||
if (!memcmp(pHeader->ktx.identifier, ktx_ident_ref, 12)) {
|
||||
*pFileType = KTX1;
|
||||
} else if (!memcmp(pHeader->ktx2.identifier, ktx2_ident_ref, 12)) {
|
||||
*pFileType = KTX2;
|
||||
} else {
|
||||
return KTX_UNKNOWN_FILE_FORMAT;
|
||||
}
|
||||
// Read rest of header.
|
||||
if (*pFileType == KTX1) {
|
||||
// Read rest of header.
|
||||
result = pStream->read(pStream, &pHeader->ktx.endianness,
|
||||
KTX_HEADER_SIZE - sizeof(ktx_ident_ref));
|
||||
} else {
|
||||
result = pStream->read(pStream, &pHeader->ktx2.vkFormat,
|
||||
KTX2_HEADER_SIZE - sizeof(ktx2_ident_ref));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Create a ktx1 or ktx2 texture according to the stream
|
||||
* data.
|
||||
*
|
||||
* See @ref ktxTexture1::ktxTexture1_CreateFromStream
|
||||
* "ktxTexture1_CreateFromStream" or
|
||||
* @ref ktxTexture2::ktxTexture2_CreateFromStream
|
||||
* "ktxTexture2_CreateFromStream" for details.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture_CreateFromStream(ktxStream* pStream,
|
||||
ktxTextureCreateFlags createFlags,
|
||||
ktxTexture** newTex)
|
||||
{
|
||||
ktxHeaderUnion_ header;
|
||||
ktxFileType_ fileType;
|
||||
KTX_error_code result;
|
||||
ktxTexture* tex;
|
||||
|
||||
result = ktxDetermineFileType_(pStream, &fileType, &header);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
if (fileType == KTX1) {
|
||||
ktxTexture1* tex1 = (ktxTexture1*)malloc(sizeof(ktxTexture1));
|
||||
if (tex1 == NULL)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
memset(tex1, 0, sizeof(ktxTexture1));
|
||||
result = ktxTexture1_constructFromStreamAndHeader(tex1, pStream,
|
||||
&header.ktx,
|
||||
createFlags);
|
||||
tex = ktxTexture(tex1);
|
||||
} else {
|
||||
ktxTexture2* tex2 = (ktxTexture2*)malloc(sizeof(ktxTexture2));
|
||||
if (tex2 == NULL)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
memset(tex2, 0, sizeof(ktxTexture2));
|
||||
result = ktxTexture2_constructFromStreamAndHeader(tex2, pStream,
|
||||
&header.ktx2,
|
||||
createFlags);
|
||||
tex = ktxTexture(tex2);
|
||||
}
|
||||
|
||||
if (result == KTX_SUCCESS)
|
||||
*newTex = (ktxTexture*)tex;
|
||||
else {
|
||||
free(tex);
|
||||
*newTex = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Create a ktxTexture1 or ktxTexture2 from a stdio stream according
|
||||
* to the stream data.
|
||||
*
|
||||
* See @ref ktxTexture1::ktxTexture1_CreateFromStdioStream
|
||||
* "ktxTexture1_CreateFromStdioStream" or
|
||||
* @ref ktxTexture2::ktxTexture2_CreateFromStdioStream
|
||||
* "ktxTexture2_CreateFromStdioStream" for details.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture_CreateFromStdioStream(FILE* stdioStream,
|
||||
ktxTextureCreateFlags createFlags,
|
||||
ktxTexture** newTex)
|
||||
{
|
||||
ktxStream stream;
|
||||
KTX_error_code result;
|
||||
|
||||
if (stdioStream == NULL || newTex == NULL)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE);
|
||||
if (result == KTX_SUCCESS) {
|
||||
result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Create a ktxTexture1 or ktxTexture2 from a named KTX file according
|
||||
* to the file contents.
|
||||
*
|
||||
* See @ref ktxTexture1::ktxTexture1_CreateFromNamedFile
|
||||
* "ktxTexture1_CreateFromNamedFile" or
|
||||
* @ref ktxTexture2::ktxTexture2_CreateFromNamedFile
|
||||
* "ktxTexture2_CreateFromNamedFile" for details.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture_CreateFromNamedFile(const char* const filename,
|
||||
ktxTextureCreateFlags createFlags,
|
||||
ktxTexture** newTex)
|
||||
{
|
||||
KTX_error_code result;
|
||||
ktxStream stream;
|
||||
FILE* file;
|
||||
|
||||
if (filename == NULL || newTex == NULL)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
file = ktxFOpenUTF8(filename, "rb");
|
||||
if (!file)
|
||||
return KTX_FILE_OPEN_FAILED;
|
||||
|
||||
result = ktxFileStream_construct(&stream, file, KTX_TRUE);
|
||||
if (result == KTX_SUCCESS) {
|
||||
result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Create a ktxTexture1 or ktxTexture2 from KTX-formatted data in memory
|
||||
* according to the data contents.
|
||||
*
|
||||
* See @ref ktxTexture1::ktxTexture1_CreateFromMemory
|
||||
* "ktxTexture1_CreateFromMemory" or
|
||||
* @ref ktxTexture2::ktxTexture2_CreateFromMemory
|
||||
* "ktxTexture2_CreateFromMemory" for details.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size,
|
||||
ktxTextureCreateFlags createFlags,
|
||||
ktxTexture** newTex)
|
||||
{
|
||||
KTX_error_code result;
|
||||
ktxStream stream;
|
||||
|
||||
if (bytes == NULL || newTex == NULL || size == 0)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
result = ktxMemStream_construct_ro(&stream, bytes, size);
|
||||
if (result == KTX_SUCCESS) {
|
||||
result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
|
||||
}
|
||||
return result;}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Return a pointer to the texture image data.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
*/
|
||||
ktx_uint8_t*
|
||||
ktxTexture_GetData(ktxTexture* This)
|
||||
{
|
||||
return This->pData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Return the total size of the texture image data in bytes.
|
||||
*
|
||||
* For a ktxTexture2 with supercompressionScheme != KTX_SS_NONE this will
|
||||
* return the deflated size of the data.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
*/
|
||||
ktx_size_t
|
||||
ktxTexture_GetDataSize(ktxTexture* This)
|
||||
{
|
||||
assert(This != NULL);
|
||||
return This->dataSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Return the size in bytes of an elements of a texture's
|
||||
* images.
|
||||
*
|
||||
* For uncompressed textures an element is one texel. For compressed
|
||||
* textures it is one block.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
*/
|
||||
ktx_uint32_t
|
||||
ktxTexture_GetElementSize(ktxTexture* This)
|
||||
{
|
||||
assert (This != NULL);
|
||||
|
||||
return (This->_protected->_formatSize.blockSizeInBits / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Calculate & return the size in bytes of an image at the specified
|
||||
* mip level.
|
||||
*
|
||||
* For arrays, this is the size of layer, for cubemaps, the size of a face
|
||||
* and for 3D textures, the size of a depth slice.
|
||||
*
|
||||
* The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in] level level of interest.
|
||||
* @param[in] fv enum specifying format version for which to calculate
|
||||
* image size.
|
||||
*/
|
||||
ktx_size_t
|
||||
ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv)
|
||||
{
|
||||
DECLARE_PROTECTED(ktxTexture);
|
||||
struct blockCount {
|
||||
ktx_uint32_t x, y;
|
||||
} blockCount;
|
||||
ktx_uint32_t blockSizeInBytes;
|
||||
ktx_uint32_t rowBytes;
|
||||
|
||||
assert (This != NULL);
|
||||
|
||||
float levelWidth = (float)(This->baseWidth >> level);
|
||||
float levelHeight = (float)(This->baseHeight >> level);
|
||||
// Round up to next whole block. We can't use KTX_PADN because some of
|
||||
// the block sizes are not powers of 2.
|
||||
blockCount.x
|
||||
= (ktx_uint32_t)ceilf(levelWidth / prtctd->_formatSize.blockWidth);
|
||||
blockCount.y
|
||||
= (ktx_uint32_t)ceilf(levelHeight / prtctd->_formatSize.blockHeight);
|
||||
blockCount.x = MAX(prtctd->_formatSize.minBlocksX, blockCount.x);
|
||||
blockCount.y = MAX(prtctd->_formatSize.minBlocksY, blockCount.y);
|
||||
|
||||
blockSizeInBytes = prtctd->_formatSize.blockSizeInBits / 8;
|
||||
|
||||
if (prtctd->_formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT) {
|
||||
assert(This->isCompressed);
|
||||
return blockCount.x * blockCount.y * blockSizeInBytes;
|
||||
} else {
|
||||
assert(prtctd->_formatSize.blockWidth == 1U
|
||||
&& prtctd->_formatSize.blockHeight == 1U
|
||||
&& prtctd->_formatSize.blockDepth == 1U);
|
||||
rowBytes = blockCount.x * blockSizeInBytes;
|
||||
if (fv == KTX_FORMAT_VERSION_ONE)
|
||||
(void)padRow(&rowBytes);
|
||||
return rowBytes * blockCount.y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Iterate over the levels or faces in a ktxTexture object.
|
||||
*
|
||||
* Blocks of image data are passed to an application-supplied callback
|
||||
* function. This is not a strict per-image iteration. Rather it reflects how
|
||||
* OpenGL needs the images. For most textures the block of data includes all
|
||||
* images of a mip level which implies all layers of an array. However, for
|
||||
* non-array cube map textures the block is a single face of the mip level,
|
||||
* i.e the callback is called once for each face.
|
||||
*
|
||||
* This function works even if @p This->pData == 0 so it can be used to
|
||||
* obtain offsets and sizes for each level by callers who have loaded the data
|
||||
* externally.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in,out] iterCb the address of a callback function which is called
|
||||
* with the data for each image block.
|
||||
* @param[in,out] userdata the address of application-specific data which is
|
||||
* passed to the callback along with the image data.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error. The
|
||||
* following are returned directly by this function. @p iterCb may
|
||||
* return these for other causes or may return additional errors.
|
||||
*
|
||||
* @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not
|
||||
* decreasing
|
||||
* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.
|
||||
*
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture_IterateLevelFaces(ktxTexture* This, PFNKTXITERCB iterCb,
|
||||
void* userdata)
|
||||
{
|
||||
ktx_uint32_t miplevel;
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
|
||||
if (This == NULL)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
if (iterCb == NULL)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
for (miplevel = 0; miplevel < This->numLevels; ++miplevel)
|
||||
{
|
||||
ktx_uint32_t faceLodSize;
|
||||
ktx_uint32_t face;
|
||||
ktx_uint32_t innerIterations;
|
||||
GLsizei width, height, depth;
|
||||
|
||||
/* Array textures have the same number of layers at each mip level. */
|
||||
width = MAX(1, This->baseWidth >> miplevel);
|
||||
height = MAX(1, This->baseHeight >> miplevel);
|
||||
depth = MAX(1, This->baseDepth >> miplevel);
|
||||
|
||||
faceLodSize = (ktx_uint32_t)ktxTexture_calcFaceLodSize(
|
||||
This, miplevel);
|
||||
|
||||
/* All array layers are passed in a group because that is how
|
||||
* GL & Vulkan need them. Hence no
|
||||
* for (layer = 0; layer < This->numLayers)
|
||||
*/
|
||||
if (This->isCubemap && !This->isArray)
|
||||
innerIterations = This->numFaces;
|
||||
else
|
||||
innerIterations = 1;
|
||||
for (face = 0; face < innerIterations; ++face)
|
||||
{
|
||||
/* And all z_slices are also passed as a group hence no
|
||||
* for (slice = 0; slice < This->depth)
|
||||
*/
|
||||
ktx_size_t offset;
|
||||
|
||||
ktxTexture_GetImageOffset(This, miplevel, 0, face, &offset);
|
||||
result = iterCb(miplevel, face,
|
||||
width, height, depth,
|
||||
faceLodSize, This->pData + offset, userdata);
|
||||
|
||||
if (result != KTX_SUCCESS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Calculate and apply the padding needed to comply with
|
||||
* KTX_GL_UNPACK_ALIGNMENT.
|
||||
*
|
||||
* For uncompressed textures, KTX format specifies KTX_GL_UNPACK_ALIGNMENT = 4.
|
||||
*
|
||||
* @param[in,out] rowBytes pointer to variable containing the packed no. of
|
||||
* bytes in a row. The no. of bytes after padding
|
||||
* is written into this location.
|
||||
* @return the no. of bytes of padding.
|
||||
*/
|
||||
static ktx_uint32_t
|
||||
padRow(ktx_uint32_t* rowBytes)
|
||||
{
|
||||
ktx_uint32_t rowPadding;
|
||||
|
||||
assert (rowBytes != NULL);
|
||||
|
||||
rowPadding = _KTX_PAD_UNPACK_ALIGN_LEN(*rowBytes);
|
||||
*rowBytes += rowPadding;
|
||||
return rowPadding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Calculate the size of an array layer at the specified mip level.
|
||||
*
|
||||
* The size of a layer is the size of an image * either the number of faces
|
||||
* or the number of depth slices. This is the size of a layer as needed to
|
||||
* find the offset within the array of images of a level and layer so the size
|
||||
* reflects any @c cubePadding.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in] level level whose layer size to return.
|
||||
*
|
||||
* @return the layer size in bytes.
|
||||
*/
|
||||
ktx_size_t
|
||||
ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv)
|
||||
{
|
||||
/*
|
||||
* As there are no 3D cubemaps, the image's z block count will always be
|
||||
* 1 for cubemaps and numFaces will always be 1 for 3D textures so the
|
||||
* multiply is safe. 3D cubemaps, if they existed, would require
|
||||
* imageSize * (blockCount.z + This->numFaces);
|
||||
*/
|
||||
DECLARE_PROTECTED(ktxTexture);
|
||||
ktx_uint32_t blockCountZ;
|
||||
ktx_size_t imageSize, layerSize;
|
||||
|
||||
assert (This != NULL);
|
||||
assert (prtctd->_formatSize.blockDepth != 0);
|
||||
|
||||
blockCountZ = ((This->baseDepth >> level) + prtctd->_formatSize.blockDepth - 1) / prtctd->_formatSize.blockDepth;
|
||||
blockCountZ = MAX(1, blockCountZ);
|
||||
imageSize = ktxTexture_calcImageSize(This, level, fv);
|
||||
layerSize = imageSize * blockCountZ;
|
||||
if (fv == KTX_FORMAT_VERSION_ONE && KTX_GL_UNPACK_ALIGNMENT != 4) {
|
||||
if (This->isCubemap && !This->isArray) {
|
||||
/* cubePadding. NOTE: this adds padding after the last face too. */
|
||||
layerSize += _KTX_PAD4(layerSize);
|
||||
}
|
||||
}
|
||||
return layerSize * This->numFaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Calculate the size of the specified mip level.
|
||||
*
|
||||
* The size of a level is the size of a layer * the number of layers.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in] level level whose layer size to return.
|
||||
*
|
||||
* @return the level size in bytes.
|
||||
*/
|
||||
ktx_size_t
|
||||
ktxTexture_calcLevelSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv)
|
||||
{
|
||||
assert (This != NULL);
|
||||
assert (level < This->numLevels);
|
||||
return ktxTexture_layerSize(This, level, fv) * This->numLayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Calculate the faceLodSize of the specified mip level.
|
||||
*
|
||||
* The faceLodSize of a level for most textures is the size of a level. For
|
||||
* non-array cube map textures is the size of a face. This is the size that
|
||||
* must be provided to OpenGL when uploading textures. Faces get uploaded 1
|
||||
* at a time while all layers of an array or all slices of a 3D texture are
|
||||
* uploaded together.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in] level level whose layer size to return.
|
||||
*
|
||||
* @return the faceLodSize size in bytes.
|
||||
*/
|
||||
ktx_size_t
|
||||
ktxTexture_doCalcFaceLodSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv)
|
||||
{
|
||||
/*
|
||||
* For non-array cubemaps this is the size of a face. For everything
|
||||
* else it is the size of the level.
|
||||
*/
|
||||
if (This->isCubemap && !This->isArray)
|
||||
return ktxTexture_calcImageSize(This, level, fv);
|
||||
else
|
||||
return ktxTexture_calcLevelSize(This, level, fv);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Return the number of bytes needed to store all the image data for
|
||||
* a ktxTexture.
|
||||
*
|
||||
* The caclulated size does not include space for storing the @c imageSize
|
||||
* fields of each mip level.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in] fv enum specifying format version for which to calculate
|
||||
* image size.
|
||||
*
|
||||
* @return the data size in bytes.
|
||||
*/
|
||||
ktx_size_t
|
||||
ktxTexture_calcDataSizeTexture(ktxTexture* This)
|
||||
{
|
||||
assert (This != NULL);
|
||||
return ktxTexture_calcDataSizeLevels(This, This->numLevels);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Get information about rows of an uncompresssed texture image at a
|
||||
* specified level.
|
||||
*
|
||||
* For an image at @p level of a ktxTexture provide the number of rows, the
|
||||
* packed (unpadded) number of bytes in a row and the padding necessary to
|
||||
* comply with KTX_GL_UNPACK_ALIGNMENT.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in] level level of interest.
|
||||
* @param[in,out] numRows pointer to location to store the number of rows.
|
||||
* @param[in,out] pRowLengthBytes pointer to location to store number of bytes
|
||||
* in a row.
|
||||
* @param[in.out] pRowPadding pointer to location to store the number of bytes
|
||||
* of padding.
|
||||
*/
|
||||
void
|
||||
ktxTexture_rowInfo(ktxTexture* This, ktx_uint32_t level,
|
||||
ktx_uint32_t* numRows, ktx_uint32_t* pRowLengthBytes,
|
||||
ktx_uint32_t* pRowPadding)
|
||||
{
|
||||
DECLARE_PROTECTED(ktxTexture);
|
||||
struct blockCount {
|
||||
ktx_uint32_t x;
|
||||
} blockCount;
|
||||
|
||||
assert (This != NULL);
|
||||
|
||||
assert(!This->isCompressed);
|
||||
assert(prtctd->_formatSize.blockWidth == 1U
|
||||
&& prtctd->_formatSize.blockHeight == 1U
|
||||
&& prtctd->_formatSize.blockDepth == 1U);
|
||||
|
||||
blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level);
|
||||
*numRows = MAX(1, (This->baseHeight / prtctd->_formatSize.blockHeight) >> level);
|
||||
|
||||
*pRowLengthBytes = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8;
|
||||
*pRowPadding = padRow(pRowLengthBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
* @brief Return pitch between rows of a texture image level in bytes.
|
||||
*
|
||||
* For uncompressed textures the pitch is the number of bytes between
|
||||
* rows of texels. For compressed textures it is the number of bytes
|
||||
* between rows of blocks. The value is padded to GL_UNPACK_ALIGNMENT,
|
||||
* if necessary. For all currently known compressed formats padding
|
||||
* will not be necessary.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
* @param[in] level level of interest.
|
||||
*
|
||||
* @return the row pitch in bytes.
|
||||
*/
|
||||
ktx_uint32_t
|
||||
ktxTexture_GetRowPitch(ktxTexture* This, ktx_uint32_t level)
|
||||
{
|
||||
DECLARE_PROTECTED(ktxTexture)
|
||||
struct blockCount {
|
||||
ktx_uint32_t x;
|
||||
} blockCount;
|
||||
ktx_uint32_t pitch;
|
||||
|
||||
blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level);
|
||||
pitch = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8;
|
||||
(void)padRow(&pitch);
|
||||
|
||||
return pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Query if a ktxTexture has an active stream.
|
||||
*
|
||||
* Tests if a ktxTexture has unread image data. The internal stream is closed
|
||||
* once all the images have been read.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture object of interest.
|
||||
*
|
||||
* @return KTX_TRUE if there is an active stream, KTX_FALSE otherwise.
|
||||
*/
|
||||
ktx_bool_t
|
||||
ktxTexture_isActiveStream(ktxTexture* This)
|
||||
{
|
||||
assert(This != NULL);
|
||||
ktxStream* stream = ktxTexture_getStream(This);
|
||||
return stream->data.file != NULL;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2019-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Declare internal ktxTexture functions for sharing between
|
||||
* compilation units.
|
||||
*
|
||||
* These functions are private and should not be used outside the library.
|
||||
*/
|
||||
|
||||
#ifndef _TEXTURE_H_
|
||||
#define _TEXTURE_H_
|
||||
|
||||
#include "ktx.h"
|
||||
#include "formatsize.h"
|
||||
|
||||
#define DECLARE_PRIVATE(class) class ## _private* private = This->_private
|
||||
#define DECLARE_PROTECTED(class) class ## _protected* prtctd = This->_protected;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
KTX_FORMAT_VERSION_ONE = 1,
|
||||
KTX_FORMAT_VERSION_TWO = 2
|
||||
} ktxFormatVersionEnum;
|
||||
|
||||
typedef ktx_size_t (* PFNCALCDATASIZELEVELS)(ktxTexture* This,
|
||||
ktx_uint32_t levels);
|
||||
typedef ktx_size_t (* PFNCALCFACELODSIZE)(ktxTexture* This, ktx_uint32_t level);
|
||||
typedef ktx_size_t (* PFNCALCLEVELOFFSET)(ktxTexture* This, ktx_uint32_t level);
|
||||
typedef struct ktxTexture_vtblInt {
|
||||
PFNCALCDATASIZELEVELS calcDataSizeLevels;
|
||||
PFNCALCFACELODSIZE calcFaceLodSize;
|
||||
PFNCALCLEVELOFFSET calcLevelOffset;
|
||||
} ktxTexture_vtblInt;
|
||||
|
||||
#define ktxTexture_calcDataSizeLevels(This, levels) \
|
||||
This->_protected->_vtbl.calcDataSizeLevels(This, levels);
|
||||
#define ktxTexture_calcFaceLodSize(This, level) \
|
||||
This->_protected->_vtbl.calcFaceLodSize(This, level);
|
||||
#define ktxTexture_calcLevelOffset(This, level) \
|
||||
This->_protected->_vtbl.calcLevelOffset(This, level);
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture
|
||||
* @~English
|
||||
*
|
||||
* @brief protected members of ktxTexture.
|
||||
*/
|
||||
typedef struct ktxTexture_protected {
|
||||
ktxTexture_vtblInt _vtbl;
|
||||
ktxFormatSize _formatSize;
|
||||
ktx_uint32_t _typeSize;
|
||||
ktxStream _stream;
|
||||
} ktxTexture_protected;
|
||||
|
||||
#define ktxTexture_getStream(t) ((ktxStream*)(&(t)->_protected->_stream))
|
||||
#define ktxTexture1_getStream(t1) ktxTexture_getStream((ktxTexture*)t1)
|
||||
#define ktxTexture2_getStream(t2) ktxTexture_getStream((ktxTexture*)t2)
|
||||
|
||||
KTX_error_code
|
||||
ktxTexture_iterateLoadedImages(ktxTexture* This, PFNKTXITERCB iterCb,
|
||||
void* userdata);
|
||||
KTX_error_code
|
||||
ktxTexture_iterateSourceImages(ktxTexture* This, PFNKTXITERCB iterCb,
|
||||
void* userdata);
|
||||
|
||||
ktx_size_t ktxTexture_calcDataSizeTexture(ktxTexture* This);
|
||||
ktx_size_t ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv);
|
||||
ktx_bool_t ktxTexture_isActiveStream(ktxTexture* This);
|
||||
ktx_size_t ktxTexture_calcLevelSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv);
|
||||
ktx_size_t ktxTexture_doCalcFaceLodSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv);
|
||||
ktx_size_t ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level,
|
||||
ktxFormatVersionEnum fv);
|
||||
void ktxTexture_rowInfo(ktxTexture* This, ktx_uint32_t level,
|
||||
ktx_uint32_t* numRows, ktx_uint32_t* rowBytes,
|
||||
ktx_uint32_t* rowPadding);
|
||||
KTX_error_code
|
||||
ktxTexture_construct(ktxTexture* This,
|
||||
const ktxTextureCreateInfo* const createInfo,
|
||||
ktxFormatSize* formatSize);
|
||||
|
||||
KTX_error_code
|
||||
ktxTexture_constructFromStream(ktxTexture* This, ktxStream* pStream,
|
||||
ktxTextureCreateFlags createFlags);
|
||||
|
||||
void
|
||||
ktxTexture_destruct(ktxTexture* This);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TEXTURE_H_ */
|
||||
+1496
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2019-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Declare internal ktxTexture1 functions for sharing between
|
||||
* compilation units.
|
||||
*
|
||||
* These functions are private and should not be used outside the library.
|
||||
*/
|
||||
|
||||
#ifndef _TEXTURE1_H_
|
||||
#define _TEXTURE1_H_
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CLASS ktxTexture1
|
||||
#include "texture_funcs.inl"
|
||||
#undef CLASS
|
||||
|
||||
KTX_error_code
|
||||
ktxTexture1_constructFromStreamAndHeader(ktxTexture1* This, ktxStream* pStream,
|
||||
KTX_header* pHeader,
|
||||
ktxTextureCreateFlags createFlags);
|
||||
|
||||
ktx_uint64_t ktxTexture1_calcDataSizeTexture(ktxTexture1* This);
|
||||
ktx_size_t ktxTexture1_calcLevelOffset(ktxTexture1* This, ktx_uint32_t level);
|
||||
ktx_uint32_t ktxTexture1_glTypeSize(ktxTexture1* This);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TEXTURE1_H_ */
|
||||
+3043
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2019-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Declare internal ktxTexture2 functions for sharing between
|
||||
* compilation units.
|
||||
*
|
||||
* These functions are private and should not be used outside the library.
|
||||
*/
|
||||
|
||||
#ifndef _TEXTURE2_H_
|
||||
#define _TEXTURE2_H_
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CLASS ktxTexture2
|
||||
#include "texture_funcs.inl"
|
||||
#undef CLASS
|
||||
|
||||
typedef struct ktxTexture2_private {
|
||||
ktx_uint8_t* _supercompressionGlobalData;
|
||||
ktx_uint32_t _requiredLevelAlignment;
|
||||
ktx_uint64_t _sgdByteLength;
|
||||
ktx_uint64_t _firstLevelFileOffset; /*!< Always 0, unless the texture was
|
||||
created from a stream and the image
|
||||
data is not yet loaded. */
|
||||
// Must be last so it can grow.
|
||||
ktxLevelIndexEntry _levelIndex[1]; /*!< Offsets in this index are from the
|
||||
start of the image data. Use
|
||||
ktxTexture_levelStreamOffset() and
|
||||
ktxTexture_levelDataOffset(). The former
|
||||
will add the above file offset to the
|
||||
index offset. */
|
||||
} ktxTexture2_private;
|
||||
|
||||
|
||||
KTX_error_code
|
||||
ktxTexture2_constructCopy(ktxTexture2* This, ktxTexture2* orig);
|
||||
KTX_error_code
|
||||
ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream,
|
||||
KTX_header2* pHeader,
|
||||
ktxTextureCreateFlags createFlags);
|
||||
|
||||
ktx_uint64_t ktxTexture2_calcDataSizeTexture(ktxTexture2* This);
|
||||
ktx_size_t ktxTexture2_calcLevelOffset(ktxTexture2* This, ktx_uint32_t level);
|
||||
ktx_uint32_t ktxTexture2_calcRequiredLevelAlignment(ktxTexture2* This);
|
||||
ktx_uint64_t ktxTexture2_levelFileOffset(ktxTexture2* This, ktx_uint32_t level);
|
||||
ktx_uint64_t ktxTexture2_levelDataOffset(ktxTexture2* This, ktx_uint32_t level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TEXTURE2_H_ */
|
||||
@@ -0,0 +1,61 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2019-2020 The Khronos Group Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Templates for functions common to base & derived ktxTexture classes.
|
||||
*
|
||||
* Define CLASS before including this file.
|
||||
*/
|
||||
|
||||
#define CAT(c, n) PRIMITIVE_CAT(c, n)
|
||||
#define PRIMITIVE_CAT(c, n) c ## _ ## n
|
||||
|
||||
#define CLASS_FUNC(name) CAT(CLASS, name)
|
||||
|
||||
/*
|
||||
======================================
|
||||
Virtual ktxTexture functions
|
||||
======================================
|
||||
*/
|
||||
|
||||
|
||||
ktx_size_t CLASS_FUNC(GetImageSize)(CLASS* This, ktx_uint32_t level);
|
||||
KTX_error_code CLASS_FUNC(GLUpload)(CLASS* This, GLuint* pTexture,
|
||||
GLenum* pTarget, GLenum* pGlerror);
|
||||
KTX_error_code CLASS_FUNC(IterateLevels)(CLASS* This,
|
||||
PFNKTXITERCB iterCb,
|
||||
void* userdata);
|
||||
KTX_error_code CLASS_FUNC(IterateLevelFaces)(CLASS* This,
|
||||
PFNKTXITERCB iterCb,
|
||||
void* userdata);
|
||||
KTX_error_code CLASS_FUNC(IterateLoadLevelFaces)(CLASS* This,
|
||||
PFNKTXITERCB iterCb,
|
||||
void* userdata);
|
||||
KTX_error_code CLASS_FUNC(SetImageFromStdioStream)(CLASS* This,
|
||||
ktx_uint32_t level,ktx_uint32_t layer,
|
||||
ktx_uint32_t faceSlice,
|
||||
FILE* src, ktx_size_t srcSize);
|
||||
KTX_error_code CLASS_FUNC(SetImageFromMemory)(CLASS* This,
|
||||
ktx_uint32_t level, ktx_uint32_t layer,
|
||||
ktx_uint32_t faceSlice,
|
||||
const ktx_uint8_t* src, ktx_size_t srcSize);
|
||||
|
||||
|
||||
/*
|
||||
======================================
|
||||
Internal ktxTexture functions
|
||||
======================================
|
||||
*/
|
||||
|
||||
|
||||
void CLASS_FUNC(destruct)(CLASS* This);
|
||||
|
||||
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
Copyright (c) 2003-2010, Troy D. Hanson http://uthash.sourceforge.net All rights reserved.
|
||||
SPDX-License-Identifier: BSD-1-Clause
|
||||
*/
|
||||
|
||||
#ifndef UTHASH_H
|
||||
#define UTHASH_H
|
||||
|
||||
#include <string.h> /* memcmp,strlen */
|
||||
#include <stddef.h> /* ptrdiff_t */
|
||||
|
||||
/* These macros use decltype or the earlier __typeof GNU extension.
|
||||
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
|
||||
when compiling c++ source) this code uses whatever method is needed
|
||||
or, for VS2008 where neither is available, uses casting workarounds. */
|
||||
#ifdef _MSC_VER /* MS compiler */
|
||||
#if _MSC_VER >= 1600 && __cplusplus /* VS2010 or newer in C++ mode */
|
||||
#define DECLTYPE(x) (decltype(x))
|
||||
#else /* VS2008 or older (or VS2010 in C mode) */
|
||||
#define NO_DECLTYPE
|
||||
#define DECLTYPE(x)
|
||||
#endif
|
||||
#else /* GNU, Sun and other compilers */
|
||||
#define DECLTYPE(x) (__typeof(x))
|
||||
#endif
|
||||
|
||||
#ifdef NO_DECLTYPE
|
||||
#define DECLTYPE_ASSIGN(dst,src) \
|
||||
do { \
|
||||
char **_da_dst = (char**)(&(dst)); \
|
||||
*_da_dst = (char*)(src); \
|
||||
} while(0)
|
||||
#else
|
||||
#define DECLTYPE_ASSIGN(dst,src) \
|
||||
do { \
|
||||
(dst) = DECLTYPE(dst)(src); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/* a number of the hash function use uint32_t which isn't defined on win32 */
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
#include <inttypes.h> /* uint32_t */
|
||||
#endif
|
||||
|
||||
#define UTHASH_VERSION 1.9.1
|
||||
|
||||
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
|
||||
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
|
||||
#define uthash_free(ptr) free(ptr) /* free fcn */
|
||||
|
||||
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
|
||||
#define uthash_expand_fyi(tbl) /* can be defined to log expands */
|
||||
|
||||
/* initial number of buckets */
|
||||
#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
|
||||
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
|
||||
#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
|
||||
|
||||
/* calculate the element whose hash handle address is hhe */
|
||||
#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
|
||||
|
||||
#define HASH_FIND(hh,head,keyptr,keylen,out) \
|
||||
do { \
|
||||
unsigned _hf_bkt,_hf_hashv; \
|
||||
out=NULL; \
|
||||
if (head) { \
|
||||
HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
|
||||
if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
|
||||
HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
|
||||
keyptr,keylen,out); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef HASH_BLOOM
|
||||
#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
|
||||
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
|
||||
#define HASH_BLOOM_MAKE(tbl) \
|
||||
do { \
|
||||
(tbl)->bloom_nbits = HASH_BLOOM; \
|
||||
(tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
|
||||
if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
|
||||
memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
|
||||
(tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
|
||||
} while (0);
|
||||
|
||||
#define HASH_BLOOM_FREE(tbl) \
|
||||
do { \
|
||||
uthash_free((tbl)->bloom_bv); \
|
||||
} while (0);
|
||||
|
||||
#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
|
||||
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
|
||||
|
||||
#define HASH_BLOOM_ADD(tbl,hashv) \
|
||||
HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
|
||||
|
||||
#define HASH_BLOOM_TEST(tbl,hashv) \
|
||||
HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
|
||||
|
||||
#else
|
||||
#define HASH_BLOOM_MAKE(tbl)
|
||||
#define HASH_BLOOM_FREE(tbl)
|
||||
#define HASH_BLOOM_ADD(tbl,hashv)
|
||||
#define HASH_BLOOM_TEST(tbl,hashv) (1)
|
||||
#endif
|
||||
|
||||
#define HASH_MAKE_TABLE(hh,head) \
|
||||
do { \
|
||||
(head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
|
||||
sizeof(UT_hash_table)); \
|
||||
if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
|
||||
memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
|
||||
(head)->hh.tbl->tail = &((head)->hh); \
|
||||
(head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
|
||||
(head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
|
||||
(head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
|
||||
(head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
|
||||
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
|
||||
if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
|
||||
memset((head)->hh.tbl->buckets, 0, \
|
||||
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
|
||||
HASH_BLOOM_MAKE((head)->hh.tbl); \
|
||||
(head)->hh.tbl->signature = HASH_SIGNATURE; \
|
||||
} while(0)
|
||||
|
||||
#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
|
||||
HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add)
|
||||
|
||||
#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
|
||||
do { \
|
||||
unsigned _ha_bkt; \
|
||||
(add)->hh.next = NULL; \
|
||||
(add)->hh.key = (char*)keyptr; \
|
||||
(add)->hh.keylen = keylen_in; \
|
||||
if (!(head)) { \
|
||||
head = (add); \
|
||||
(head)->hh.prev = NULL; \
|
||||
HASH_MAKE_TABLE(hh,head); \
|
||||
} else { \
|
||||
(head)->hh.tbl->tail->next = (add); \
|
||||
(add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
|
||||
(head)->hh.tbl->tail = &((add)->hh); \
|
||||
} \
|
||||
(head)->hh.tbl->num_items++; \
|
||||
(add)->hh.tbl = (head)->hh.tbl; \
|
||||
HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
|
||||
(add)->hh.hashv, _ha_bkt); \
|
||||
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
|
||||
HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
|
||||
HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
|
||||
HASH_FSCK(hh,head); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
|
||||
do { \
|
||||
bkt = ((hashv) & ((num_bkts) - 1)); \
|
||||
} while(0)
|
||||
|
||||
/* delete "delptr" from the hash table.
|
||||
* "the usual" patch-up process for the app-order doubly-linked-list.
|
||||
* The use of _hd_hh_del below deserves special explanation.
|
||||
* These used to be expressed using (delptr) but that led to a bug
|
||||
* if someone used the same symbol for the head and deletee, like
|
||||
* HASH_DELETE(hh,users,users);
|
||||
* We want that to work, but by changing the head (users) below
|
||||
* we were forfeiting our ability to further refer to the deletee (users)
|
||||
* in the patch-up process. Solution: use scratch space to
|
||||
* copy the deletee pointer, then the latter references are via that
|
||||
* scratch pointer rather than through the repointed (users) symbol.
|
||||
*/
|
||||
#define HASH_DELETE(hh,head,delptr) \
|
||||
do { \
|
||||
unsigned _hd_bkt; \
|
||||
struct UT_hash_handle *_hd_hh_del; \
|
||||
if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
|
||||
uthash_free((head)->hh.tbl->buckets ); \
|
||||
HASH_BLOOM_FREE((head)->hh.tbl); \
|
||||
uthash_free((head)->hh.tbl); \
|
||||
head = NULL; \
|
||||
} else { \
|
||||
_hd_hh_del = &((delptr)->hh); \
|
||||
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
|
||||
(head)->hh.tbl->tail = \
|
||||
(UT_hash_handle*)((char*)((delptr)->hh.prev) + \
|
||||
(head)->hh.tbl->hho); \
|
||||
} \
|
||||
if ((delptr)->hh.prev) { \
|
||||
((UT_hash_handle*)((char*)((delptr)->hh.prev) + \
|
||||
(head)->hh.tbl->hho))->next = (delptr)->hh.next; \
|
||||
} else { \
|
||||
DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
|
||||
} \
|
||||
if (_hd_hh_del->next) { \
|
||||
((UT_hash_handle*)((char*)_hd_hh_del->next + \
|
||||
(head)->hh.tbl->hho))->prev = \
|
||||
_hd_hh_del->prev; \
|
||||
} \
|
||||
HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
|
||||
HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
|
||||
(head)->hh.tbl->num_items--; \
|
||||
} \
|
||||
HASH_FSCK(hh,head); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
|
||||
#define HASH_FIND_STR(head,findstr,out) \
|
||||
HASH_FIND(hh,head,findstr,strlen(findstr),out)
|
||||
#define HASH_ADD_STR(head,strfield,add) \
|
||||
HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
|
||||
#define HASH_FIND_INT(head,findint,out) \
|
||||
HASH_FIND(hh,head,findint,sizeof(int),out)
|
||||
#define HASH_ADD_INT(head,intfield,add) \
|
||||
HASH_ADD(hh,head,intfield,sizeof(int),add)
|
||||
#define HASH_FIND_PTR(head,findptr,out) \
|
||||
HASH_FIND(hh,head,findptr,sizeof(void *),out)
|
||||
#define HASH_ADD_PTR(head,ptrfield,add) \
|
||||
HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
|
||||
#define HASH_DEL(head,delptr) \
|
||||
HASH_DELETE(hh,head,delptr)
|
||||
|
||||
/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
|
||||
* This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
|
||||
*/
|
||||
#ifdef HASH_DEBUG
|
||||
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
|
||||
#define HASH_FSCK(hh,head) \
|
||||
do { \
|
||||
unsigned _bkt_i; \
|
||||
unsigned _count, _bkt_count; \
|
||||
char *_prev; \
|
||||
struct UT_hash_handle *_thh; \
|
||||
if (head) { \
|
||||
_count = 0; \
|
||||
for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
|
||||
_bkt_count = 0; \
|
||||
_thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
|
||||
_prev = NULL; \
|
||||
while (_thh) { \
|
||||
if (_prev != (char*)(_thh->hh_prev)) { \
|
||||
HASH_OOPS("invalid hh_prev %p, actual %p\n", \
|
||||
_thh->hh_prev, _prev ); \
|
||||
} \
|
||||
_bkt_count++; \
|
||||
_prev = (char*)(_thh); \
|
||||
_thh = _thh->hh_next; \
|
||||
} \
|
||||
_count += _bkt_count; \
|
||||
if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
|
||||
HASH_OOPS("invalid bucket count %d, actual %d\n", \
|
||||
(head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
|
||||
} \
|
||||
} \
|
||||
if (_count != (head)->hh.tbl->num_items) { \
|
||||
HASH_OOPS("invalid hh item count %d, actual %d\n", \
|
||||
(head)->hh.tbl->num_items, _count ); \
|
||||
} \
|
||||
/* traverse hh in app order; check next/prev integrity, count */ \
|
||||
_count = 0; \
|
||||
_prev = NULL; \
|
||||
_thh = &(head)->hh; \
|
||||
while (_thh) { \
|
||||
_count++; \
|
||||
if (_prev !=(char*)(_thh->prev)) { \
|
||||
HASH_OOPS("invalid prev %p, actual %p\n", \
|
||||
_thh->prev, _prev ); \
|
||||
} \
|
||||
_prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
|
||||
_thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
|
||||
(head)->hh.tbl->hho) : NULL ); \
|
||||
} \
|
||||
if (_count != (head)->hh.tbl->num_items) { \
|
||||
HASH_OOPS("invalid app item count %d, actual %d\n", \
|
||||
(head)->hh.tbl->num_items, _count ); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define HASH_FSCK(hh,head)
|
||||
#endif
|
||||
|
||||
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
|
||||
* the descriptor to which this macro is defined for tuning the hash function.
|
||||
* The app can #include <unistd.h> to get the prototype for write(2). */
|
||||
#ifdef HASH_EMIT_KEYS
|
||||
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
|
||||
do { \
|
||||
unsigned _klen = fieldlen; \
|
||||
write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
|
||||
write(HASH_EMIT_KEYS, keyptr, fieldlen); \
|
||||
} while (0)
|
||||
#else
|
||||
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
|
||||
#endif
|
||||
|
||||
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
|
||||
#ifdef HASH_FUNCTION
|
||||
#define HASH_FCN HASH_FUNCTION
|
||||
#else
|
||||
#define HASH_FCN HASH_JEN
|
||||
#endif
|
||||
|
||||
/* The Bernstein hash function, used in Perl prior to v5.6 */
|
||||
#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _hb_keylen=keylen; \
|
||||
char *_hb_key=(char*)key; \
|
||||
(hashv) = 0; \
|
||||
while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \
|
||||
bkt = (hashv) & (num_bkts-1); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
|
||||
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
|
||||
#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _sx_i; \
|
||||
char *_hs_key=(char*)key; \
|
||||
hashv = 0; \
|
||||
for(_sx_i=0; _sx_i < keylen; _sx_i++) \
|
||||
hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _fn_i; \
|
||||
char *_hf_key=(char*)key; \
|
||||
hashv = 2166136261UL; \
|
||||
for(_fn_i=0; _fn_i < keylen; _fn_i++) \
|
||||
hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0);
|
||||
|
||||
#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _ho_i; \
|
||||
char *_ho_key=(char*)key; \
|
||||
hashv = 0; \
|
||||
for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
|
||||
hashv += _ho_key[_ho_i]; \
|
||||
hashv += (hashv << 10); \
|
||||
hashv ^= (hashv >> 6); \
|
||||
} \
|
||||
hashv += (hashv << 3); \
|
||||
hashv ^= (hashv >> 11); \
|
||||
hashv += (hashv << 15); \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_JEN_MIX(a,b,c) \
|
||||
do { \
|
||||
a -= b; a -= c; a ^= ( c >> 13 ); \
|
||||
b -= c; b -= a; b ^= ( a << 8 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 13 ); \
|
||||
a -= b; a -= c; a ^= ( c >> 12 ); \
|
||||
b -= c; b -= a; b ^= ( a << 16 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 5 ); \
|
||||
a -= b; a -= c; a ^= ( c >> 3 ); \
|
||||
b -= c; b -= a; b ^= ( a << 10 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 15 ); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _hj_i,_hj_j,_hj_k; \
|
||||
char *_hj_key=(char*)key; \
|
||||
hashv = 0xfeedbeef; \
|
||||
_hj_i = _hj_j = 0x9e3779b9; \
|
||||
_hj_k = keylen; \
|
||||
while (_hj_k >= 12) { \
|
||||
_hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[2] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[3] << 24 ) ); \
|
||||
_hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[6] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[7] << 24 ) ); \
|
||||
hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[10] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[11] << 24 ) ); \
|
||||
\
|
||||
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
|
||||
\
|
||||
_hj_key += 12; \
|
||||
_hj_k -= 12; \
|
||||
} \
|
||||
hashv += keylen; \
|
||||
switch ( _hj_k ) { \
|
||||
case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
|
||||
case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
|
||||
case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
|
||||
case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
|
||||
case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
|
||||
case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
|
||||
case 5: _hj_j += _hj_key[4]; \
|
||||
case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
|
||||
case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
|
||||
case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
|
||||
case 1: _hj_i += _hj_key[0]; \
|
||||
} \
|
||||
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
/* The Paul Hsieh hash function */
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
char *_sfh_key=(char*)key; \
|
||||
uint32_t _sfh_tmp, _sfh_len = keylen; \
|
||||
\
|
||||
int _sfh_rem = _sfh_len & 3; \
|
||||
_sfh_len >>= 2; \
|
||||
hashv = 0xcafebabe; \
|
||||
\
|
||||
/* Main loop */ \
|
||||
for (;_sfh_len > 0; _sfh_len--) { \
|
||||
hashv += get16bits (_sfh_key); \
|
||||
_sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \
|
||||
hashv = (hashv << 16) ^ _sfh_tmp; \
|
||||
_sfh_key += 2*sizeof (uint16_t); \
|
||||
hashv += hashv >> 11; \
|
||||
} \
|
||||
\
|
||||
/* Handle end cases */ \
|
||||
switch (_sfh_rem) { \
|
||||
case 3: hashv += get16bits (_sfh_key); \
|
||||
hashv ^= hashv << 16; \
|
||||
hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \
|
||||
hashv += hashv >> 11; \
|
||||
break; \
|
||||
case 2: hashv += get16bits (_sfh_key); \
|
||||
hashv ^= hashv << 11; \
|
||||
hashv += hashv >> 17; \
|
||||
break; \
|
||||
case 1: hashv += *_sfh_key; \
|
||||
hashv ^= hashv << 10; \
|
||||
hashv += hashv >> 1; \
|
||||
} \
|
||||
\
|
||||
/* Force "avalanching" of final 127 bits */ \
|
||||
hashv ^= hashv << 3; \
|
||||
hashv += hashv >> 5; \
|
||||
hashv ^= hashv << 4; \
|
||||
hashv += hashv >> 17; \
|
||||
hashv ^= hashv << 25; \
|
||||
hashv += hashv >> 6; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0);
|
||||
|
||||
#ifdef HASH_USING_NO_STRICT_ALIASING
|
||||
/* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads.
|
||||
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
|
||||
* So MurmurHash comes in two versions, the faster unaligned one and the slower
|
||||
* aligned one. We only use the faster one on CPU's where we know it's safe.
|
||||
*
|
||||
* Note the preprocessor built-in defines can be emitted using:
|
||||
*
|
||||
* gcc -m64 -dM -E - < /dev/null (on gcc)
|
||||
* cc -## a.c (where a.c is a simple test file) (Sun Studio)
|
||||
*/
|
||||
#if (defined(__i386__) || defined(__x86_64__))
|
||||
#define HASH_MUR HASH_MUR_UNALIGNED
|
||||
#else
|
||||
#define HASH_MUR HASH_MUR_ALIGNED
|
||||
#endif
|
||||
|
||||
/* Appleby's MurmurHash fast version for unaligned-tolerant archs like i386 */
|
||||
#define HASH_MUR_UNALIGNED(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
const unsigned int _mur_m = 0x5bd1e995; \
|
||||
const int _mur_r = 24; \
|
||||
hashv = 0xcafebabe ^ keylen; \
|
||||
char *_mur_key = (char *)key; \
|
||||
uint32_t _mur_tmp, _mur_len = keylen; \
|
||||
\
|
||||
for (;_mur_len >= 4; _mur_len-=4) { \
|
||||
_mur_tmp = *(uint32_t *)_mur_key; \
|
||||
_mur_tmp *= _mur_m; \
|
||||
_mur_tmp ^= _mur_tmp >> _mur_r; \
|
||||
_mur_tmp *= _mur_m; \
|
||||
hashv *= _mur_m; \
|
||||
hashv ^= _mur_tmp; \
|
||||
_mur_key += 4; \
|
||||
} \
|
||||
\
|
||||
switch(_mur_len) \
|
||||
{ \
|
||||
case 3: hashv ^= _mur_key[2] << 16; \
|
||||
case 2: hashv ^= _mur_key[1] << 8; \
|
||||
case 1: hashv ^= _mur_key[0]; \
|
||||
hashv *= _mur_m; \
|
||||
}; \
|
||||
\
|
||||
hashv ^= hashv >> 13; \
|
||||
hashv *= _mur_m; \
|
||||
hashv ^= hashv >> 15; \
|
||||
\
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
/* Appleby's MurmurHash version for alignment-sensitive archs like Sparc */
|
||||
#define HASH_MUR_ALIGNED(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
const unsigned int _mur_m = 0x5bd1e995; \
|
||||
const int _mur_r = 24; \
|
||||
hashv = 0xcafebabe ^ keylen; \
|
||||
char *_mur_key = (char *)key; \
|
||||
uint32_t _mur_len = keylen; \
|
||||
int _mur_align = (int)_mur_key & 3; \
|
||||
\
|
||||
if (_mur_align && (_mur_len >= 4)) { \
|
||||
unsigned _mur_t = 0, _mur_d = 0; \
|
||||
switch(_mur_align) { \
|
||||
case 1: _mur_t |= _mur_key[2] << 16; \
|
||||
case 2: _mur_t |= _mur_key[1] << 8; \
|
||||
case 3: _mur_t |= _mur_key[0]; \
|
||||
} \
|
||||
_mur_t <<= (8 * _mur_align); \
|
||||
_mur_key += 4-_mur_align; \
|
||||
_mur_len -= 4-_mur_align; \
|
||||
int _mur_sl = 8 * (4-_mur_align); \
|
||||
int _mur_sr = 8 * _mur_align; \
|
||||
\
|
||||
for (;_mur_len >= 4; _mur_len-=4) { \
|
||||
_mur_d = *(unsigned *)_mur_key; \
|
||||
_mur_t = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
|
||||
unsigned _mur_k = _mur_t; \
|
||||
_mur_k *= _mur_m; \
|
||||
_mur_k ^= _mur_k >> _mur_r; \
|
||||
_mur_k *= _mur_m; \
|
||||
hashv *= _mur_m; \
|
||||
hashv ^= _mur_k; \
|
||||
_mur_t = _mur_d; \
|
||||
_mur_key += 4; \
|
||||
} \
|
||||
_mur_d = 0; \
|
||||
if(_mur_len >= _mur_align) { \
|
||||
switch(_mur_align) { \
|
||||
case 3: _mur_d |= _mur_key[2] << 16; \
|
||||
case 2: _mur_d |= _mur_key[1] << 8; \
|
||||
case 1: _mur_d |= _mur_key[0]; \
|
||||
} \
|
||||
unsigned _mur_k = (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
|
||||
_mur_k *= _mur_m; \
|
||||
_mur_k ^= _mur_k >> _mur_r; \
|
||||
_mur_k *= _mur_m; \
|
||||
hashv *= _mur_m; \
|
||||
hashv ^= _mur_k; \
|
||||
_mur_k += _mur_align; \
|
||||
_mur_len -= _mur_align; \
|
||||
\
|
||||
switch(_mur_len) \
|
||||
{ \
|
||||
case 3: hashv ^= _mur_key[2] << 16; \
|
||||
case 2: hashv ^= _mur_key[1] << 8; \
|
||||
case 1: hashv ^= _mur_key[0]; \
|
||||
hashv *= _mur_m; \
|
||||
} \
|
||||
} else { \
|
||||
switch(_mur_len) \
|
||||
{ \
|
||||
case 3: _mur_d ^= _mur_key[2] << 16; \
|
||||
case 2: _mur_d ^= _mur_key[1] << 8; \
|
||||
case 1: _mur_d ^= _mur_key[0]; \
|
||||
case 0: hashv ^= (_mur_t >> _mur_sr) | (_mur_d << _mur_sl); \
|
||||
hashv *= _mur_m; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
hashv ^= hashv >> 13; \
|
||||
hashv *= _mur_m; \
|
||||
hashv ^= hashv >> 15; \
|
||||
} else { \
|
||||
for (;_mur_len >= 4; _mur_len-=4) { \
|
||||
unsigned _mur_k = *(unsigned*)_mur_key; \
|
||||
_mur_k *= _mur_m; \
|
||||
_mur_k ^= _mur_k >> _mur_r; \
|
||||
_mur_k *= _mur_m; \
|
||||
hashv *= _mur_m; \
|
||||
hashv ^= _mur_k; \
|
||||
_mur_key += 4; \
|
||||
} \
|
||||
switch(_mur_len) \
|
||||
{ \
|
||||
case 3: hashv ^= _mur_key[2] << 16; \
|
||||
case 2: hashv ^= _mur_key[1] << 8; \
|
||||
case 1: hashv ^= _mur_key[0]; \
|
||||
hashv *= _mur_m; \
|
||||
} \
|
||||
\
|
||||
hashv ^= hashv >> 13; \
|
||||
hashv *= _mur_m; \
|
||||
hashv ^= hashv >> 15; \
|
||||
} \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
#endif /* HASH_USING_NO_STRICT_ALIASING */
|
||||
|
||||
/* key comparison function; return 0 if keys equal */
|
||||
#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
|
||||
|
||||
/* iterate over items in a known bucket to find desired item */
|
||||
#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
|
||||
do { \
|
||||
if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
|
||||
else out=NULL; \
|
||||
while (out) { \
|
||||
if (out->hh.keylen == keylen_in) { \
|
||||
if ((HASH_KEYCMP(out->hh.key,keyptr,keylen_in)) == 0) break; \
|
||||
} \
|
||||
if (out->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,out->hh.hh_next)); \
|
||||
else out = NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* add an item to a bucket */
|
||||
#define HASH_ADD_TO_BKT(head,addhh) \
|
||||
do { \
|
||||
head.count++; \
|
||||
(addhh)->hh_next = head.hh_head; \
|
||||
(addhh)->hh_prev = NULL; \
|
||||
if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
|
||||
(head).hh_head=addhh; \
|
||||
if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
|
||||
&& (addhh)->tbl->noexpand != 1) { \
|
||||
HASH_EXPAND_BUCKETS((addhh)->tbl); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* remove an item from a given bucket */
|
||||
#define HASH_DEL_IN_BKT(hh,head,hh_del) \
|
||||
(head).count--; \
|
||||
if ((head).hh_head == hh_del) { \
|
||||
(head).hh_head = hh_del->hh_next; \
|
||||
} \
|
||||
if (hh_del->hh_prev) { \
|
||||
hh_del->hh_prev->hh_next = hh_del->hh_next; \
|
||||
} \
|
||||
if (hh_del->hh_next) { \
|
||||
hh_del->hh_next->hh_prev = hh_del->hh_prev; \
|
||||
}
|
||||
|
||||
/* Bucket expansion has the effect of doubling the number of buckets
|
||||
* and redistributing the items into the new buckets. Ideally the
|
||||
* items will distribute more or less evenly into the new buckets
|
||||
* (the extent to which this is true is a measure of the quality of
|
||||
* the hash function as it applies to the key domain).
|
||||
*
|
||||
* With the items distributed into more buckets, the chain length
|
||||
* (item count) in each bucket is reduced. Thus by expanding buckets
|
||||
* the hash keeps a bound on the chain length. This bounded chain
|
||||
* length is the essence of how a hash provides constant time lookup.
|
||||
*
|
||||
* The calculation of tbl->ideal_chain_maxlen below deserves some
|
||||
* explanation. First, keep in mind that we're calculating the ideal
|
||||
* maximum chain length based on the *new* (doubled) bucket count.
|
||||
* In fractions this is just n/b (n=number of items,b=new num buckets).
|
||||
* Since the ideal chain length is an integer, we want to calculate
|
||||
* ceil(n/b). We don't depend on floating point arithmetic in this
|
||||
* hash, so to calculate ceil(n/b) with integers we could write
|
||||
*
|
||||
* ceil(n/b) = (n/b) + ((n%b)?1:0)
|
||||
*
|
||||
* and in fact a previous version of this hash did just that.
|
||||
* But now we have improved things a bit by recognizing that b is
|
||||
* always a power of two. We keep its base 2 log handy (call it lb),
|
||||
* so now we can write this with a bit shift and logical AND:
|
||||
*
|
||||
* ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
|
||||
*
|
||||
*/
|
||||
#define HASH_EXPAND_BUCKETS(tbl) \
|
||||
do { \
|
||||
unsigned _he_bkt; \
|
||||
unsigned _he_bkt_i; \
|
||||
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
|
||||
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
|
||||
_he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
|
||||
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
|
||||
if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
|
||||
memset(_he_new_buckets, 0, \
|
||||
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
|
||||
tbl->ideal_chain_maxlen = \
|
||||
(tbl->num_items >> (tbl->log2_num_buckets+1)) + \
|
||||
((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
|
||||
tbl->nonideal_items = 0; \
|
||||
for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
|
||||
{ \
|
||||
_he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
|
||||
while (_he_thh) { \
|
||||
_he_hh_nxt = _he_thh->hh_next; \
|
||||
HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
|
||||
_he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
|
||||
if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
|
||||
tbl->nonideal_items++; \
|
||||
_he_newbkt->expand_mult = _he_newbkt->count / \
|
||||
tbl->ideal_chain_maxlen; \
|
||||
} \
|
||||
_he_thh->hh_prev = NULL; \
|
||||
_he_thh->hh_next = _he_newbkt->hh_head; \
|
||||
if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
|
||||
_he_thh; \
|
||||
_he_newbkt->hh_head = _he_thh; \
|
||||
_he_thh = _he_hh_nxt; \
|
||||
} \
|
||||
} \
|
||||
tbl->num_buckets *= 2; \
|
||||
tbl->log2_num_buckets++; \
|
||||
uthash_free( tbl->buckets ); \
|
||||
tbl->buckets = _he_new_buckets; \
|
||||
tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
|
||||
(tbl->ineff_expands+1) : 0; \
|
||||
if (tbl->ineff_expands > 1) { \
|
||||
tbl->noexpand=1; \
|
||||
uthash_noexpand_fyi(tbl); \
|
||||
} \
|
||||
uthash_expand_fyi(tbl); \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
|
||||
/* Note that HASH_SORT assumes the hash handle name to be hh.
|
||||
* HASH_SRT was added to allow the hash handle name to be passed in. */
|
||||
#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
|
||||
#define HASH_SRT(hh,head,cmpfcn) \
|
||||
do { \
|
||||
unsigned _hs_i; \
|
||||
unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
|
||||
struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
|
||||
if (head) { \
|
||||
_hs_insize = 1; \
|
||||
_hs_looping = 1; \
|
||||
_hs_list = &((head)->hh); \
|
||||
while (_hs_looping) { \
|
||||
_hs_p = _hs_list; \
|
||||
_hs_list = NULL; \
|
||||
_hs_tail = NULL; \
|
||||
_hs_nmerges = 0; \
|
||||
while (_hs_p) { \
|
||||
_hs_nmerges++; \
|
||||
_hs_q = _hs_p; \
|
||||
_hs_psize = 0; \
|
||||
for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
|
||||
_hs_psize++; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
if (! (_hs_q) ) break; \
|
||||
} \
|
||||
_hs_qsize = _hs_insize; \
|
||||
while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
|
||||
if (_hs_psize == 0) { \
|
||||
_hs_e = _hs_q; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_qsize--; \
|
||||
} else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
|
||||
_hs_e = _hs_p; \
|
||||
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
|
||||
((void*)((char*)(_hs_p->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_psize--; \
|
||||
} else if (( \
|
||||
cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
|
||||
DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
|
||||
) <= 0) { \
|
||||
_hs_e = _hs_p; \
|
||||
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
|
||||
((void*)((char*)(_hs_p->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_psize--; \
|
||||
} else { \
|
||||
_hs_e = _hs_q; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_qsize--; \
|
||||
} \
|
||||
if ( _hs_tail ) { \
|
||||
_hs_tail->next = ((_hs_e) ? \
|
||||
ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
|
||||
} else { \
|
||||
_hs_list = _hs_e; \
|
||||
} \
|
||||
_hs_e->prev = ((_hs_tail) ? \
|
||||
ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
|
||||
_hs_tail = _hs_e; \
|
||||
} \
|
||||
_hs_p = _hs_q; \
|
||||
} \
|
||||
_hs_tail->next = NULL; \
|
||||
if ( _hs_nmerges <= 1 ) { \
|
||||
_hs_looping=0; \
|
||||
(head)->hh.tbl->tail = _hs_tail; \
|
||||
DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
|
||||
} \
|
||||
_hs_insize *= 2; \
|
||||
} \
|
||||
HASH_FSCK(hh,head); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* This function selects items from one hash into another hash.
|
||||
* The end result is that the selected items have dual presence
|
||||
* in both hashes. There is no copy of the items made; rather
|
||||
* they are added into the new hash through a secondary hash
|
||||
* hash handle that must be present in the structure. */
|
||||
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
|
||||
do { \
|
||||
unsigned _src_bkt, _dst_bkt; \
|
||||
void *_last_elt=NULL, *_elt; \
|
||||
UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
|
||||
ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
|
||||
if (src) { \
|
||||
for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
|
||||
for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
|
||||
_src_hh; \
|
||||
_src_hh = _src_hh->hh_next) { \
|
||||
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
|
||||
if (cond(_elt)) { \
|
||||
_dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
|
||||
_dst_hh->key = _src_hh->key; \
|
||||
_dst_hh->keylen = _src_hh->keylen; \
|
||||
_dst_hh->hashv = _src_hh->hashv; \
|
||||
_dst_hh->prev = _last_elt; \
|
||||
_dst_hh->next = NULL; \
|
||||
if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
|
||||
if (!dst) { \
|
||||
DECLTYPE_ASSIGN(dst,_elt); \
|
||||
HASH_MAKE_TABLE(hh_dst,dst); \
|
||||
} else { \
|
||||
_dst_hh->tbl = (dst)->hh_dst.tbl; \
|
||||
} \
|
||||
HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
|
||||
HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
|
||||
(dst)->hh_dst.tbl->num_items++; \
|
||||
_last_elt = _elt; \
|
||||
_last_elt_hh = _dst_hh; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
HASH_FSCK(hh_dst,dst); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_CLEAR(hh,head) \
|
||||
do { \
|
||||
if (head) { \
|
||||
uthash_free((head)->hh.tbl->buckets ); \
|
||||
uthash_free((head)->hh.tbl); \
|
||||
(head)=NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* obtain a count of items in the hash */
|
||||
#define HASH_COUNT(head) HASH_CNT(hh,head)
|
||||
#define HASH_CNT(hh,head) (head?(head->hh.tbl->num_items):0)
|
||||
|
||||
typedef struct UT_hash_bucket {
|
||||
struct UT_hash_handle *hh_head;
|
||||
unsigned count;
|
||||
|
||||
/* expand_mult is normally set to 0. In this situation, the max chain length
|
||||
* threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
|
||||
* the bucket's chain exceeds this length, bucket expansion is triggered).
|
||||
* However, setting expand_mult to a non-zero value delays bucket expansion
|
||||
* (that would be triggered by additions to this particular bucket)
|
||||
* until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
|
||||
* (The multiplier is simply expand_mult+1). The whole idea of this
|
||||
* multiplier is to reduce bucket expansions, since they are expensive, in
|
||||
* situations where we know that a particular bucket tends to be overused.
|
||||
* It is better to let its chain length grow to a longer yet-still-bounded
|
||||
* value, than to do an O(n) bucket expansion too often.
|
||||
*/
|
||||
unsigned expand_mult;
|
||||
|
||||
} UT_hash_bucket;
|
||||
|
||||
/* random signature used only to find hash tables in external analysis */
|
||||
#define HASH_SIGNATURE 0xa0111fe1
|
||||
#define HASH_BLOOM_SIGNATURE 0xb12220f2
|
||||
|
||||
typedef struct UT_hash_table {
|
||||
UT_hash_bucket *buckets;
|
||||
unsigned num_buckets, log2_num_buckets;
|
||||
unsigned num_items;
|
||||
struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
|
||||
ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
|
||||
|
||||
/* in an ideal situation (all buckets used equally), no bucket would have
|
||||
* more than ceil(#items/#buckets) items. that's the ideal chain length. */
|
||||
unsigned ideal_chain_maxlen;
|
||||
|
||||
/* nonideal_items is the number of items in the hash whose chain position
|
||||
* exceeds the ideal chain maxlen. these items pay the penalty for an uneven
|
||||
* hash distribution; reaching them in a chain traversal takes >ideal steps */
|
||||
unsigned nonideal_items;
|
||||
|
||||
/* ineffective expands occur when a bucket doubling was performed, but
|
||||
* afterward, more than half the items in the hash had nonideal chain
|
||||
* positions. If this happens on two consecutive expansions we inhibit any
|
||||
* further expansion, as it's not helping; this happens when the hash
|
||||
* function isn't a good fit for the key domain. When expansion is inhibited
|
||||
* the hash will still work, albeit no longer in constant time. */
|
||||
unsigned ineff_expands, noexpand;
|
||||
|
||||
uint32_t signature; /* used only to find hash tables in external analysis */
|
||||
#ifdef HASH_BLOOM
|
||||
uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
|
||||
uint8_t *bloom_bv;
|
||||
char bloom_nbits;
|
||||
#endif
|
||||
|
||||
} UT_hash_table;
|
||||
|
||||
typedef struct UT_hash_handle {
|
||||
struct UT_hash_table *tbl;
|
||||
void *prev; /* prev element in app order */
|
||||
void *next; /* next element in app order */
|
||||
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
|
||||
struct UT_hash_handle *hh_next; /* next hh in bucket order */
|
||||
void *key; /* ptr to enclosing struct's key */
|
||||
unsigned keylen; /* enclosing struct's key len */
|
||||
unsigned hashv; /* result of hash-fcn(key) */
|
||||
} UT_hash_handle;
|
||||
|
||||
#endif /* UTHASH_H */
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
// [API version]
|
||||
@par API Version
|
||||
v4.0
|
||||
// [API version]
|
||||
// [Code version]
|
||||
exitcode-128-NOTFOUND
|
||||
// [Code version]
|
||||
*/
|
||||
#define LIBKTX_VERSION exitcode-128-NOTFOUND
|
||||
#define LIBKTX_DEFAULT_VERSION v4.0.__default__
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2024 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Get GL format information matching a VkFormat
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VK2GL_H_
|
||||
#define _VK2GL_H_
|
||||
|
||||
#include "vkformat_enum.h"
|
||||
#include "GL/glcorearb.h"
|
||||
|
||||
// These are only in glext.h.
|
||||
#if !defined( GL_COMPRESSED_SRGB_S3TC_DXT1_EXT )
|
||||
#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C
|
||||
#endif
|
||||
#if !defined( GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT )
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
|
||||
#endif
|
||||
#if !defined( GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT )
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
|
||||
#endif
|
||||
#if !defined( GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT )
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
|
||||
#endif
|
||||
|
||||
// These are only in GLES headers not in glcorearb.h or glext.h.
|
||||
|
||||
//
|
||||
// ETC
|
||||
//
|
||||
|
||||
#if !defined( GL_ETC1_RGB8_OES )
|
||||
#define GL_ETC1_RGB8_OES 0x8D64
|
||||
#endif
|
||||
|
||||
//
|
||||
// PVRTC
|
||||
//
|
||||
|
||||
#if !defined( GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG )
|
||||
#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
|
||||
#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
|
||||
#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
|
||||
#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
|
||||
#endif
|
||||
#if !defined( GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG )
|
||||
#define GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137
|
||||
#define GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138
|
||||
#endif
|
||||
#if !defined( GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT )
|
||||
#define GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54
|
||||
#define GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57
|
||||
#endif
|
||||
#if !defined( GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG )
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG 0x93F0
|
||||
#define GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG 0x93F1
|
||||
#endif
|
||||
|
||||
//
|
||||
// ASTC
|
||||
//
|
||||
|
||||
#if !defined( GL_COMPRESSED_RGBA_ASTC_3x3x3_OES )
|
||||
#define GL_COMPRESSED_RGBA_ASTC_3x3x3_OES 0x93C0
|
||||
#define GL_COMPRESSED_RGBA_ASTC_4x3x3_OES 0x93C1
|
||||
#define GL_COMPRESSED_RGBA_ASTC_4x4x3_OES 0x93C2
|
||||
#define GL_COMPRESSED_RGBA_ASTC_4x4x4_OES 0x93C3
|
||||
#define GL_COMPRESSED_RGBA_ASTC_5x4x4_OES 0x93C4
|
||||
#define GL_COMPRESSED_RGBA_ASTC_5x5x4_OES 0x93C5
|
||||
#define GL_COMPRESSED_RGBA_ASTC_5x5x5_OES 0x93C6
|
||||
#define GL_COMPRESSED_RGBA_ASTC_6x5x5_OES 0x93C7
|
||||
#define GL_COMPRESSED_RGBA_ASTC_6x6x5_OES 0x93C8
|
||||
#define GL_COMPRESSED_RGBA_ASTC_6x6x6_OES 0x93C9
|
||||
#endif
|
||||
|
||||
#if !defined( GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES )
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES 0x93E0
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES 0x93E1
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES 0x93E2
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES 0x93E3
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES 0x93E4
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES 0x93E5
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES 0x93E6
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES 0x93E7
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES 0x93E8
|
||||
#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES 0x93E9
|
||||
#endif
|
||||
|
||||
static inline GLenum vkFormat2glInternalFormat( VkFormat vkFormat )
|
||||
{
|
||||
switch ( vkFormat )
|
||||
{
|
||||
#include "vkFormat2glInternalFormat.inl"
|
||||
default: return GL_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline GLenum vkFormat2glFormat( VkFormat vkFormat )
|
||||
{
|
||||
switch ( vkFormat )
|
||||
{
|
||||
#include "vkFormat2glFormat.inl"
|
||||
default: return GL_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline GLenum vkFormat2glType( VkFormat vkFormat )
|
||||
{
|
||||
switch ( vkFormat )
|
||||
{
|
||||
#include "vkFormat2glType.inl"
|
||||
default: return GL_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _VK2GL_H_ */
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2020 The Khronos Group Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*************************************** Do not edit ***************************************
|
||||
Automatically generated by
|
||||
https://github.com/KhronosGroup/KTX-Specification/blob/master/generate_format_switches.rb
|
||||
*******************************************************************************************/
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: return GL_RGBA;
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: return GL_BGRA;
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16: return GL_RGB;
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16: return GL_RGB;
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: return GL_RGBA;
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: return GL_BGRA;
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: return GL_BGRA;
|
||||
case VK_FORMAT_R8_UNORM: return GL_RED;
|
||||
case VK_FORMAT_R8_SNORM: return GL_RED;
|
||||
case VK_FORMAT_R8_UINT: return GL_RED_INTEGER;
|
||||
case VK_FORMAT_R8_SINT: return GL_RED_INTEGER;
|
||||
case VK_FORMAT_R8_SRGB: return GL_RED;
|
||||
case VK_FORMAT_R8G8_UNORM: return GL_RG;
|
||||
case VK_FORMAT_R8G8_SNORM: return GL_RG;
|
||||
case VK_FORMAT_R8G8_UINT: return GL_RG_INTEGER;
|
||||
case VK_FORMAT_R8G8_SINT: return GL_RG_INTEGER;
|
||||
case VK_FORMAT_R8G8_SRGB: return GL_RG;
|
||||
case VK_FORMAT_R8G8B8_UNORM: return GL_RGB;
|
||||
case VK_FORMAT_R8G8B8_SNORM: return GL_RGB;
|
||||
case VK_FORMAT_R8G8B8_UINT: return GL_RGB_INTEGER;
|
||||
case VK_FORMAT_R8G8B8_SINT: return GL_RGB_INTEGER;
|
||||
case VK_FORMAT_R8G8B8_SRGB: return GL_RGB;
|
||||
case VK_FORMAT_B8G8R8_UNORM: return GL_BGR;
|
||||
case VK_FORMAT_B8G8R8_SNORM: return GL_BGR;
|
||||
case VK_FORMAT_B8G8R8_UINT: return GL_BGR_INTEGER;
|
||||
case VK_FORMAT_B8G8R8_SINT: return GL_BGR_INTEGER;
|
||||
case VK_FORMAT_B8G8R8_SRGB: return GL_BGR;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: return GL_RGBA;
|
||||
case VK_FORMAT_R8G8B8A8_SNORM: return GL_RGBA;
|
||||
case VK_FORMAT_R8G8B8A8_UINT: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_R8G8B8A8_SINT: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB: return GL_RGBA;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM: return GL_BGRA;
|
||||
case VK_FORMAT_B8G8R8A8_SNORM: return GL_BGRA;
|
||||
case VK_FORMAT_B8G8R8A8_UINT: return GL_BGRA_INTEGER;
|
||||
case VK_FORMAT_B8G8R8A8_SINT: return GL_BGRA_INTEGER;
|
||||
case VK_FORMAT_B8G8R8A8_SRGB: return GL_BGRA;
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: return GL_RGBA;
|
||||
case VK_FORMAT_A8B8G8R8_SNORM_PACK32: return GL_RGBA;
|
||||
case VK_FORMAT_A8B8G8R8_UINT_PACK32: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_A8B8G8R8_SINT_PACK32: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32: return GL_RGBA;
|
||||
case VK_FORMAT_A2R10G10B10_UNORM_PACK32: return GL_BGRA;
|
||||
case VK_FORMAT_A2R10G10B10_UINT_PACK32: return GL_BGRA_INTEGER;
|
||||
case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return GL_RGBA;
|
||||
case VK_FORMAT_A2B10G10R10_UINT_PACK32: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_R16_UNORM: return GL_RED;
|
||||
case VK_FORMAT_R16_SNORM: return GL_RED;
|
||||
case VK_FORMAT_R16_UINT: return GL_RED_INTEGER;
|
||||
case VK_FORMAT_R16_SINT: return GL_RED_INTEGER;
|
||||
case VK_FORMAT_R16_SFLOAT: return GL_RED;
|
||||
case VK_FORMAT_R16G16_UNORM: return GL_RG;
|
||||
case VK_FORMAT_R16G16_SNORM: return GL_RG;
|
||||
case VK_FORMAT_R16G16_UINT: return GL_RG_INTEGER;
|
||||
case VK_FORMAT_R16G16_SINT: return GL_RG_INTEGER;
|
||||
case VK_FORMAT_R16G16_SFLOAT: return GL_RG;
|
||||
case VK_FORMAT_R16G16B16_UNORM: return GL_RGB;
|
||||
case VK_FORMAT_R16G16B16_SNORM: return GL_RGB;
|
||||
case VK_FORMAT_R16G16B16_UINT: return GL_RGB_INTEGER;
|
||||
case VK_FORMAT_R16G16B16_SINT: return GL_RGB_INTEGER;
|
||||
case VK_FORMAT_R16G16B16_SFLOAT: return GL_RGB;
|
||||
case VK_FORMAT_R16G16B16A16_UNORM: return GL_RGBA;
|
||||
case VK_FORMAT_R16G16B16A16_SNORM: return GL_RGBA;
|
||||
case VK_FORMAT_R16G16B16A16_UINT: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_R16G16B16A16_SINT: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT: return GL_RGBA;
|
||||
case VK_FORMAT_R32_UINT: return GL_RED_INTEGER;
|
||||
case VK_FORMAT_R32_SINT: return GL_RED_INTEGER;
|
||||
case VK_FORMAT_R32_SFLOAT: return GL_RED;
|
||||
case VK_FORMAT_R32G32_UINT: return GL_RG_INTEGER;
|
||||
case VK_FORMAT_R32G32_SINT: return GL_RG_INTEGER;
|
||||
case VK_FORMAT_R32G32_SFLOAT: return GL_RG;
|
||||
case VK_FORMAT_R32G32B32_UINT: return GL_RGB_INTEGER;
|
||||
case VK_FORMAT_R32G32B32_SINT: return GL_RGB_INTEGER;
|
||||
case VK_FORMAT_R32G32B32_SFLOAT: return GL_RGB;
|
||||
case VK_FORMAT_R32G32B32A32_UINT: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_R32G32B32A32_SINT: return GL_RGBA_INTEGER;
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT: return GL_RGBA;
|
||||
case VK_FORMAT_B10G11R11_UFLOAT_PACK32: return GL_RGB;
|
||||
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: return GL_RGB;
|
||||
case VK_FORMAT_D16_UNORM: return GL_DEPTH_COMPONENT;
|
||||
case VK_FORMAT_D32_SFLOAT: return GL_DEPTH_COMPONENT;
|
||||
case VK_FORMAT_S8_UINT: return GL_STENCIL_INDEX;
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT: return GL_DEPTH_STENCIL;
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT: return GL_DEPTH_STENCIL;
|
||||
case VK_FORMAT_A4R4G4B4_UNORM_PACK16: return GL_BGRA;
|
||||
case VK_FORMAT_A4B4G4R4_UNORM_PACK16: return GL_RGBA;
|
||||
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: return GL_RGBA;
|
||||
case VK_FORMAT_A8_UNORM_KHR: return GL_ALPHA;
|
||||
@@ -0,0 +1,202 @@
|
||||
// Copyright 2020 The Khronos Group Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*************************************** Do not edit ***************************************
|
||||
Automatically generated by
|
||||
https://github.com/KhronosGroup/KTX-Specification/blob/master/generate_format_switches.rb
|
||||
*******************************************************************************************/
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: return GL_RGBA4;
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: return GL_RGBA4;
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16: return GL_RGB565;
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16: return GL_RGB565;
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: return GL_RGB5_A1;
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: return GL_RGB5_A1;
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: return GL_RGB5_A1;
|
||||
case VK_FORMAT_R8_UNORM: return GL_R8;
|
||||
case VK_FORMAT_R8_SNORM: return GL_R8_SNORM;
|
||||
case VK_FORMAT_R8_UINT: return GL_R8UI;
|
||||
case VK_FORMAT_R8_SINT: return GL_R8I;
|
||||
case VK_FORMAT_R8_SRGB: return GL_SR8_EXT;
|
||||
case VK_FORMAT_R8G8_UNORM: return GL_RG8;
|
||||
case VK_FORMAT_R8G8_SNORM: return GL_RG8_SNORM;
|
||||
case VK_FORMAT_R8G8_UINT: return GL_RG8UI;
|
||||
case VK_FORMAT_R8G8_SINT: return GL_RG8I;
|
||||
case VK_FORMAT_R8G8_SRGB: return GL_SRG8_EXT;
|
||||
case VK_FORMAT_R8G8B8_UNORM: return GL_RGB8;
|
||||
case VK_FORMAT_R8G8B8_SNORM: return GL_RGB8_SNORM;
|
||||
case VK_FORMAT_R8G8B8_UINT: return GL_RGB8UI;
|
||||
case VK_FORMAT_R8G8B8_SINT: return GL_RGB8I;
|
||||
case VK_FORMAT_R8G8B8_SRGB: return GL_SRGB8;
|
||||
case VK_FORMAT_B8G8R8_UNORM: return GL_RGB8;
|
||||
case VK_FORMAT_B8G8R8_SNORM: return GL_RGB8_SNORM;
|
||||
case VK_FORMAT_B8G8R8_UINT: return GL_RGB8UI;
|
||||
case VK_FORMAT_B8G8R8_SINT: return GL_RGB8I;
|
||||
case VK_FORMAT_B8G8R8_SRGB: return GL_SRGB8;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: return GL_RGBA8;
|
||||
case VK_FORMAT_R8G8B8A8_SNORM: return GL_RGBA8_SNORM;
|
||||
case VK_FORMAT_R8G8B8A8_UINT: return GL_RGBA8UI;
|
||||
case VK_FORMAT_R8G8B8A8_SINT: return GL_RGBA8I;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB: return GL_SRGB8_ALPHA8;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM: return GL_RGBA8;
|
||||
case VK_FORMAT_B8G8R8A8_SNORM: return GL_RGBA8_SNORM;
|
||||
case VK_FORMAT_B8G8R8A8_UINT: return GL_RGBA8UI;
|
||||
case VK_FORMAT_B8G8R8A8_SINT: return GL_RGBA8I;
|
||||
case VK_FORMAT_B8G8R8A8_SRGB: return GL_SRGB8_ALPHA8;
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: return GL_RGBA8;
|
||||
case VK_FORMAT_A8B8G8R8_SNORM_PACK32: return GL_RGBA8_SNORM;
|
||||
case VK_FORMAT_A8B8G8R8_UINT_PACK32: return GL_RGBA8UI;
|
||||
case VK_FORMAT_A8B8G8R8_SINT_PACK32: return GL_RGBA8I;
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32: return GL_SRGB8_ALPHA8;
|
||||
case VK_FORMAT_A2R10G10B10_UNORM_PACK32: return GL_RGB10_A2;
|
||||
case VK_FORMAT_A2R10G10B10_UINT_PACK32: return GL_RGB10_A2UI;
|
||||
case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return GL_RGB10_A2;
|
||||
case VK_FORMAT_A2B10G10R10_UINT_PACK32: return GL_RGB10_A2UI;
|
||||
case VK_FORMAT_R16_UNORM: return GL_R16;
|
||||
case VK_FORMAT_R16_SNORM: return GL_R16_SNORM;
|
||||
case VK_FORMAT_R16_UINT: return GL_R16UI;
|
||||
case VK_FORMAT_R16_SINT: return GL_R16I;
|
||||
case VK_FORMAT_R16_SFLOAT: return GL_R16F;
|
||||
case VK_FORMAT_R16G16_UNORM: return GL_RG16;
|
||||
case VK_FORMAT_R16G16_SNORM: return GL_RG16_SNORM;
|
||||
case VK_FORMAT_R16G16_UINT: return GL_RG16UI;
|
||||
case VK_FORMAT_R16G16_SINT: return GL_RG16I;
|
||||
case VK_FORMAT_R16G16_SFLOAT: return GL_RG16F;
|
||||
case VK_FORMAT_R16G16B16_UNORM: return GL_RGB16;
|
||||
case VK_FORMAT_R16G16B16_SNORM: return GL_RGB16_SNORM;
|
||||
case VK_FORMAT_R16G16B16_UINT: return GL_RGB16UI;
|
||||
case VK_FORMAT_R16G16B16_SINT: return GL_RGB16I;
|
||||
case VK_FORMAT_R16G16B16_SFLOAT: return GL_RGB16F;
|
||||
case VK_FORMAT_R16G16B16A16_UNORM: return GL_RGBA16;
|
||||
case VK_FORMAT_R16G16B16A16_SNORM: return GL_RGBA16_SNORM;
|
||||
case VK_FORMAT_R16G16B16A16_UINT: return GL_RGBA16UI;
|
||||
case VK_FORMAT_R16G16B16A16_SINT: return GL_RGBA16I;
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT: return GL_RGBA16F;
|
||||
case VK_FORMAT_R32_UINT: return GL_R32UI;
|
||||
case VK_FORMAT_R32_SINT: return GL_R32I;
|
||||
case VK_FORMAT_R32_SFLOAT: return GL_R32F;
|
||||
case VK_FORMAT_R32G32_UINT: return GL_RG32UI;
|
||||
case VK_FORMAT_R32G32_SINT: return GL_RG32I;
|
||||
case VK_FORMAT_R32G32_SFLOAT: return GL_RG32F;
|
||||
case VK_FORMAT_R32G32B32_UINT: return GL_RGB32UI;
|
||||
case VK_FORMAT_R32G32B32_SINT: return GL_RGB32I;
|
||||
case VK_FORMAT_R32G32B32_SFLOAT: return GL_RGB32F;
|
||||
case VK_FORMAT_R32G32B32A32_UINT: return GL_RGBA32UI;
|
||||
case VK_FORMAT_R32G32B32A32_SINT: return GL_RGBA32I;
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT: return GL_RGBA32F;
|
||||
case VK_FORMAT_B10G11R11_UFLOAT_PACK32: return GL_R11F_G11F_B10F;
|
||||
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: return GL_RGB9_E5;
|
||||
case VK_FORMAT_D16_UNORM: return GL_DEPTH_COMPONENT16;
|
||||
case VK_FORMAT_D32_SFLOAT: return GL_DEPTH_COMPONENT32F;
|
||||
case VK_FORMAT_S8_UINT: return GL_STENCIL_INDEX8;
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT: return GL_DEPTH24_STENCIL8;
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT: return GL_DEPTH32F_STENCIL8;
|
||||
case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
case VK_FORMAT_BC1_RGB_SRGB_BLOCK: return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
|
||||
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
|
||||
case VK_FORMAT_BC2_UNORM_BLOCK: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
case VK_FORMAT_BC2_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
|
||||
case VK_FORMAT_BC3_UNORM_BLOCK: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
case VK_FORMAT_BC3_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
|
||||
case VK_FORMAT_BC4_UNORM_BLOCK: return GL_COMPRESSED_RED_RGTC1;
|
||||
case VK_FORMAT_BC4_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_RED_RGTC1;
|
||||
case VK_FORMAT_BC5_UNORM_BLOCK: return GL_COMPRESSED_RG_RGTC2;
|
||||
case VK_FORMAT_BC5_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_RG_RGTC2;
|
||||
case VK_FORMAT_BC6H_UFLOAT_BLOCK: return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||
case VK_FORMAT_BC6H_SFLOAT_BLOCK: return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
|
||||
case VK_FORMAT_BC7_UNORM_BLOCK: return GL_COMPRESSED_RGBA_BPTC_UNORM;
|
||||
case VK_FORMAT_BC7_SRGB_BLOCK: return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
|
||||
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: return GL_COMPRESSED_RGB8_ETC2;
|
||||
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ETC2;
|
||||
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
|
||||
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
|
||||
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: return GL_COMPRESSED_RGBA8_ETC2_EAC;
|
||||
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
|
||||
case VK_FORMAT_EAC_R11_UNORM_BLOCK: return GL_COMPRESSED_R11_EAC;
|
||||
case VK_FORMAT_EAC_R11_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_R11_EAC;
|
||||
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: return GL_COMPRESSED_RG11_EAC;
|
||||
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: return GL_COMPRESSED_SIGNED_RG11_EAC;
|
||||
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
|
||||
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;
|
||||
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
|
||||
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
|
||||
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR;
|
||||
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
|
||||
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_5x5_KHR;
|
||||
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR;
|
||||
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_5x5_KHR;
|
||||
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_6x5_KHR;
|
||||
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR;
|
||||
case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_6x5_KHR;
|
||||
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_6x6_KHR;
|
||||
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR;
|
||||
case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_6x6_KHR;
|
||||
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x5_KHR;
|
||||
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR;
|
||||
case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x5_KHR;
|
||||
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x6_KHR;
|
||||
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR;
|
||||
case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x6_KHR;
|
||||
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x8_KHR;
|
||||
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR;
|
||||
case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_8x8_KHR;
|
||||
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x5_KHR;
|
||||
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR;
|
||||
case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x5_KHR;
|
||||
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x6_KHR;
|
||||
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR;
|
||||
case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x6_KHR;
|
||||
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x8_KHR;
|
||||
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR;
|
||||
case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x8_KHR;
|
||||
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x10_KHR;
|
||||
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR;
|
||||
case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_10x10_KHR;
|
||||
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_12x10_KHR;
|
||||
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR;
|
||||
case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_12x10_KHR;
|
||||
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: return GL_COMPRESSED_RGBA_ASTC_12x12_KHR;
|
||||
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR;
|
||||
case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK: return GL_COMPRESSED_RGBA_ASTC_12x12_KHR;
|
||||
case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_3x3x3_OES;
|
||||
case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES;
|
||||
case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_3x3x3_OES;
|
||||
case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_4x3x3_OES;
|
||||
case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES;
|
||||
case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_4x3x3_OES;
|
||||
case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_4x4x3_OES;
|
||||
case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES;
|
||||
case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_4x4x3_OES;
|
||||
case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_4x4x4_OES;
|
||||
case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES;
|
||||
case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_4x4x4_OES;
|
||||
case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_5x4x4_OES;
|
||||
case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES;
|
||||
case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_5x4x4_OES;
|
||||
case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_5x5x4_OES;
|
||||
case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES;
|
||||
case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_5x5x4_OES;
|
||||
case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_5x5x5_OES;
|
||||
case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES;
|
||||
case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_5x5x5_OES;
|
||||
case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_6x5x5_OES;
|
||||
case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES;
|
||||
case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_6x5x5_OES;
|
||||
case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_6x6x5_OES;
|
||||
case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES;
|
||||
case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_6x6x5_OES;
|
||||
case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_6x6x6_OES;
|
||||
case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES;
|
||||
case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT: return GL_COMPRESSED_RGBA_ASTC_6x6x6_OES;
|
||||
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
|
||||
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
|
||||
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG;
|
||||
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: return GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG;
|
||||
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT;
|
||||
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT;
|
||||
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG;
|
||||
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG;
|
||||
case VK_FORMAT_A4R4G4B4_UNORM_PACK16: return GL_RGBA4;
|
||||
case VK_FORMAT_A4B4G4R4_UNORM_PACK16: return GL_RGBA4;
|
||||
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: return GL_RGB5_A1;
|
||||
case VK_FORMAT_A8_UNORM_KHR: return GL_ALPHA8_EXT;
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2020 The Khronos Group Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/*************************************** Do not edit ***************************************
|
||||
Automatically generated by
|
||||
https://github.com/KhronosGroup/KTX-Specification/blob/master/generate_format_switches.rb
|
||||
*******************************************************************************************/
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: return GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: return GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16: return GL_UNSIGNED_SHORT_5_6_5;
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16: return GL_UNSIGNED_SHORT_5_6_5_REV;
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: return GL_UNSIGNED_SHORT_5_5_5_1;
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: return GL_UNSIGNED_SHORT_5_5_5_1;
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: return GL_UNSIGNED_SHORT_1_5_5_5_REV;
|
||||
case VK_FORMAT_R8_UNORM: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8_SNORM: return GL_BYTE;
|
||||
case VK_FORMAT_R8_UINT: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8_SINT: return GL_BYTE;
|
||||
case VK_FORMAT_R8_SRGB: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8_UNORM: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8_SNORM: return GL_BYTE;
|
||||
case VK_FORMAT_R8G8_UINT: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8_SINT: return GL_BYTE;
|
||||
case VK_FORMAT_R8G8_SRGB: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8B8_UNORM: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8B8_SNORM: return GL_BYTE;
|
||||
case VK_FORMAT_R8G8B8_UINT: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8B8_SINT: return GL_BYTE;
|
||||
case VK_FORMAT_R8G8B8_SRGB: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_B8G8R8_UNORM: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_B8G8R8_SNORM: return GL_BYTE;
|
||||
case VK_FORMAT_B8G8R8_UINT: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_B8G8R8_SINT: return GL_BYTE;
|
||||
case VK_FORMAT_B8G8R8_SRGB: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8B8A8_SNORM: return GL_BYTE;
|
||||
case VK_FORMAT_R8G8B8A8_UINT: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_R8G8B8A8_SINT: return GL_BYTE;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_B8G8R8A8_SNORM: return GL_BYTE;
|
||||
case VK_FORMAT_B8G8R8A8_UINT: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_B8G8R8A8_SINT: return GL_BYTE;
|
||||
case VK_FORMAT_B8G8R8A8_SRGB: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_A8B8G8R8_SNORM_PACK32: return GL_BYTE;
|
||||
case VK_FORMAT_A8B8G8R8_UINT_PACK32: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_A8B8G8R8_SINT_PACK32: return GL_BYTE;
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_A2R10G10B10_UNORM_PACK32: return GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
case VK_FORMAT_A2R10G10B10_UINT_PACK32: return GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
case VK_FORMAT_A2B10G10R10_UINT_PACK32: return GL_UNSIGNED_INT_2_10_10_10_REV;
|
||||
case VK_FORMAT_R16_UNORM: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16_SNORM: return GL_SHORT;
|
||||
case VK_FORMAT_R16_UINT: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16_SINT: return GL_SHORT;
|
||||
case VK_FORMAT_R16_SFLOAT: return GL_HALF_FLOAT;
|
||||
case VK_FORMAT_R16G16_UNORM: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16G16_SNORM: return GL_SHORT;
|
||||
case VK_FORMAT_R16G16_UINT: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16G16_SINT: return GL_SHORT;
|
||||
case VK_FORMAT_R16G16_SFLOAT: return GL_HALF_FLOAT;
|
||||
case VK_FORMAT_R16G16B16_UNORM: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16G16B16_SNORM: return GL_SHORT;
|
||||
case VK_FORMAT_R16G16B16_UINT: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16G16B16_SINT: return GL_SHORT;
|
||||
case VK_FORMAT_R16G16B16_SFLOAT: return GL_HALF_FLOAT;
|
||||
case VK_FORMAT_R16G16B16A16_UNORM: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16G16B16A16_SNORM: return GL_SHORT;
|
||||
case VK_FORMAT_R16G16B16A16_UINT: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_R16G16B16A16_SINT: return GL_SHORT;
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT: return GL_HALF_FLOAT;
|
||||
case VK_FORMAT_R32_UINT: return GL_UNSIGNED_INT;
|
||||
case VK_FORMAT_R32_SINT: return GL_INT;
|
||||
case VK_FORMAT_R32_SFLOAT: return GL_FLOAT;
|
||||
case VK_FORMAT_R32G32_UINT: return GL_UNSIGNED_INT;
|
||||
case VK_FORMAT_R32G32_SINT: return GL_INT;
|
||||
case VK_FORMAT_R32G32_SFLOAT: return GL_FLOAT;
|
||||
case VK_FORMAT_R32G32B32_UINT: return GL_UNSIGNED_INT;
|
||||
case VK_FORMAT_R32G32B32_SINT: return GL_INT;
|
||||
case VK_FORMAT_R32G32B32_SFLOAT: return GL_FLOAT;
|
||||
case VK_FORMAT_R32G32B32A32_UINT: return GL_UNSIGNED_INT;
|
||||
case VK_FORMAT_R32G32B32A32_SINT: return GL_INT;
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT: return GL_FLOAT;
|
||||
case VK_FORMAT_B10G11R11_UFLOAT_PACK32: return GL_UNSIGNED_INT_10F_11F_11F_REV;
|
||||
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: return GL_UNSIGNED_INT_5_9_9_9_REV;
|
||||
case VK_FORMAT_D16_UNORM: return GL_UNSIGNED_SHORT;
|
||||
case VK_FORMAT_D32_SFLOAT: return GL_FLOAT;
|
||||
case VK_FORMAT_S8_UINT: return GL_UNSIGNED_BYTE;
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT: return GL_UNSIGNED_INT_24_8;
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT: return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
|
||||
case VK_FORMAT_A4R4G4B4_UNORM_PACK16: return GL_UNSIGNED_SHORT_4_4_4_4_REV;
|
||||
case VK_FORMAT_A4B4G4R4_UNORM_PACK16: return GL_UNSIGNED_SHORT_4_4_4_4_REV;
|
||||
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR: return GL_UNSIGNED_SHORT_1_5_5_5_REV;
|
||||
case VK_FORMAT_A8_UNORM_KHR: return GL_UNSIGNED_BYTE;
|
||||
+1392
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2017-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Retrieve Vulkan function pointers needed by libktx
|
||||
*/
|
||||
|
||||
#define UNIX 0
|
||||
#define MACOS 0
|
||||
#define WINDOWS 0
|
||||
#define IOS 0
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef WINDOWS
|
||||
#define WINDOWS 1
|
||||
#endif
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__)
|
||||
#undef UNIX
|
||||
#define UNIX 1
|
||||
#endif
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
#undef UNIX
|
||||
#define UNIX 1
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__x86_64__)
|
||||
#undef MACOS
|
||||
#define MACOS 1
|
||||
#endif
|
||||
#if defined(__APPLE__) && (defined(__arm64__) || defined (__arm__))
|
||||
#undef IOS
|
||||
#define IOS 1
|
||||
#endif
|
||||
#if (IOS + MACOS + UNIX + WINDOWS) > 1
|
||||
#error "Multiple OS\'s defined"
|
||||
#endif
|
||||
|
||||
#include "vk_funcs.h"
|
||||
|
||||
|
||||
#if WINDOWS
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "ktx.h"
|
||||
|
||||
#if WINDOWS
|
||||
HMODULE ktxVulkanModuleHandle;
|
||||
#define GetVulkanModuleHandle(flags) ktxGetVulkanModuleHandle()
|
||||
#define LoadProcAddr GetProcAddress
|
||||
#elif MACOS || UNIX || IOS
|
||||
// Using NULL returns a handle that can be used to search the process that
|
||||
// loaded us and any other libraries it has loaded. That's all we need to
|
||||
// search as the app is responsible for creating the GL context so it must
|
||||
// be there.
|
||||
#define GetVulkanModuleHandle(flags) dlopen(NULL, flags)
|
||||
#define LoadProcAddr dlsym
|
||||
void* ktxVulkanModuleHandle;
|
||||
#else
|
||||
#error "Don\'t know how to load symbols on this OS."
|
||||
#endif
|
||||
|
||||
#if WINDOWS
|
||||
#define VULKANLIB "vulkan-1.dll"
|
||||
static HMODULE
|
||||
ktxGetVulkanModuleHandle()
|
||||
{
|
||||
HMODULE module = NULL;
|
||||
GetModuleHandleExA(
|
||||
0,
|
||||
VULKANLIB,
|
||||
&module
|
||||
);
|
||||
return module;
|
||||
}
|
||||
#endif
|
||||
|
||||
ktx_error_code_e
|
||||
ktxLoadVulkanLibrary(void)
|
||||
{
|
||||
if (ktxVulkanModuleHandle)
|
||||
return KTX_SUCCESS;
|
||||
|
||||
ktxVulkanModuleHandle = GetVulkanModuleHandle(RTLD_LAZY);
|
||||
if (ktxVulkanModuleHandle == NULL) {
|
||||
fprintf(stderr, "Vulkan lib not linked or loaded by application.\n");
|
||||
// Normal use is for this constructor to be called by an
|
||||
// application that has completed OpenGL initialization. In that
|
||||
// case the only cause for failure would be a coding error in our
|
||||
// library loading. The only other cause would be an application
|
||||
// calling GLUpload without having initialized OpenGL.
|
||||
#if defined(DEBUG)
|
||||
abort();
|
||||
#else
|
||||
return KTX_LIBRARY_NOT_LINKED; // So release version doesn't crash.
|
||||
#endif
|
||||
}
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
PFN_vkVoidFunction
|
||||
ktxLoadVulkanFunction(const char* pName) {
|
||||
ktx_error_code_e rc = ktxLoadVulkanLibrary();
|
||||
if (rc != KTX_SUCCESS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PFN_vkVoidFunction pfn
|
||||
= (PFN_vkVoidFunction)LoadProcAddr(ktxVulkanModuleHandle, pName);
|
||||
if (pfn == NULL) {
|
||||
fprintf(stderr, "Couldn't load Vulkan command: %s\n", pName);
|
||||
return NULL;
|
||||
}
|
||||
return pfn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab textwidth=70: */
|
||||
|
||||
/*
|
||||
* Copyright 2017-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Declare pointers for Vulkan functions.
|
||||
*
|
||||
* Dynamically retrieving pointers avoids apps having to make sure a
|
||||
* Vulkan library is available when using a shared libktx, even if
|
||||
* not using libktx's Vulkan loader.
|
||||
*/
|
||||
|
||||
#ifndef _VK_FUNCS_H_
|
||||
#define _VK_FUNCS_H_
|
||||
|
||||
#if !defined(VK_NO_PROTOTYPES)
|
||||
#define VK_NO_PROTOTYPES
|
||||
#endif
|
||||
|
||||
#include "vulkan/vk_platform.h"
|
||||
#include "vulkan/vulkan_core.h"
|
||||
#include "ktx.h"
|
||||
|
||||
|
||||
#if WINDOWS
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
extern HMODULE ktxVulkanModuleHandle;
|
||||
#else
|
||||
extern void* ktxVulkanModuleHandle;
|
||||
#endif
|
||||
|
||||
ktx_error_code_e ktxLoadVulkanLibrary(void);
|
||||
|
||||
// This is used to load instance functions through libktx's methods.
|
||||
PFN_vkVoidFunction ktxLoadVulkanFunction(const char* pName);
|
||||
|
||||
|
||||
#endif /* _VK_FUNCS_H_ */
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
|
||||
/***************************** Do not edit. *****************************
|
||||
Automatically generated from vulkan_core.h version 287 by mkvkformatfiles.
|
||||
*************************************************************************/
|
||||
|
||||
/*
|
||||
** Copyright 2015-2024 The Khronos Group Inc.
|
||||
**
|
||||
** SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// clang-format off: CI is complicated if formatting checks on generated files are enforced.
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "vkformat_enum.h"
|
||||
|
||||
bool
|
||||
isProhibitedFormat(VkFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case VK_FORMAT_R8_USCALED:
|
||||
case VK_FORMAT_R8_SSCALED:
|
||||
case VK_FORMAT_R8G8_USCALED:
|
||||
case VK_FORMAT_R8G8_SSCALED:
|
||||
case VK_FORMAT_R8G8B8_USCALED:
|
||||
case VK_FORMAT_R8G8B8_SSCALED:
|
||||
case VK_FORMAT_B8G8R8_USCALED:
|
||||
case VK_FORMAT_B8G8R8_SSCALED:
|
||||
case VK_FORMAT_R8G8B8A8_USCALED:
|
||||
case VK_FORMAT_R8G8B8A8_SSCALED:
|
||||
case VK_FORMAT_B8G8R8A8_USCALED:
|
||||
case VK_FORMAT_B8G8R8A8_SSCALED:
|
||||
case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
|
||||
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
|
||||
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
|
||||
case VK_FORMAT_R16_USCALED:
|
||||
case VK_FORMAT_R16_SSCALED:
|
||||
case VK_FORMAT_R16G16_USCALED:
|
||||
case VK_FORMAT_R16G16_SSCALED:
|
||||
case VK_FORMAT_R16G16B16_USCALED:
|
||||
case VK_FORMAT_R16G16B16_SSCALED:
|
||||
case VK_FORMAT_R16G16B16A16_USCALED:
|
||||
case VK_FORMAT_R16G16B16A16_SSCALED:
|
||||
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
|
||||
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
|
||||
case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
|
||||
case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
|
||||
case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
|
||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
|
||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
|
||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
|
||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
|
||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
|
||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
|
||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
|
||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
|
||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
|
||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
|
||||
case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
|
||||
case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
|
||||
case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
|
||||
case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
|
||||
case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
|
||||
case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
|
||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
|
||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
|
||||
case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
isSrgbFormat(VkFormat format)
|
||||
{
|
||||
switch(format) {
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
case VK_FORMAT_R8G8_SRGB:
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
|
||||
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
|
||||
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
|
||||
case VK_FORMAT_BC2_SRGB_BLOCK:
|
||||
case VK_FORMAT_BC3_SRGB_BLOCK:
|
||||
case VK_FORMAT_BC7_SRGB_BLOCK:
|
||||
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
|
||||
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
|
||||
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
|
||||
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
|
||||
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
isValidFormat(VkFormat format)
|
||||
{
|
||||
// On MSVC VkFormat can be a signed integer
|
||||
if ((uint32_t) format <= VK_FORMAT_MAX_STANDARD_ENUM)
|
||||
return true;
|
||||
else switch(format) {
|
||||
case VK_FORMAT_G8B8G8R8_422_UNORM:
|
||||
case VK_FORMAT_B8G8R8G8_422_UNORM:
|
||||
case VK_FORMAT_R10X6_UNORM_PACK16:
|
||||
case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
|
||||
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
|
||||
case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
|
||||
case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
|
||||
case VK_FORMAT_R12X4_UNORM_PACK16:
|
||||
case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
|
||||
case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
|
||||
case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
|
||||
case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
|
||||
case VK_FORMAT_G16B16G16R16_422_UNORM:
|
||||
case VK_FORMAT_B16G16R16G16_422_UNORM:
|
||||
case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
|
||||
case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
|
||||
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
|
||||
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
|
||||
case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT:
|
||||
case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT:
|
||||
case VK_FORMAT_R16G16_SFIXED5_NV:
|
||||
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
|
||||
case VK_FORMAT_A8_UNORM_KHR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
** Copyright 2025 The Khronos Group Inc.
|
||||
**
|
||||
** SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "vkformat_enum.h"
|
||||
|
||||
bool
|
||||
isNotSrgbFormatButHasSrgbVariant(VkFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
// VK_FORMAT_R8_SRGB
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
case VK_FORMAT_R8_SNORM:
|
||||
case VK_FORMAT_R8_UINT:
|
||||
case VK_FORMAT_R8_SINT:
|
||||
|
||||
// VK_FORMAT_R8G8_SRGB
|
||||
case VK_FORMAT_R8G8_UNORM:
|
||||
case VK_FORMAT_R8G8_SNORM:
|
||||
case VK_FORMAT_R8G8_UINT:
|
||||
case VK_FORMAT_R8G8_SINT:
|
||||
|
||||
// VK_FORMAT_R8G8B8_SRGB
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
case VK_FORMAT_R8G8B8_SNORM:
|
||||
case VK_FORMAT_R8G8B8_UINT:
|
||||
case VK_FORMAT_R8G8B8_SINT:
|
||||
|
||||
// VK_FORMAT_B8G8R8_SRGB
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
case VK_FORMAT_B8G8R8_SNORM:
|
||||
case VK_FORMAT_B8G8R8_UINT:
|
||||
case VK_FORMAT_B8G8R8_SINT:
|
||||
|
||||
// VK_FORMAT_R8G8B8A8_SRGB
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
case VK_FORMAT_R8G8B8A8_SNORM:
|
||||
case VK_FORMAT_R8G8B8A8_UINT:
|
||||
case VK_FORMAT_R8G8B8A8_SINT:
|
||||
|
||||
// VK_FORMAT_B8G8R8A8_SRGB
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SNORM:
|
||||
case VK_FORMAT_B8G8R8A8_UINT:
|
||||
case VK_FORMAT_B8G8R8A8_SINT:
|
||||
|
||||
// VK_FORMAT_A8B8G8R8_SRGB_PACK32
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_UINT_PACK32:
|
||||
case VK_FORMAT_A8B8G8R8_SINT_PACK32:
|
||||
|
||||
// VK_FORMAT_BC1_RGB_SRGB_BLOCK
|
||||
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_BC1_RGBA_SRGB_BLOCK
|
||||
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_BC2_SRGB_BLOCK
|
||||
case VK_FORMAT_BC2_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_BC3_SRGB_BLOCK
|
||||
case VK_FORMAT_BC3_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_BC7_SRGB_BLOCK
|
||||
case VK_FORMAT_BC7_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK
|
||||
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK
|
||||
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK
|
||||
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_4x4_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_5x4_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_5x5_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_6x5_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_6x6_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_8x5_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_8x6_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_8x8_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_10x5_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_10x6_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_10x8_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_10x10_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_12x10_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_ASTC_12x12_SRGB_BLOCK
|
||||
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
|
||||
|
||||
// VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG
|
||||
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
|
||||
|
||||
// VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG
|
||||
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
|
||||
|
||||
// VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG
|
||||
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
|
||||
|
||||
// VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG
|
||||
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
|
||||
|
||||
// VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT:
|
||||
|
||||
// VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT
|
||||
case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
// clang-format off: CI is complicated if formatting checks on generated files are enforced.
|
||||
#if !defined(_VKFORMAT_ENUM_H_) && !defined(VULKAN_CORE_H_)
|
||||
#define _VKFORMAT_ENUM_H_
|
||||
|
||||
/***************************** Do not edit. *****************************
|
||||
Automatically generated from vulkan_core.h version 287 by mkvkformatfiles.
|
||||
*************************************************************************/
|
||||
|
||||
/*
|
||||
** Copyright 2015-2024 The Khronos Group Inc.
|
||||
**
|
||||
** SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900 // Older than VS 2015.
|
||||
typedef unsigned __int32 VkFlags;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
typedef uint32_t VkFlags;
|
||||
#endif
|
||||
|
||||
typedef enum VkFormat {
|
||||
VK_FORMAT_UNDEFINED = 0,
|
||||
VK_FORMAT_R4G4_UNORM_PACK8 = 1,
|
||||
VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,
|
||||
VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,
|
||||
VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,
|
||||
VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,
|
||||
VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,
|
||||
VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,
|
||||
VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,
|
||||
VK_FORMAT_R8_UNORM = 9,
|
||||
VK_FORMAT_R8_SNORM = 10,
|
||||
VK_FORMAT_R8_USCALED = 11,
|
||||
VK_FORMAT_R8_SSCALED = 12,
|
||||
VK_FORMAT_R8_UINT = 13,
|
||||
VK_FORMAT_R8_SINT = 14,
|
||||
VK_FORMAT_R8_SRGB = 15,
|
||||
VK_FORMAT_R8G8_UNORM = 16,
|
||||
VK_FORMAT_R8G8_SNORM = 17,
|
||||
VK_FORMAT_R8G8_USCALED = 18,
|
||||
VK_FORMAT_R8G8_SSCALED = 19,
|
||||
VK_FORMAT_R8G8_UINT = 20,
|
||||
VK_FORMAT_R8G8_SINT = 21,
|
||||
VK_FORMAT_R8G8_SRGB = 22,
|
||||
VK_FORMAT_R8G8B8_UNORM = 23,
|
||||
VK_FORMAT_R8G8B8_SNORM = 24,
|
||||
VK_FORMAT_R8G8B8_USCALED = 25,
|
||||
VK_FORMAT_R8G8B8_SSCALED = 26,
|
||||
VK_FORMAT_R8G8B8_UINT = 27,
|
||||
VK_FORMAT_R8G8B8_SINT = 28,
|
||||
VK_FORMAT_R8G8B8_SRGB = 29,
|
||||
VK_FORMAT_B8G8R8_UNORM = 30,
|
||||
VK_FORMAT_B8G8R8_SNORM = 31,
|
||||
VK_FORMAT_B8G8R8_USCALED = 32,
|
||||
VK_FORMAT_B8G8R8_SSCALED = 33,
|
||||
VK_FORMAT_B8G8R8_UINT = 34,
|
||||
VK_FORMAT_B8G8R8_SINT = 35,
|
||||
VK_FORMAT_B8G8R8_SRGB = 36,
|
||||
VK_FORMAT_R8G8B8A8_UNORM = 37,
|
||||
VK_FORMAT_R8G8B8A8_SNORM = 38,
|
||||
VK_FORMAT_R8G8B8A8_USCALED = 39,
|
||||
VK_FORMAT_R8G8B8A8_SSCALED = 40,
|
||||
VK_FORMAT_R8G8B8A8_UINT = 41,
|
||||
VK_FORMAT_R8G8B8A8_SINT = 42,
|
||||
VK_FORMAT_R8G8B8A8_SRGB = 43,
|
||||
VK_FORMAT_B8G8R8A8_UNORM = 44,
|
||||
VK_FORMAT_B8G8R8A8_SNORM = 45,
|
||||
VK_FORMAT_B8G8R8A8_USCALED = 46,
|
||||
VK_FORMAT_B8G8R8A8_SSCALED = 47,
|
||||
VK_FORMAT_B8G8R8A8_UINT = 48,
|
||||
VK_FORMAT_B8G8R8A8_SINT = 49,
|
||||
VK_FORMAT_B8G8R8A8_SRGB = 50,
|
||||
VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,
|
||||
VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,
|
||||
VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,
|
||||
VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,
|
||||
VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,
|
||||
VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,
|
||||
VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,
|
||||
VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,
|
||||
VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,
|
||||
VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,
|
||||
VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,
|
||||
VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,
|
||||
VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,
|
||||
VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,
|
||||
VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,
|
||||
VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,
|
||||
VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,
|
||||
VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,
|
||||
VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,
|
||||
VK_FORMAT_R16_UNORM = 70,
|
||||
VK_FORMAT_R16_SNORM = 71,
|
||||
VK_FORMAT_R16_USCALED = 72,
|
||||
VK_FORMAT_R16_SSCALED = 73,
|
||||
VK_FORMAT_R16_UINT = 74,
|
||||
VK_FORMAT_R16_SINT = 75,
|
||||
VK_FORMAT_R16_SFLOAT = 76,
|
||||
VK_FORMAT_R16G16_UNORM = 77,
|
||||
VK_FORMAT_R16G16_SNORM = 78,
|
||||
VK_FORMAT_R16G16_USCALED = 79,
|
||||
VK_FORMAT_R16G16_SSCALED = 80,
|
||||
VK_FORMAT_R16G16_UINT = 81,
|
||||
VK_FORMAT_R16G16_SINT = 82,
|
||||
VK_FORMAT_R16G16_SFLOAT = 83,
|
||||
VK_FORMAT_R16G16B16_UNORM = 84,
|
||||
VK_FORMAT_R16G16B16_SNORM = 85,
|
||||
VK_FORMAT_R16G16B16_USCALED = 86,
|
||||
VK_FORMAT_R16G16B16_SSCALED = 87,
|
||||
VK_FORMAT_R16G16B16_UINT = 88,
|
||||
VK_FORMAT_R16G16B16_SINT = 89,
|
||||
VK_FORMAT_R16G16B16_SFLOAT = 90,
|
||||
VK_FORMAT_R16G16B16A16_UNORM = 91,
|
||||
VK_FORMAT_R16G16B16A16_SNORM = 92,
|
||||
VK_FORMAT_R16G16B16A16_USCALED = 93,
|
||||
VK_FORMAT_R16G16B16A16_SSCALED = 94,
|
||||
VK_FORMAT_R16G16B16A16_UINT = 95,
|
||||
VK_FORMAT_R16G16B16A16_SINT = 96,
|
||||
VK_FORMAT_R16G16B16A16_SFLOAT = 97,
|
||||
VK_FORMAT_R32_UINT = 98,
|
||||
VK_FORMAT_R32_SINT = 99,
|
||||
VK_FORMAT_R32_SFLOAT = 100,
|
||||
VK_FORMAT_R32G32_UINT = 101,
|
||||
VK_FORMAT_R32G32_SINT = 102,
|
||||
VK_FORMAT_R32G32_SFLOAT = 103,
|
||||
VK_FORMAT_R32G32B32_UINT = 104,
|
||||
VK_FORMAT_R32G32B32_SINT = 105,
|
||||
VK_FORMAT_R32G32B32_SFLOAT = 106,
|
||||
VK_FORMAT_R32G32B32A32_UINT = 107,
|
||||
VK_FORMAT_R32G32B32A32_SINT = 108,
|
||||
VK_FORMAT_R32G32B32A32_SFLOAT = 109,
|
||||
VK_FORMAT_R64_UINT = 110,
|
||||
VK_FORMAT_R64_SINT = 111,
|
||||
VK_FORMAT_R64_SFLOAT = 112,
|
||||
VK_FORMAT_R64G64_UINT = 113,
|
||||
VK_FORMAT_R64G64_SINT = 114,
|
||||
VK_FORMAT_R64G64_SFLOAT = 115,
|
||||
VK_FORMAT_R64G64B64_UINT = 116,
|
||||
VK_FORMAT_R64G64B64_SINT = 117,
|
||||
VK_FORMAT_R64G64B64_SFLOAT = 118,
|
||||
VK_FORMAT_R64G64B64A64_UINT = 119,
|
||||
VK_FORMAT_R64G64B64A64_SINT = 120,
|
||||
VK_FORMAT_R64G64B64A64_SFLOAT = 121,
|
||||
VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,
|
||||
VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,
|
||||
VK_FORMAT_D16_UNORM = 124,
|
||||
VK_FORMAT_X8_D24_UNORM_PACK32 = 125,
|
||||
VK_FORMAT_D32_SFLOAT = 126,
|
||||
VK_FORMAT_S8_UINT = 127,
|
||||
VK_FORMAT_D16_UNORM_S8_UINT = 128,
|
||||
VK_FORMAT_D24_UNORM_S8_UINT = 129,
|
||||
VK_FORMAT_D32_SFLOAT_S8_UINT = 130,
|
||||
VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,
|
||||
VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,
|
||||
VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,
|
||||
VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,
|
||||
VK_FORMAT_BC2_UNORM_BLOCK = 135,
|
||||
VK_FORMAT_BC2_SRGB_BLOCK = 136,
|
||||
VK_FORMAT_BC3_UNORM_BLOCK = 137,
|
||||
VK_FORMAT_BC3_SRGB_BLOCK = 138,
|
||||
VK_FORMAT_BC4_UNORM_BLOCK = 139,
|
||||
VK_FORMAT_BC4_SNORM_BLOCK = 140,
|
||||
VK_FORMAT_BC5_UNORM_BLOCK = 141,
|
||||
VK_FORMAT_BC5_SNORM_BLOCK = 142,
|
||||
VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,
|
||||
VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,
|
||||
VK_FORMAT_BC7_UNORM_BLOCK = 145,
|
||||
VK_FORMAT_BC7_SRGB_BLOCK = 146,
|
||||
VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,
|
||||
VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,
|
||||
VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,
|
||||
VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,
|
||||
VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,
|
||||
VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,
|
||||
VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,
|
||||
VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,
|
||||
VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,
|
||||
VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,
|
||||
VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,
|
||||
VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,
|
||||
VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,
|
||||
VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,
|
||||
VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,
|
||||
VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,
|
||||
VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,
|
||||
VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,
|
||||
VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,
|
||||
VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,
|
||||
VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,
|
||||
VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,
|
||||
VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,
|
||||
VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,
|
||||
VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,
|
||||
VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,
|
||||
VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,
|
||||
VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,
|
||||
VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,
|
||||
VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,
|
||||
VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,
|
||||
VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,
|
||||
VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,
|
||||
VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,
|
||||
VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,
|
||||
VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
|
||||
VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
|
||||
VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
|
||||
VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
|
||||
VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
|
||||
VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
|
||||
VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
|
||||
VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
|
||||
VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
|
||||
VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
|
||||
VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
|
||||
VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
|
||||
VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
|
||||
VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
|
||||
VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
|
||||
VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
|
||||
VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
|
||||
VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
|
||||
VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
|
||||
VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
|
||||
VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
|
||||
VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
|
||||
VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
|
||||
VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
|
||||
VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
|
||||
VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
|
||||
VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
|
||||
VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
|
||||
VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
|
||||
VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
|
||||
VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
|
||||
VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
|
||||
VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
|
||||
VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
|
||||
VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
|
||||
VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
|
||||
VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
|
||||
VK_FORMAT_G8_B8R8_2PLANE_444_UNORM = 1000330000,
|
||||
VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 = 1000330001,
|
||||
VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 = 1000330002,
|
||||
VK_FORMAT_G16_B16R16_2PLANE_444_UNORM = 1000330003,
|
||||
VK_FORMAT_A4R4G4B4_UNORM_PACK16 = 1000340000,
|
||||
VK_FORMAT_A4B4G4R4_UNORM_PACK16 = 1000340001,
|
||||
VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK = 1000066000,
|
||||
VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK = 1000066001,
|
||||
VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK = 1000066002,
|
||||
VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK = 1000066003,
|
||||
VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK = 1000066004,
|
||||
VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK = 1000066005,
|
||||
VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK = 1000066006,
|
||||
VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK = 1000066007,
|
||||
VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK = 1000066008,
|
||||
VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK = 1000066009,
|
||||
VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK = 1000066010,
|
||||
VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK = 1000066011,
|
||||
VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK = 1000066012,
|
||||
VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK = 1000066013,
|
||||
VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
|
||||
VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
|
||||
VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
|
||||
VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
|
||||
VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
|
||||
VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
|
||||
VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
|
||||
VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
|
||||
VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT = 1000288000,
|
||||
VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT = 1000288001,
|
||||
VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT = 1000288002,
|
||||
VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT = 1000288003,
|
||||
VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT = 1000288004,
|
||||
VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT = 1000288005,
|
||||
VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT = 1000288006,
|
||||
VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT = 1000288007,
|
||||
VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT = 1000288008,
|
||||
VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT = 1000288009,
|
||||
VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT = 1000288010,
|
||||
VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT = 1000288011,
|
||||
VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT = 1000288012,
|
||||
VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT = 1000288013,
|
||||
VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT = 1000288014,
|
||||
VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT = 1000288015,
|
||||
VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT = 1000288016,
|
||||
VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT = 1000288017,
|
||||
VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT = 1000288018,
|
||||
VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT = 1000288019,
|
||||
VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT = 1000288020,
|
||||
VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT = 1000288021,
|
||||
VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT = 1000288022,
|
||||
VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT = 1000288023,
|
||||
VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT = 1000288024,
|
||||
VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT = 1000288025,
|
||||
VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT = 1000288026,
|
||||
VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT = 1000288027,
|
||||
VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT = 1000288028,
|
||||
VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT = 1000288029,
|
||||
VK_FORMAT_R16G16_SFIXED5_NV = 1000464000,
|
||||
VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR = 1000470000,
|
||||
VK_FORMAT_A8_UNORM_KHR = 1000470001,
|
||||
VK_FORMAT_MAX_ENUM = 0x7FFFFFFF
|
||||
} VkFormat;
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900 // Older than VS 2015.
|
||||
typedef unsigned __int32 VkFlags;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
typedef uint64_t VkFlags64;
|
||||
#endif
|
||||
|
||||
|
||||
#define VK_FORMAT_MAX_STANDARD_ENUM 184
|
||||
|
||||
#endif /* _VKFORMAT_ENUM_H_ */
|
||||
// clang-format on
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,586 @@
|
||||
|
||||
/***************************** Do not edit. *****************************
|
||||
Automatically generated from vulkan_core.h version 287 by mkvkformatfiles.
|
||||
*************************************************************************/
|
||||
|
||||
/*
|
||||
** Copyright 2015-2024 The Khronos Group Inc.
|
||||
**
|
||||
** SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// clang-format off: CI is complicated if formatting checks on generated files are enforced.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "vkformat_enum.h"
|
||||
|
||||
uint32_t
|
||||
vkFormatTypeSize(VkFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case VK_FORMAT_UNDEFINED:
|
||||
return 1;
|
||||
case VK_FORMAT_R4G4_UNORM_PACK8:
|
||||
return 1;
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R8_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8_SNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8_USCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8_SSCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8_UINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8_SINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_SNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_USCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_SSCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_UINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_SINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8_SRGB:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8_SNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8_USCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8_SSCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8_UINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8_SINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8_SNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8_USCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8_SSCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8_UINT:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8_SINT:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8A8_SNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8A8_USCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8A8_SSCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8A8_UINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8A8_SINT:
|
||||
return 1;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8A8_SNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8A8_USCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8A8_SSCALED:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8A8_UINT:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8A8_SINT:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return 1;
|
||||
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A8B8G8R8_UINT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A8B8G8R8_SINT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2R10G10B10_UINT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2R10G10B10_SINT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_A2B10G10R10_SINT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_R16_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16_SNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16_USCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16_SSCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16_UINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16_SINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16_SFLOAT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_SNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_USCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_SSCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_UINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_SINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16_SFLOAT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16_SNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16_USCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16_SSCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16_UINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16_SINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16_SFLOAT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16A16_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16A16_SNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16A16_USCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16A16_SSCALED:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16A16_UINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16A16_SINT:
|
||||
return 2;
|
||||
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||
return 2;
|
||||
case VK_FORMAT_R32_UINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32_SINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32_SFLOAT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32_UINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32_SINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32_SFLOAT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32B32_UINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32B32_SINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32B32_SFLOAT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32B32A32_UINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32B32A32_SINT:
|
||||
return 4;
|
||||
case VK_FORMAT_R32G32B32A32_SFLOAT:
|
||||
return 4;
|
||||
case VK_FORMAT_R64_UINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64_SINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64_SFLOAT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64_UINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64_SINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64_SFLOAT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64B64_UINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64B64_SINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64B64_SFLOAT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64B64A64_UINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64B64A64_SINT:
|
||||
return 8;
|
||||
case VK_FORMAT_R64G64B64A64_SFLOAT:
|
||||
return 8;
|
||||
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_D16_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||
return 4;
|
||||
case VK_FORMAT_D32_SFLOAT:
|
||||
return 4;
|
||||
case VK_FORMAT_S8_UINT:
|
||||
return 1;
|
||||
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||
return 2;
|
||||
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||
return 4;
|
||||
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||
return 4;
|
||||
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC2_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC2_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC3_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC3_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC4_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC4_SNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC5_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC5_SNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC7_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_BC7_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_G8B8G8R8_422_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_B8G8R8G8_422_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_R10X6_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R12X4_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G16B16G16R16_422_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_B16G16R16G16_422_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
|
||||
return 1;
|
||||
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
|
||||
return 2;
|
||||
case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
|
||||
return 2;
|
||||
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_3x3x3_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_3x3x3_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_3x3x3_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x3x3_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x3x3_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x3x3_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4x3_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4x3_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4x3_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4x4_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4x4_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_4x4x4_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x4x4_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x4x4_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x4x4_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5x4_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5x4_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5x4_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5x5_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5x5_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_5x5x5_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x5x5_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x5x5_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x5x5_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6x5_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6x5_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6x5_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6x6_UNORM_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6x6_SRGB_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_ASTC_6x6x6_SFLOAT_BLOCK_EXT:
|
||||
return 1;
|
||||
case VK_FORMAT_R16G16_SFIXED5_NV:
|
||||
return 2;
|
||||
case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
|
||||
return 2;
|
||||
case VK_FORMAT_A8_UNORM_KHR:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
+1983
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,978 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Functions for creating KTX-format files from a set of images.
|
||||
*
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2018-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(__GNUC__)
|
||||
#include <strings.h> // For strncasecmp on GNU/Linux
|
||||
#endif
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
#include "filestream.h"
|
||||
#include "memstream.h"
|
||||
#include "texture1.h"
|
||||
|
||||
#include "dfdutils/dfd.h"
|
||||
#include "vkformat_enum.h"
|
||||
#include "vk_format.h"
|
||||
#include "version.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup writer Writer
|
||||
* @brief Write KTX-formatted data.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture @private
|
||||
* @~English
|
||||
* @brief Set image for level, layer, faceSlice from a ktxStream source.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] level mip level of the image to set.
|
||||
* @param[in] layer array layer of the image to set.
|
||||
* @param[in] faceSlice cube map face or depth slice of the image to set.
|
||||
* @param[in] src ktxStream pointer to the source.
|
||||
* @param[in] srcSize size of the source image in bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p src is NULL.
|
||||
* @exception KTX_INVALID_VALUE @p srcSize != the expected image size for the
|
||||
* specified level, layer & faceSlice.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* No storage was allocated when the texture was
|
||||
* created.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_setImageFromStream(ktxTexture1* This, ktx_uint32_t level,
|
||||
ktx_uint32_t layer, ktx_uint32_t faceSlice,
|
||||
ktxStream* src, ktx_size_t srcSize)
|
||||
{
|
||||
ktx_uint32_t packedRowBytes, rowBytes, rowPadding, numRows = 0;
|
||||
ktx_size_t packedBytes, unpackedBytes;
|
||||
ktx_size_t imageOffset;
|
||||
#if (KTX_GL_UNPACK_ALIGNMENT != 4)
|
||||
ktx_uint32_t faceLodPadding;
|
||||
#endif
|
||||
|
||||
if (!This || !src)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
if (!This->pData)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
ktxTexture_GetImageOffset(ktxTexture(This), level, layer, faceSlice, &imageOffset);
|
||||
|
||||
if (This->isCompressed) {
|
||||
packedBytes = ktxTexture_GetImageSize(ktxTexture(This), level);
|
||||
rowPadding = 0;
|
||||
// These 2 are not used when rowPadding == 0. Quiets compiler warning.
|
||||
packedRowBytes = 0;
|
||||
rowBytes = 0;
|
||||
} else {
|
||||
ktxTexture_rowInfo(ktxTexture(This), level, &numRows, &rowBytes, &rowPadding);
|
||||
unpackedBytes = rowBytes * numRows;
|
||||
if (rowPadding) {
|
||||
packedRowBytes = rowBytes - rowPadding;
|
||||
packedBytes = packedRowBytes * numRows;
|
||||
} else {
|
||||
packedRowBytes = rowBytes;
|
||||
packedBytes = unpackedBytes;
|
||||
}
|
||||
}
|
||||
|
||||
if (srcSize != packedBytes)
|
||||
return KTX_INVALID_OPERATION;
|
||||
// The above will catch a flagrantly invalid srcSize. This is an
|
||||
// additional check of the internal calculations.
|
||||
assert (imageOffset + srcSize <= This->dataSize);
|
||||
|
||||
#if (KTX_GL_UNPACK_ALIGNMENT != 4)
|
||||
faceLodPadding = _KTX_PAD4_LEN(faceLodSize);
|
||||
#endif
|
||||
|
||||
if (rowPadding == 0) {
|
||||
/* Can copy whole image at once */
|
||||
src->read(src, This->pData + imageOffset, srcSize);
|
||||
} else {
|
||||
/* Copy the rows individually, padding each one */
|
||||
ktx_uint32_t row;
|
||||
ktx_uint8_t* dst = This->pData + imageOffset;
|
||||
ktx_uint8_t pad[4] = { 0, 0, 0, 0 };
|
||||
for (row = 0; row < numRows; row++) {
|
||||
ktx_uint32_t rowOffset = rowBytes * row;
|
||||
src->read(src, dst + rowOffset, packedRowBytes);
|
||||
memcpy(dst + rowOffset + packedRowBytes, pad, rowPadding);
|
||||
}
|
||||
}
|
||||
#if (KTX_GL_UNPACK_ALIGNMENT != 4)
|
||||
/*
|
||||
* When KTX_GL_UNPACK_ALIGNMENT == 4, rows, and therefore everything else,
|
||||
* are always 4-byte aligned and faceLodPadding is always 0. It is always
|
||||
* 0 for compressed formats too because they all have multiple-of-4 block
|
||||
* sizes.
|
||||
*/
|
||||
if (faceLodPadding)
|
||||
memcpy(This->pData + faceLodSize, pad, faceLodPadding);
|
||||
#endif
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Set image for level, layer, faceSlice from a stdio stream source.
|
||||
*
|
||||
* Uncompressed images read from the stream are expected to have their rows
|
||||
* tightly packed as is the norm for most image file formats. The copied image
|
||||
* is padded as necessary to achieve the KTX-specified row alignment. No
|
||||
* padding is done if the ktxTexture's @c isCompressed field is @c KTX_TRUE.
|
||||
*
|
||||
* Level, layer, faceSlice rather than offset are specified to enable some
|
||||
* validation.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] level mip level of the image to set.
|
||||
* @param[in] layer array layer of the image to set.
|
||||
* @param[in] faceSlice cube map face or depth slice of the image to set.
|
||||
* @param[in] src stdio stream pointer to the source.
|
||||
* @param[in] srcSize size of the source image in bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p src is NULL.
|
||||
* @exception KTX_INVALID_VALUE @p srcSize != the expected image size for the
|
||||
* specified level, layer & faceSlice.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* No storage was allocated when the texture was
|
||||
* created.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_SetImageFromStdioStream(ktxTexture1* This, ktx_uint32_t level,
|
||||
ktx_uint32_t layer, ktx_uint32_t faceSlice,
|
||||
FILE* src, ktx_size_t srcSize)
|
||||
{
|
||||
ktxStream srcstr;
|
||||
KTX_error_code result;
|
||||
|
||||
result = ktxFileStream_construct(&srcstr, src, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
result = ktxTexture1_setImageFromStream(This, level, layer, faceSlice,
|
||||
&srcstr, srcSize);
|
||||
ktxFileStream_destruct(&srcstr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Set image for level, layer, faceSlice from an image in memory.
|
||||
*
|
||||
* Uncompressed images in memory are expected to have their rows tightly packed
|
||||
* as is the norm for most image file formats. The copied image is padded as
|
||||
* necessary to achieve the KTX-specified row alignment. No padding is done if
|
||||
* the ktxTexture's @c isCompressed field is @c KTX_TRUE.
|
||||
*
|
||||
* Level, layer, faceSlice rather than offset are specified to enable some
|
||||
* validation.
|
||||
*
|
||||
* @warning Do not use @c memcpy for this as it will not pad when necessary.
|
||||
*
|
||||
* @note The caller is responsible for freeing the original image memory
|
||||
* referred to by @p src.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] level mip level of the image to set.
|
||||
* @param[in] layer array layer of the image to set.
|
||||
* @param[in] faceSlice cube map face or depth slice of the image to set.
|
||||
* @param[in] src pointer to the image source in memory.
|
||||
* @param[in] srcSize size of the source image in bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p src is NULL.
|
||||
* @exception KTX_INVALID_VALUE @p srcSize != the expected image size for the
|
||||
* specified level, layer & faceSlice.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* No storage was allocated when the texture was
|
||||
* created.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_SetImageFromMemory(ktxTexture1* This, ktx_uint32_t level,
|
||||
ktx_uint32_t layer, ktx_uint32_t faceSlice,
|
||||
const ktx_uint8_t* src, ktx_size_t srcSize)
|
||||
{
|
||||
ktxStream srcstr;
|
||||
KTX_error_code result;
|
||||
|
||||
result = ktxMemStream_construct_ro(&srcstr, src, srcSize);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
result = ktxTexture1_setImageFromStream(This, level, layer, faceSlice,
|
||||
&srcstr, srcSize);
|
||||
ktxMemStream_destruct(&srcstr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a ktxStream in KTX format.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dststr destination ktxStream.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dststr is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteToStream(ktxTexture1* This, ktxStream* dststr)
|
||||
{
|
||||
KTX_header header = { .identifier = KTX_IDENTIFIER_REF };
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
ktx_uint8_t* pKvd = 0;
|
||||
ktx_uint32_t level, levelOffset;
|
||||
|
||||
if (!dststr) {
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (This->pData == NULL)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
if (This->kvDataHead && This->kvData)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
//endianess int.. if this comes out reversed, all of the other ints will too.
|
||||
header.endianness = KTX_ENDIAN_REF;
|
||||
header.glInternalformat = This->glInternalformat;
|
||||
header.glFormat = This->glFormat;
|
||||
header.glBaseInternalformat = This->glBaseInternalformat;
|
||||
header.glType = This->glType;
|
||||
header.glTypeSize = ktxTexture1_glTypeSize(This);
|
||||
header.pixelWidth = This->baseWidth;
|
||||
header.pixelHeight = This->numDimensions > 1 ? This->baseHeight : 0;
|
||||
header.pixelDepth = This->numDimensions > 2 ? This->baseDepth : 0;
|
||||
header.numberOfArrayElements = This->isArray ? This->numLayers : 0;
|
||||
assert (This->isCubemap ? This->numFaces == 6 : This->numFaces == 1);
|
||||
header.numberOfFaces = This->numFaces;
|
||||
assert (This->generateMipmaps ? This->numLevels == 1 : This->numLevels >= 1);
|
||||
header.numberOfMipLevels = This->generateMipmaps ? 0 : This->numLevels;
|
||||
|
||||
if (This->kvDataHead != NULL) {
|
||||
ktxHashList_Serialize(&This->kvDataHead,
|
||||
&header.bytesOfKeyValueData, &pKvd);
|
||||
} else if (This->kvData) {
|
||||
pKvd = This->kvData;
|
||||
header.bytesOfKeyValueData = This->kvDataLen;
|
||||
} else {
|
||||
header.bytesOfKeyValueData = 0;
|
||||
}
|
||||
|
||||
//write header
|
||||
result = dststr->write(dststr, &header, sizeof(KTX_header), 1);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
//write keyValueData
|
||||
if (header.bytesOfKeyValueData != 0) {
|
||||
assert(pKvd != NULL);
|
||||
|
||||
result = dststr->write(dststr, pKvd, 1, header.bytesOfKeyValueData);
|
||||
if (This->kvDataHead != NULL)
|
||||
free(pKvd);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Write the image data */
|
||||
for (level = 0, levelOffset=0; level < This->numLevels; ++level)
|
||||
{
|
||||
ktx_uint32_t faceLodSize, layer, levelDepth, numImages;
|
||||
ktx_size_t imageSize;
|
||||
|
||||
faceLodSize = (ktx_uint32_t)ktxTexture_doCalcFaceLodSize(ktxTexture(This),
|
||||
level,
|
||||
KTX_FORMAT_VERSION_ONE);
|
||||
imageSize = ktxTexture_GetImageSize(ktxTexture(This), level);
|
||||
levelDepth = MAX(1, This->baseDepth >> level);
|
||||
if (This->isCubemap && !This->isArray)
|
||||
numImages = This->numFaces;
|
||||
else
|
||||
numImages = This->isCubemap ? This->numFaces : levelDepth;
|
||||
|
||||
result = dststr->write(dststr, &faceLodSize, sizeof(faceLodSize), 1);
|
||||
if (result != KTX_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
for (layer = 0; layer < This->numLayers; layer++) {
|
||||
ktx_uint32_t faceSlice;
|
||||
|
||||
for (faceSlice = 0; faceSlice < numImages; faceSlice++) {
|
||||
result = dststr->write(dststr, This->pData + levelOffset,
|
||||
imageSize, 1);
|
||||
levelOffset += (ktx_uint32_t)imageSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a stdio stream in KTX format.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dstsstr destination stdio stream.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dstsstr is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteToStdioStream(ktxTexture1* This, FILE* dstsstr)
|
||||
{
|
||||
ktxStream stream;
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
|
||||
if (!This)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
result = ktxFileStream_construct(&stream, dstsstr, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
return ktxTexture1_WriteToStream(This, &stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a named file in KTX format.
|
||||
*
|
||||
* The file name must be encoded in utf-8. On Windows convert unicode names
|
||||
* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dstname destination file name.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dstname is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteToNamedFile(ktxTexture1* This, const char* const dstname)
|
||||
{
|
||||
KTX_error_code result;
|
||||
FILE* dst;
|
||||
|
||||
if (!This)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
dst = ktxFOpenUTF8(dstname, "wb");
|
||||
if (dst) {
|
||||
result = ktxTexture1_WriteToStdioStream(This, dst);
|
||||
fclose(dst);
|
||||
} else
|
||||
result = KTX_FILE_OPEN_FAILED;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to block of memory in KTX format.
|
||||
*
|
||||
* Memory is allocated by the function and the caller is responsible for
|
||||
* freeing it.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in,out] ppDstBytes pointer to location to write the address of
|
||||
* the destination memory. The Application is
|
||||
* responsible for freeing this memory.
|
||||
* @param[in,out] pSize pointer to location to write the size in bytes of
|
||||
* the KTX data.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This, @p ppDstBytes or @p pSize is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteToMemory(ktxTexture1* This,
|
||||
ktx_uint8_t** ppDstBytes, ktx_size_t* pSize)
|
||||
{
|
||||
struct ktxStream dststr;
|
||||
KTX_error_code result;
|
||||
ktx_size_t strSize;
|
||||
|
||||
if (!This || !ppDstBytes || !pSize)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
*ppDstBytes = NULL;
|
||||
|
||||
result = ktxMemStream_construct(&dststr, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
result = ktxTexture1_WriteToStream(This, &dststr);
|
||||
if(result != KTX_SUCCESS)
|
||||
{
|
||||
ktxMemStream_destruct(&dststr);
|
||||
return result;
|
||||
}
|
||||
|
||||
ktxMemStream_getdata(&dststr, ppDstBytes);
|
||||
dststr.getsize(&dststr, &strSize);
|
||||
*pSize = (GLsizei)strSize;
|
||||
/* This function does not free the memory pointed at by the
|
||||
* value obtained from ktxMemStream_getdata() thanks to the
|
||||
* KTX_FALSE passed to the constructor above.
|
||||
*/
|
||||
ktxMemStream_destruct(&dststr);
|
||||
return KTX_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
ktx_uint32_t lcm4(uint32_t a);
|
||||
KTX_error_code appendLibId(ktxHashList* head,
|
||||
ktxHashListEntry* writerEntry);
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a ktxStream in KTX 2 format.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dststr destination ktxStream.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dststr is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture contains unknownY KTX- or ktx-
|
||||
* prefixed metadata keys.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The length of the already set writerId metadata
|
||||
* plus the library's version id exceeds the
|
||||
* maximum allowed.
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteKTX2ToStream(ktxTexture1* This, ktxStream* dststr)
|
||||
{
|
||||
KTX_header2 header = { .identifier = KTX2_IDENTIFIER_REF };
|
||||
KTX_error_code result;
|
||||
ktx_uint32_t kvdLen;
|
||||
ktx_uint8_t* pKvd;
|
||||
ktx_uint32_t initialLevelPadLen;
|
||||
ktxLevelIndexEntry* levelIndex = NULL;
|
||||
ktx_uint32_t levelIndexSize;
|
||||
ktx_uint32_t offset;
|
||||
ktx_uint32_t requiredLevelAlignment;
|
||||
|
||||
if (!dststr) {
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (This->pData == NULL)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
header.vkFormat
|
||||
= vkGetFormatFromOpenGLInternalFormat(This->glInternalformat);
|
||||
// The above function does not return any formats in the prohibited list.
|
||||
if (header.vkFormat == VK_FORMAT_UNDEFINED) {
|
||||
// XXX TODO. Handle ASTC HDR & 3D.
|
||||
return KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
}
|
||||
header.typeSize = ktxTexture1_glTypeSize(This);
|
||||
header.pixelWidth = This->baseWidth;
|
||||
header.pixelHeight = This->numDimensions > 1 ? This->baseHeight : 0;
|
||||
header.pixelDepth = This->numDimensions > 2 ? This->baseDepth : 0;
|
||||
header.layerCount = This->isArray ? This->numLayers : 0;
|
||||
assert (This->isCubemap ? This->numFaces == 6 : This->numFaces == 1);
|
||||
header.faceCount = This->numFaces;
|
||||
assert (This->generateMipmaps? This->numLevels == 1 : This->numLevels >= 1);
|
||||
header.levelCount = This->generateMipmaps ? 0 : This->numLevels;
|
||||
|
||||
levelIndexSize = sizeof(ktxLevelIndexEntry) * This->numLevels;
|
||||
levelIndex = (ktxLevelIndexEntry*) malloc(levelIndexSize);
|
||||
|
||||
offset = sizeof(header) + levelIndexSize;
|
||||
|
||||
ktx_uint32_t* dfd = vk2dfd(header.vkFormat);
|
||||
if (!dfd) {
|
||||
result = KTX_UNSUPPORTED_TEXTURE_TYPE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
header.dataFormatDescriptor.byteOffset = offset;
|
||||
header.dataFormatDescriptor.byteLength = *dfd;
|
||||
offset += header.dataFormatDescriptor.byteLength;
|
||||
|
||||
ktxHashListEntry* pEntry;
|
||||
// Check for invalid metadata.
|
||||
for (pEntry = This->kvDataHead; pEntry != NULL; pEntry = ktxHashList_Next(pEntry)) {
|
||||
unsigned int keyLen;
|
||||
char* key;
|
||||
|
||||
ktxHashListEntry_GetKey(pEntry, &keyLen, &key);
|
||||
if (strncasecmp(key, "KTX", 3) == 0) {
|
||||
// N.B. Writer metadata is not legal in a KTX v1 file but we know
|
||||
// we're going to write this out as a v2 file so we allow it so
|
||||
// conversion apps can identify themselves.
|
||||
if (strcmp(key, KTX_ORIENTATION_KEY) && strcmp(key, KTX_WRITER_KEY)) {
|
||||
result = KTX_INVALID_OPERATION;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = ktxHashList_FindEntry(&This->kvDataHead, KTX_ORIENTATION_KEY,
|
||||
&pEntry);
|
||||
// Rewrite the orientation value in the KTX2 form.
|
||||
if (result == KTX_SUCCESS) {
|
||||
unsigned int count;
|
||||
char* orientation;
|
||||
ktx_uint32_t orientationLen;
|
||||
char newOrient[4] = {0, 0, 0, 0};
|
||||
|
||||
result = ktxHashListEntry_GetValue(pEntry,
|
||||
&orientationLen, (void**)&orientation);
|
||||
count = sscanf(orientation, "S=%c,T=%c,R=%c",
|
||||
&newOrient[0],
|
||||
&newOrient[1],
|
||||
&newOrient[2]);
|
||||
|
||||
if (count < This->numDimensions) {
|
||||
// There needs to be an entry for each dimension of the texture.
|
||||
result = KTX_FILE_DATA_ERROR;
|
||||
goto cleanup;
|
||||
} else if (count > This->numDimensions) {
|
||||
// KTX 1 is less strict than KTX 2 so there is a chance of having
|
||||
// more dimensions than needed.
|
||||
count = This->numDimensions;
|
||||
newOrient[count] = '\0';
|
||||
}
|
||||
|
||||
ktxHashList_DeleteEntry(&This->kvDataHead, pEntry);
|
||||
ktxHashList_AddKVPair(&This->kvDataHead, KTX_ORIENTATION_KEY,
|
||||
count+1, newOrient);
|
||||
}
|
||||
pEntry = NULL;
|
||||
// See comment at valid metadata check at line 582.
|
||||
result = ktxHashList_FindEntry(&This->kvDataHead, KTX_WRITER_KEY,
|
||||
&pEntry);
|
||||
result = appendLibId(&This->kvDataHead, pEntry);
|
||||
if (result != KTX_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
ktxHashList_Sort(&This->kvDataHead); // KTX2 requires sorted metadata.
|
||||
ktxHashList_Serialize(&This->kvDataHead, &kvdLen, &pKvd);
|
||||
header.keyValueData.byteOffset = kvdLen != 0 ? offset : 0;
|
||||
header.keyValueData.byteLength = kvdLen;
|
||||
offset += kvdLen;
|
||||
|
||||
header.supercompressionGlobalData.byteOffset = 0;
|
||||
header.supercompressionGlobalData.byteLength = 0;
|
||||
|
||||
requiredLevelAlignment
|
||||
= lcm4(This->_protected->_formatSize.blockSizeInBits / 8);
|
||||
initialLevelPadLen = _KTX_PADN_LEN(requiredLevelAlignment, offset);
|
||||
offset += initialLevelPadLen;
|
||||
|
||||
for (ktx_int32_t level = This->numLevels - 1; level >= 0; level--) {
|
||||
ktx_size_t levelSize =
|
||||
ktxTexture_calcLevelSize(ktxTexture(This), level,
|
||||
KTX_FORMAT_VERSION_TWO);
|
||||
|
||||
levelIndex[level].uncompressedByteLength = levelSize;
|
||||
levelIndex[level].byteLength = levelSize;
|
||||
levelIndex[level].byteOffset = offset;
|
||||
offset += _KTX_PADN(requiredLevelAlignment, levelSize);
|
||||
}
|
||||
|
||||
// write header and indices
|
||||
result = dststr->write(dststr, &header, sizeof(header), 1);
|
||||
if (result != KTX_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
// write level index
|
||||
result = dststr->write(dststr, levelIndex, levelIndexSize, 1);
|
||||
if (result != KTX_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
// write data format descriptor
|
||||
result = dststr->write(dststr, dfd, 1, *dfd);
|
||||
|
||||
// write keyValueData
|
||||
if (kvdLen != 0) {
|
||||
assert(pKvd != NULL);
|
||||
|
||||
result = dststr->write(dststr, pKvd, 1, kvdLen);
|
||||
free(pKvd);
|
||||
if (result != KTX_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
char padding[32] = { 0 };
|
||||
// write supercompressionGlobalData & sgdPadding
|
||||
|
||||
if (initialLevelPadLen) {
|
||||
result = dststr->write(dststr, padding, 1, initialLevelPadLen);
|
||||
if (result != KTX_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the image data
|
||||
for (ktx_int32_t level = This->numLevels - 1;
|
||||
level >= 0 && result == KTX_SUCCESS; --level)
|
||||
{
|
||||
//ktx_uint64_t faceLodSize;
|
||||
ktx_uint32_t layer, levelDepth, numImages;
|
||||
ktx_uint32_t srcLevelOffset, srcOffset;
|
||||
ktx_size_t imageSize, dstLevelSize = 0;
|
||||
#define DUMP_IMAGE 0
|
||||
#if defined(DEBUG) || DUMP_IMAGE
|
||||
ktx_size_t pos;
|
||||
#endif
|
||||
imageSize = ktxTexture_calcImageSize(ktxTexture(This), level,
|
||||
KTX_FORMAT_VERSION_TWO);
|
||||
#if defined(DEBUG)
|
||||
result = dststr->getpos(dststr, (ktx_off_t*)&pos);
|
||||
// Could fail if stdout is a pipe
|
||||
if (result == KTX_SUCCESS)
|
||||
assert(pos == levelIndex[level].byteOffset);
|
||||
else
|
||||
assert(result == KTX_FILE_ISPIPE);
|
||||
#endif
|
||||
|
||||
levelDepth = MAX(1, This->baseDepth >> level);
|
||||
if (This->isCubemap && !This->isArray)
|
||||
numImages = This->numFaces;
|
||||
else
|
||||
numImages = This->isCubemap ? This->numFaces : levelDepth;
|
||||
|
||||
ktx_uint32_t numRows = 0, rowBytes = 0, rowPadding = 0;
|
||||
if (!This->isCompressed) {
|
||||
ktxTexture_rowInfo(ktxTexture(This), level, &numRows, &rowBytes,
|
||||
&rowPadding);
|
||||
}
|
||||
srcLevelOffset = (ktx_uint32_t)ktxTexture_calcLevelOffset(
|
||||
ktxTexture(This),
|
||||
level);
|
||||
srcOffset = srcLevelOffset;
|
||||
for (layer = 0; layer < This->numLayers; layer++) {
|
||||
ktx_uint32_t faceSlice;
|
||||
|
||||
for (faceSlice = 0; faceSlice < numImages; faceSlice++) {
|
||||
#if DUMP_IMAGE
|
||||
dststr->getsize(dststr, &pos);
|
||||
fprintf(stdout, "Writing level %d, layer %d, faceSlice %d to offset %#zx\n",
|
||||
level, layer, faceSlice, pos);
|
||||
#endif
|
||||
if (rowPadding == 0) {
|
||||
#if DUMP_IMAGE
|
||||
if (!This->isCompressed)
|
||||
for (uint32_t y = 0; y < (This->baseHeight >> level); y++) {
|
||||
for (uint32_t x = 0; x < rowBytes; x++) {
|
||||
fprintf(stdout, "%#x, ",
|
||||
*(This->pData + srcOffset + y * rowBytes + x));
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
#endif
|
||||
// Write entire image.
|
||||
result = dststr->write(dststr, This->pData + srcOffset,
|
||||
imageSize, 1);
|
||||
dstLevelSize += imageSize;
|
||||
} else {
|
||||
/* Copy the rows individually, removing padding. */
|
||||
ktx_uint32_t row;
|
||||
ktx_uint8_t* src = This->pData + srcOffset;
|
||||
ktx_uint32_t packedRowBytes = rowBytes - rowPadding;
|
||||
for (row = 0; row < numRows; row++) {
|
||||
ktx_uint32_t rowOffset = rowBytes * row;
|
||||
#if DUMP_IMAGE
|
||||
for (uint32_t i = 0; i < packedRowBytes; i++)
|
||||
fprintf(stdout, "%#x, ", *(src + rowOffset + i));
|
||||
#endif
|
||||
result = dststr->write(dststr, src + rowOffset,
|
||||
packedRowBytes, 1);
|
||||
dstLevelSize += packedRowBytes;
|
||||
}
|
||||
}
|
||||
#if DUMP_IMAGE
|
||||
fprintf(stdout, "\n");
|
||||
#endif
|
||||
srcOffset += (ktx_uint32_t)imageSize;
|
||||
}
|
||||
}
|
||||
if (result == KTX_SUCCESS && level != 0) {
|
||||
uint32_t levelPadLen = _KTX_PADN_LEN(requiredLevelAlignment,
|
||||
dstLevelSize);
|
||||
if (levelPadLen)
|
||||
result = dststr->write(dststr, padding, 1, levelPadLen);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(dfd);
|
||||
free(levelIndex);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a stdio stream in KTX2 format.
|
||||
*
|
||||
* Callers are strongly urged to include a KTXwriter item in the texture's metadata.
|
||||
* It can be added by code, similar to the following, prior to calling this
|
||||
* function.
|
||||
* @code
|
||||
* char writer[100];
|
||||
* snprintf(writer, sizeof(writer), "%s version %s", appName, appVer);
|
||||
* ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
||||
* (ktx_uint32_t)strlen(writer) + 1,
|
||||
* writer);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dstsstr destination stdio stream.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dstsstr is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture contains unknownY KTX- or ktx-
|
||||
* prefixed metadata keys.
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteKTX2ToStdioStream(ktxTexture1* This, FILE* dstsstr)
|
||||
{
|
||||
ktxStream stream;
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
|
||||
if (!This)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
result = ktxFileStream_construct(&stream, dstsstr, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
return ktxTexture1_WriteKTX2ToStream(This, &stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a named file in KTX2 format.
|
||||
*
|
||||
* The file name must be encoded in utf-8. On Windows convert unicode names
|
||||
* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.
|
||||
*
|
||||
* Callers are strongly urged to include a KTXwriter item in the texture's
|
||||
* metadata. It can be added by code, similar to the following, prior to
|
||||
* calling this function.
|
||||
* @code
|
||||
* char writer[100];
|
||||
* snprintf(writer, sizeof(writer), "%s version %s", appName, appVer);
|
||||
* ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
||||
* (ktx_uint32_t)strlen(writer) + 1,
|
||||
* writer);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dstname destination file name.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dstname is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture contains unknownY KTX- or ktx-
|
||||
* prefixed metadata keys.
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteKTX2ToNamedFile(ktxTexture1* This, const char* const dstname)
|
||||
{
|
||||
KTX_error_code result;
|
||||
FILE* dst;
|
||||
|
||||
if (!This)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
dst = ktxFOpenUTF8(dstname, "wb");
|
||||
if (dst) {
|
||||
result = ktxTexture1_WriteKTX2ToStdioStream(This, dst);
|
||||
fclose(dst);
|
||||
} else
|
||||
result = KTX_FILE_OPEN_FAILED;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture1
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to block of memory in KTX2 format.
|
||||
*
|
||||
* Memory is allocated by the function and the caller is responsible for
|
||||
* freeing it.
|
||||
*
|
||||
* Callers are strongly urged to include a KTXwriter item in the texture's metadata.
|
||||
* It can be added by code, similar to the following, prior to calling this
|
||||
* function.
|
||||
* @code
|
||||
* char writer[100];
|
||||
* snprintf(writer, sizeof(writer), "%s version %s", appName, appVer);
|
||||
* ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
||||
* (ktx_uint32_t)strlen(writer) + 1,
|
||||
* writer);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in,out] ppDstBytes pointer to location to write the address of
|
||||
* the destination memory. The Application is
|
||||
* responsible for freeing this memory.
|
||||
* @param[in,out] pSize pointer to location to write the size in bytes of
|
||||
* the KTX data.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This, @p ppDstBytes or @p pSize is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture contains unknownY KTX- or ktx-
|
||||
* prefixed metadata keys.
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture1_WriteKTX2ToMemory(ktxTexture1* This,
|
||||
ktx_uint8_t** ppDstBytes, ktx_size_t* pSize)
|
||||
{
|
||||
struct ktxStream dststr;
|
||||
KTX_error_code result;
|
||||
ktx_size_t strSize;
|
||||
|
||||
if (!This || !ppDstBytes || !pSize)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
*ppDstBytes = NULL;
|
||||
|
||||
result = ktxMemStream_construct(&dststr, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
result = ktxTexture1_WriteKTX2ToStream(This, &dststr);
|
||||
if(result != KTX_SUCCESS)
|
||||
{
|
||||
ktxMemStream_destruct(&dststr);
|
||||
return result;
|
||||
}
|
||||
|
||||
ktxMemStream_getdata(&dststr, ppDstBytes);
|
||||
dststr.getsize(&dststr, &strSize);
|
||||
*pSize = (GLsizei)strSize;
|
||||
/* This function does not free the memory pointed at by the
|
||||
* value obtained from ktxMemStream_getdata() thanks to the
|
||||
* KTX_FALSE passed to the constructor above.
|
||||
*/
|
||||
ktxMemStream_destruct(&dststr);
|
||||
return KTX_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,990 @@
|
||||
/* -*- tab-width: 4; -*- */
|
||||
/* vi: set sw=2 ts=4 expandtab: */
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @file
|
||||
* @~English
|
||||
*
|
||||
* @brief Functions for creating KTX-format files from a set of images.
|
||||
*
|
||||
* @author Mark Callow, HI Corporation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2018-2020 Mark Callow.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(__GNUC__)
|
||||
#include <strings.h> // For strncasecmp on GNU/Linux
|
||||
#endif
|
||||
#include <zstd.h>
|
||||
#include <zstd_errors.h>
|
||||
#include <KHR/khr_df.h>
|
||||
|
||||
#include "ktx.h"
|
||||
#include "ktxint.h"
|
||||
#include "filestream.h"
|
||||
#include "memstream.h"
|
||||
#include "texture2.h"
|
||||
|
||||
#include "dfdutils/dfd.h"
|
||||
#include "vkformat_enum.h"
|
||||
#include "vk_format.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup writer Writer
|
||||
* @brief Write KTX-formatted data.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) || defined(linux) || defined(__linux) || defined(__linux__) || defined(__EMSCRIPTEN__)
|
||||
/** @internal
|
||||
* @~English
|
||||
* @brief strnstr for Windows, Linux and Emscripten.
|
||||
*
|
||||
* strnstr is available in <apple>OS and BSD distributions. To use in Linux
|
||||
* requires linking an additional library, libbsd. It is simpler to use ours.
|
||||
*
|
||||
* @param[in] haystack pointer to string to search.
|
||||
* @param[in] needle pointer to string to search for.
|
||||
* @param[in] len length of @p haystack string. Also used as limit to
|
||||
* length of @p needle string.
|
||||
*
|
||||
* @return @p haystack, if @p needle is an empty string otherwise NULL, if
|
||||
* @p needle does not occur in @p haystack, or a pointer to the
|
||||
* first character of the first occurrence of @p needle.
|
||||
*/
|
||||
static char*
|
||||
strnstr(const char *haystack, const char *needle, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
size_t needleLen;
|
||||
const char* needleEnd;
|
||||
|
||||
// strnlen is not part of the C standard and does not compile on some platforms,
|
||||
// use case is covered by memchr.
|
||||
needleEnd = (char *)memchr(needle, 0, len);
|
||||
if (needleEnd == needle)
|
||||
return (char *)haystack;
|
||||
|
||||
needleLen = len;
|
||||
if (needleEnd != NULL)
|
||||
needleLen = needleEnd - needle;
|
||||
|
||||
for (i = 0; i <= len - needleLen; i++)
|
||||
{
|
||||
if (haystack[0] == needle[0]
|
||||
&& strncmp(haystack, needle, needleLen) == 0)
|
||||
return (char *)haystack;
|
||||
haystack++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @internal
|
||||
* @~English
|
||||
* @brief Append the library's id to the KTXwriter value.
|
||||
*
|
||||
* @param[in] head pointer to the head of the hash list.
|
||||
* @param[in] writerEntry pointer to an existing KTXwriter entry.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_OUT_OF_MEMORY not enough memory for temporary strings.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* the length of the value of writerEntry and the
|
||||
* lib id being added is greater than the
|
||||
* maximum allowed.
|
||||
*/
|
||||
KTX_error_code
|
||||
appendLibId(ktxHashList* head, ktxHashListEntry* writerEntry)
|
||||
{
|
||||
KTX_error_code result;
|
||||
const char* id;
|
||||
const char* libVer;
|
||||
const char libIdIntro[] = " / libktx ";
|
||||
size_t idLen, libIdLen;
|
||||
|
||||
if (writerEntry) {
|
||||
ktx_uint32_t len;
|
||||
result = ktxHashListEntry_GetValue(writerEntry, &len, (void**)&id);
|
||||
idLen = len;
|
||||
} else {
|
||||
id = "Unidentified app";
|
||||
idLen = 17;
|
||||
}
|
||||
|
||||
// strnstr needed because KTXwriter values may not be NUL terminated.
|
||||
#if defined(EMPTY_LIBVER_WITH_UNIDENTIFIED_APP)
|
||||
// May be needed for patching some CTS files without changing their KTXwriter
|
||||
// metadata. Keep in case useful again.
|
||||
if (strnstr(id, "Unidentified app", idLen) != NULL) {
|
||||
libVer = "";
|
||||
} else
|
||||
#endif
|
||||
if (strnstr(id, "__default__", idLen) != NULL) {
|
||||
libVer = STR(LIBKTX_DEFAULT_VERSION);
|
||||
} else {
|
||||
libVer = STR(LIBKTX_VERSION);
|
||||
}
|
||||
// sizeof(libIdIntro) includes space for its terminating NUL which we will
|
||||
// overwrite so no need for +1 after strlen.
|
||||
libIdLen = sizeof(libIdIntro) + (ktx_uint32_t)strlen(libVer);
|
||||
char* libId = malloc(libIdLen);
|
||||
if (!libId)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
strncpy(libId, libIdIntro, libIdLen);
|
||||
strncpy(&libId[sizeof(libIdIntro)-1], libVer,
|
||||
libIdLen-(sizeof(libIdIntro)-1));
|
||||
|
||||
char* fullId = NULL;
|
||||
if (strnstr(id, libId, idLen) != NULL) {
|
||||
// This lib id is already in the writer value.
|
||||
result = KTX_SUCCESS;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
const char* libVerPos = strnstr(id, libIdIntro, idLen);
|
||||
if (libVerPos != NULL) {
|
||||
// There is a libktx version but not the current version.
|
||||
idLen = libVerPos - id;
|
||||
} else if (id[idLen-1] == '\0') {
|
||||
idLen--;
|
||||
}
|
||||
|
||||
size_t fullIdLen = idLen + strlen(libId) + 1;
|
||||
if (fullIdLen > UINT_MAX) {
|
||||
result = KTX_INVALID_OPERATION;
|
||||
goto cleanup;
|
||||
}
|
||||
fullId = malloc(fullIdLen);
|
||||
if (!fullId) {
|
||||
result = KTX_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
strncpy(fullId, id, idLen);
|
||||
strncpy(&fullId[idLen], libId, libIdLen);
|
||||
assert(fullId[fullIdLen-1] == '\0');
|
||||
|
||||
ktxHashList_DeleteEntry(head, writerEntry);
|
||||
result = ktxHashList_AddKVPair(head, KTX_WRITER_KEY,
|
||||
(ktx_uint32_t)fullIdLen, fullId);
|
||||
cleanup:
|
||||
free(libId);
|
||||
free(fullId);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2 @private
|
||||
* @~English
|
||||
* @brief Set image for level, layer, faceSlice from a ktxStream source.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] level mip level of the image to set.
|
||||
* @param[in] layer array layer of the image to set.
|
||||
* @param[in] faceSlice cube map face or depth slice of the image to set or
|
||||
* KTX_FACESLICE_WHOLE_LEVEL to set the entire level.
|
||||
* @param[in] src ktxStream pointer to the source.
|
||||
* @param[in] srcSize size of the source image in bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p src is NULL.
|
||||
* @exception KTX_INVALID_VALUE @p srcSize != the expected image size for the
|
||||
* specified level, layer & faceSlice.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* No storage was allocated when the texture was
|
||||
* created.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_setImageFromStream(ktxTexture2* This, ktx_uint32_t level,
|
||||
ktx_uint32_t layer, ktx_uint32_t faceSlice,
|
||||
ktxStream* src, ktx_size_t srcSize)
|
||||
{
|
||||
ktx_size_t imageByteLength;
|
||||
ktx_size_t imageByteOffset;
|
||||
ktx_error_code_e result;
|
||||
|
||||
if (!This || !src)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
if (!This->pData)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
if (faceSlice == KTX_FACESLICE_WHOLE_LEVEL) {
|
||||
result = ktxTexture_GetImageOffset(ktxTexture(This), level, layer, 0, &imageByteOffset);
|
||||
if (result != KTX_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
imageByteLength = ktxTexture_calcLevelSize(ktxTexture(This), level, KTX_FORMAT_VERSION_TWO);
|
||||
} else {
|
||||
result = ktxTexture_GetImageOffset(ktxTexture(This), level, layer, faceSlice, &imageByteOffset);
|
||||
if (result != KTX_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
imageByteLength = ktxTexture_GetImageSize(ktxTexture(This), level);
|
||||
}
|
||||
|
||||
if (srcSize != imageByteLength)
|
||||
return KTX_INVALID_OPERATION;
|
||||
// The above will catch a flagrantly invalid srcSize. This is an
|
||||
// additional check of the internal calculations.
|
||||
assert (imageByteOffset + srcSize <= This->dataSize);
|
||||
|
||||
/* Can copy whole image at once */
|
||||
src->read(src, This->pData + imageByteOffset, srcSize);
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Set image for level, layer, faceSlice from a stdio stream source.
|
||||
*
|
||||
* Uncompressed images read from the stream are expected to have their rows
|
||||
* tightly packed as is the norm for most image file formats. KTX 2 also requires
|
||||
* tight packing this function does not add any padding.
|
||||
*
|
||||
* Level, layer, faceSlice rather than offset are specified to enable some
|
||||
* validation.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] level mip level of the image to set.
|
||||
* @param[in] layer array layer of the image to set.
|
||||
* @param[in] faceSlice cube map face or depth slice of the image to set or
|
||||
* KTX_FACESLICE_WHOLE_LEVEL to set the entire level.
|
||||
* @param[in] src stdio stream pointer to the source.
|
||||
* @param[in] srcSize size of the source image in bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p src is NULL.
|
||||
* @exception KTX_INVALID_VALUE @p srcSize != the expected image size for the
|
||||
* specified level, layer & faceSlice.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* No storage was allocated when the texture was
|
||||
* created.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_SetImageFromStdioStream(ktxTexture2* This, ktx_uint32_t level,
|
||||
ktx_uint32_t layer, ktx_uint32_t faceSlice,
|
||||
FILE* src, ktx_size_t srcSize)
|
||||
{
|
||||
ktxStream srcstr;
|
||||
KTX_error_code result;
|
||||
|
||||
result = ktxFileStream_construct(&srcstr, src, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
result = ktxTexture2_setImageFromStream(This, level, layer, faceSlice,
|
||||
&srcstr, srcSize);
|
||||
ktxFileStream_destruct(&srcstr);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Set image for level, layer, faceSlice from an image in memory.
|
||||
*
|
||||
* Uncompressed images in memory are expected to have their rows tightly packed
|
||||
* as is the norm for most image file formats. KTX 2 also requires
|
||||
* tight packing this function does not add any padding.
|
||||
*
|
||||
* Level, layer, faceSlice rather than offset are specified to enable some
|
||||
* validation.
|
||||
*
|
||||
* @note The caller is responsible for freeing the original image memory
|
||||
* referred to by @p src.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] level mip level of the image to set.
|
||||
* @param[in] layer array layer of the image to set.
|
||||
* @param[in] faceSlice cube map face or depth slice of the image to set or
|
||||
* KTX_FACESLICE_WHOLE_LEVEL to set the entire level.
|
||||
* @param[in] src pointer to the image source in memory.
|
||||
* @param[in] srcSize size of the source image in bytes.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p src is NULL.
|
||||
* @exception KTX_INVALID_VALUE @p srcSize != the expected image size for the
|
||||
* specified level, layer & faceSlice.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* No storage was allocated when the texture was
|
||||
* created.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_SetImageFromMemory(ktxTexture2* This, ktx_uint32_t level,
|
||||
ktx_uint32_t layer, ktx_uint32_t faceSlice,
|
||||
const ktx_uint8_t* src, ktx_size_t srcSize)
|
||||
{
|
||||
ktxStream srcstr;
|
||||
KTX_error_code result;
|
||||
|
||||
result = ktxMemStream_construct_ro(&srcstr, src, srcSize);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
result = ktxTexture2_setImageFromStream(This, level, layer, faceSlice,
|
||||
&srcstr, srcSize);
|
||||
ktxMemStream_destruct(&srcstr);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(TestNoMetadata)
|
||||
// Only so texturetests can test loading of files without any metadata.
|
||||
ktx_bool_t __disableWriterMetadata__ = KTX_FALSE;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a ktxStream in KTX format.
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dststr destination ktxStream.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dststr is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The length of the already set writerId metadata
|
||||
* plus the library's version id exceeds the
|
||||
* maximum allowed.
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_WriteToStream(ktxTexture2* This, ktxStream* dststr)
|
||||
{
|
||||
DECLARE_PRIVATE(ktxTexture2);
|
||||
KTX_header2 header = { .identifier = KTX2_IDENTIFIER_REF };
|
||||
KTX_error_code result;
|
||||
ktx_uint32_t kvdLen;
|
||||
ktx_uint8_t* pKvd;
|
||||
ktx_uint32_t align8PadLen = 0;
|
||||
ktx_uint64_t sgdLen;
|
||||
ktx_uint32_t initialLevelPadLen;
|
||||
ktx_uint32_t levelIndexSize;
|
||||
ktx_uint64_t baseOffset;
|
||||
|
||||
if (!dststr) {
|
||||
return KTX_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (This->pData == NULL)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
header.vkFormat = This->vkFormat;
|
||||
header.typeSize = This->_protected->_typeSize;
|
||||
header.pixelWidth = This->baseWidth;
|
||||
header.pixelHeight = This->numDimensions > 1 ? This->baseHeight : 0;
|
||||
header.pixelDepth = This->numDimensions > 2 ? This->baseDepth : 0;
|
||||
header.layerCount = This->isArray ? This->numLayers : 0;
|
||||
assert (This->isCubemap ? This->numFaces == 6 : This->numFaces == 1);
|
||||
header.faceCount = This->numFaces;
|
||||
assert (This->generateMipmaps? This->numLevels == 1 : This->numLevels >= 1);
|
||||
header.levelCount = This->generateMipmaps ? 0 : This->numLevels;
|
||||
header.supercompressionScheme = This->supercompressionScheme;
|
||||
|
||||
levelIndexSize = sizeof(ktxLevelIndexEntry) * This->numLevels;
|
||||
|
||||
baseOffset = sizeof(header) + levelIndexSize;
|
||||
|
||||
header.dataFormatDescriptor.byteOffset = (uint32_t)baseOffset;
|
||||
header.dataFormatDescriptor.byteLength = *This->pDfd;
|
||||
baseOffset += header.dataFormatDescriptor.byteLength;
|
||||
|
||||
ktxHashListEntry* pEntry;
|
||||
// Check for invalid metadata.
|
||||
for (pEntry = This->kvDataHead; pEntry != NULL; pEntry = ktxHashList_Next(pEntry)) {
|
||||
unsigned int keyLen;
|
||||
char* key;
|
||||
|
||||
ktxHashListEntry_GetKey(pEntry, &keyLen, &key);
|
||||
if (strncasecmp(key, "KTX", 3) == 0) {
|
||||
ktx_uint32_t i;
|
||||
const char* knownKeys[] = {
|
||||
"KTXcubemapIncomplete",
|
||||
"KTXorientation",
|
||||
"KTXglFormat",
|
||||
"KTXdxgiFormat__",
|
||||
"KTXmetalPixelFormat",
|
||||
"KTXswizzle",
|
||||
"KTXwriter",
|
||||
"KTXwriterScParams",
|
||||
"KTXastcDecodeMode",
|
||||
"KTXanimData"
|
||||
};
|
||||
if (strncmp(key, "ktx", 3) == 0)
|
||||
return KTX_INVALID_OPERATION;
|
||||
// Check for unrecognized KTX keys.
|
||||
for (i = 0; i < sizeof(knownKeys)/sizeof(char*); i++) {
|
||||
if (strcmp(key, knownKeys[i]) == 0)
|
||||
break;
|
||||
}
|
||||
if (i == sizeof(knownKeys)/sizeof(char*))
|
||||
return KTX_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(TestNoMetadata)
|
||||
if (!__disableWriterMetadata__) {
|
||||
#endif
|
||||
pEntry = NULL;
|
||||
result = ktxHashList_FindEntry(&This->kvDataHead, KTX_WRITER_KEY,
|
||||
&pEntry);
|
||||
result = appendLibId(&This->kvDataHead, pEntry);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
#if defined(TestNoMetadata)
|
||||
}
|
||||
#endif
|
||||
|
||||
ktxHashList_Sort(&This->kvDataHead); // KTX2 requires sorted metadata.
|
||||
ktxHashList_Serialize(&This->kvDataHead, &kvdLen, &pKvd);
|
||||
header.keyValueData.byteOffset = kvdLen != 0 ? (uint32_t)baseOffset : 0;
|
||||
header.keyValueData.byteLength = kvdLen;
|
||||
baseOffset += kvdLen;
|
||||
|
||||
sgdLen = private->_sgdByteLength;
|
||||
if (sgdLen) {
|
||||
align8PadLen = _KTX_PAD8_LEN(baseOffset);
|
||||
baseOffset += align8PadLen;
|
||||
}
|
||||
|
||||
header.supercompressionGlobalData.byteOffset = sgdLen != 0 ? baseOffset : 0;
|
||||
header.supercompressionGlobalData.byteLength = sgdLen;
|
||||
baseOffset += sgdLen;
|
||||
|
||||
initialLevelPadLen = _KTX_PADN_LEN(This->_private->_requiredLevelAlignment,
|
||||
baseOffset);
|
||||
baseOffset += initialLevelPadLen;
|
||||
|
||||
// write header and indices
|
||||
result = dststr->write(dststr, &header, sizeof(header), 1);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
// Create a copy of the level index with file-adjusted offsets and write it.
|
||||
ktxLevelIndexEntry* levelIndex
|
||||
= (ktxLevelIndexEntry*)malloc(levelIndexSize);
|
||||
if (!levelIndex)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
for (ktx_uint32_t level = 0; level < This->numLevels; level++) {
|
||||
levelIndex[level].byteLength = private->_levelIndex[level].byteLength;
|
||||
levelIndex[level].uncompressedByteLength
|
||||
= private->_levelIndex[level].uncompressedByteLength;
|
||||
levelIndex[level].byteOffset = private->_levelIndex[level].byteOffset;
|
||||
levelIndex[level].byteOffset += baseOffset;
|
||||
}
|
||||
result = dststr->write(dststr, levelIndex, levelIndexSize, 1);
|
||||
free(levelIndex);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
// write data format descriptor
|
||||
result = dststr->write(dststr, This->pDfd, 1, *This->pDfd);
|
||||
|
||||
// write keyValueData
|
||||
if (kvdLen != 0) {
|
||||
assert(pKvd != NULL);
|
||||
|
||||
result = dststr->write(dststr, pKvd, 1, kvdLen);
|
||||
free(pKvd);
|
||||
if (result != KTX_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
char padding[32] = { 0 };
|
||||
// write supercompressionGlobalData & sgdPadding
|
||||
if (private->_sgdByteLength != 0) {
|
||||
if (align8PadLen) {
|
||||
result = dststr->write(dststr, padding, 1, align8PadLen);
|
||||
if (result != KTX_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result = dststr->write(dststr, private->_supercompressionGlobalData,
|
||||
1, private->_sgdByteLength);
|
||||
if (result != KTX_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (initialLevelPadLen) {
|
||||
result = dststr->write(dststr, padding, 1, initialLevelPadLen);
|
||||
if (result != KTX_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// write the image data
|
||||
for (ktx_int32_t level = This->numLevels-1; level >= 0 && result == KTX_SUCCESS; --level)
|
||||
{
|
||||
ktx_uint64_t srcLevelOffset, levelSize;
|
||||
#define DUMP_IMAGE 0
|
||||
#if defined(DEBUG) || DUMP_IMAGE
|
||||
ktx_size_t pos;
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
result = dststr->getpos(dststr, (ktx_off_t*)&pos);
|
||||
// Could fail if stdout is a pipe
|
||||
if (result == KTX_SUCCESS)
|
||||
assert(pos == private->_levelIndex[level].byteOffset + baseOffset);
|
||||
else
|
||||
assert(result == KTX_FILE_ISPIPE);
|
||||
#endif
|
||||
|
||||
srcLevelOffset = ktxTexture2_levelDataOffset(This, level);
|
||||
levelSize = private->_levelIndex[level].byteLength;
|
||||
|
||||
#if DUMP_IMAGE
|
||||
if (!This->isCompressed) {
|
||||
for (layer = 0; layer < This->numLayers; layer++) {
|
||||
ktx_uint32_t faceSlice;
|
||||
for (faceSlice = 0; faceSlice < numImages; faceSlice++) {
|
||||
dststr->getsize(dststr, &pos);
|
||||
fprintf(stdout, "Writing level %d, layer %d, faceSlice %d to baseOffset %#zx\n",
|
||||
level, layer, faceSlice, pos);
|
||||
for (uint32_t y = 0; y < (This->baseHeight >> level); y++) {
|
||||
for (uint32_t x = 0; x < rowBytes; x++) {
|
||||
fprintf(stdout, "%#x, ",
|
||||
*(This->pData + srcOffset + y * rowBytes + x));
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
#endif
|
||||
// Write entire level.
|
||||
result = dststr->write(dststr, This->pData + srcLevelOffset,
|
||||
levelSize, 1);
|
||||
if (result == KTX_SUCCESS && level > 0) { // No padding at end.
|
||||
ktx_uint32_t levelPadLen
|
||||
= _KTX_PADN_LEN(This->_private->_requiredLevelAlignment,
|
||||
levelSize);
|
||||
if (levelPadLen != 0)
|
||||
result = dststr->write(dststr, padding, 1, levelPadLen);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a stdio stream in KTX format.
|
||||
*
|
||||
* Callers are strongly urged to include a KTXwriter item in the texture's
|
||||
* metadata. It can be added by code, similar to the following, prior to
|
||||
* calling this function.
|
||||
* @code
|
||||
* char writer[100];
|
||||
* snprintf(writer, sizeof(writer), "%s version %s", appName, appVer);
|
||||
* ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
||||
* (ktx_uint32_t)strlen(writer) + 1,
|
||||
* writer);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dstsstr destination stdio stream.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dstsstr is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_WriteToStdioStream(ktxTexture2* This, FILE* dstsstr)
|
||||
{
|
||||
ktxStream stream;
|
||||
KTX_error_code result = KTX_SUCCESS;
|
||||
|
||||
if (!This)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
result = ktxFileStream_construct(&stream, dstsstr, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
return ktxTexture2_WriteToStream(This, &stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to a named file in KTX format.
|
||||
*
|
||||
* The file name must be encoded in utf-8. On Windows convert unicode names
|
||||
* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.
|
||||
*
|
||||
* Callers are strongly urged to include a KTXwriter item in the texture's
|
||||
* metadata. It can be added by code, similar to the following, prior to
|
||||
* calling this function.
|
||||
* @code
|
||||
* char writer[100];
|
||||
* snprintf(writer, sizeof(writer), "%s version %s", appName, appVer);
|
||||
* ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
||||
* (ktx_uint32_t)strlen(writer) + 1,
|
||||
* writer);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in] dstname destination file name.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This or @p dstname is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_WriteToNamedFile(ktxTexture2* This, const char* const dstname)
|
||||
{
|
||||
KTX_error_code result;
|
||||
FILE* dst;
|
||||
|
||||
if (!This)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
dst = ktxFOpenUTF8(dstname, "wb");
|
||||
if (dst) {
|
||||
result = ktxTexture2_WriteToStdioStream(This, dst);
|
||||
fclose(dst);
|
||||
} else
|
||||
result = KTX_FILE_OPEN_FAILED;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Write a ktxTexture object to block of memory in KTX format.
|
||||
*
|
||||
* Memory is allocated by the function and the caller is responsible for
|
||||
* freeing it.
|
||||
*
|
||||
* Callers are strongly urged to include a KTXwriter item in the texture's
|
||||
* metadata. It can be added by code, similar to the following, prior to
|
||||
* calling this function.
|
||||
* @code
|
||||
* char writer[100];
|
||||
* snprintf(writer, sizeof(writer), "%s version %s", appName, appVer);
|
||||
* ktxHashList_AddKVPair(&texture->kvDataHead, KTX_WRITER_KEY,
|
||||
* (ktx_uint32_t)strlen(writer) + 1,
|
||||
* writer);
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] This pointer to the target ktxTexture object.
|
||||
* @param[in,out] ppDstBytes pointer to location to write the address of
|
||||
* the destination memory. The Application is
|
||||
* responsible for freeing this memory.
|
||||
* @param[in,out] pSize pointer to location to write the size in bytes of
|
||||
* the KTX data.
|
||||
*
|
||||
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
|
||||
*
|
||||
* @exception KTX_INVALID_VALUE @p This, @p ppDstBytes or @p pSize is NULL.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* The ktxTexture does not contain any image data.
|
||||
* @exception KTX_INVALID_OPERATION
|
||||
* Both kvDataHead and kvData are set in the
|
||||
* ktxTexture
|
||||
* @exception KTX_FILE_OVERFLOW The file exceeded the maximum size supported by
|
||||
* the system.
|
||||
* @exception KTX_FILE_WRITE_ERROR
|
||||
* An error occurred while writing the file.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_WriteToMemory(ktxTexture2* This,
|
||||
ktx_uint8_t** ppDstBytes, ktx_size_t* pSize)
|
||||
{
|
||||
struct ktxStream dststr;
|
||||
KTX_error_code result;
|
||||
ktx_size_t strSize;
|
||||
|
||||
if (!This || !ppDstBytes || !pSize)
|
||||
return KTX_INVALID_VALUE;
|
||||
|
||||
*ppDstBytes = NULL;
|
||||
|
||||
result = ktxMemStream_construct(&dststr, KTX_FALSE);
|
||||
if (result != KTX_SUCCESS)
|
||||
return result;
|
||||
|
||||
result = ktxTexture2_WriteToStream(This, &dststr);
|
||||
if(result != KTX_SUCCESS)
|
||||
{
|
||||
ktxMemStream_destruct(&dststr);
|
||||
return result;
|
||||
}
|
||||
|
||||
ktxMemStream_getdata(&dststr, ppDstBytes);
|
||||
dststr.getsize(&dststr, &strSize);
|
||||
*pSize = (GLsizei)strSize;
|
||||
/* This function does not free the memory pointed at by the
|
||||
* value obtained from ktxMemStream_getdata() thanks to the
|
||||
* KTX_FALSE passed to the constructor above.
|
||||
*/
|
||||
ktxMemStream_destruct(&dststr);
|
||||
return KTX_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Deflate the data in a ktxTexture2 object using Zstandard.
|
||||
*
|
||||
* The texture's levelIndex, dataSize, DFD, data pointer, and supercompressionScheme will
|
||||
* all be updated after successful deflation to reflect the deflated data.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture2 object of interest.
|
||||
* @param[in] compressionLevel set speed vs compression ratio trade-off. Values
|
||||
* between 1 and 22 are accepted. The lower the level the faster. Values
|
||||
* above 20 should be used with caution as they require more memory.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_DeflateZstd(ktxTexture2* This, ktx_uint32_t compressionLevel)
|
||||
{
|
||||
ktx_uint32_t levelIndexByteLength =
|
||||
This->numLevels * sizeof(ktxLevelIndexEntry);
|
||||
ktx_uint8_t* workBuf;
|
||||
ktx_uint8_t* cmpData;
|
||||
ktx_size_t dstRemainingByteLength = 0;
|
||||
ktx_size_t byteLengthCmp = 0;
|
||||
ktx_size_t levelOffset = 0;
|
||||
ktxLevelIndexEntry* cindex = This->_private->_levelIndex;
|
||||
ktxLevelIndexEntry* nindex;
|
||||
ktx_uint8_t* pCmpDst;
|
||||
ktx_error_code_e result;
|
||||
|
||||
ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||
if (cctx == NULL)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
|
||||
if (This->supercompressionScheme != KTX_SS_NONE)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
// On rare occasions the deflated data can be a few bytes larger than
|
||||
// the source data. Calculating the dst buffer size using
|
||||
// ZSTD_compressBound provides a suitable size plus compression is said
|
||||
// to run faster when the dst buffer is >= compressBound.
|
||||
for (int32_t level = This->numLevels - 1; level >= 0; level--) {
|
||||
dstRemainingByteLength += ZSTD_compressBound(cindex[level].byteLength);
|
||||
}
|
||||
|
||||
workBuf = malloc(dstRemainingByteLength + levelIndexByteLength);
|
||||
if (workBuf == NULL) {
|
||||
result = KTX_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
nindex = (ktxLevelIndexEntry*)workBuf;
|
||||
pCmpDst = &workBuf[levelIndexByteLength];
|
||||
|
||||
for (int32_t level = This->numLevels - 1; level >= 0; level--) {
|
||||
size_t levelByteLengthCmp =
|
||||
ZSTD_compressCCtx(cctx, pCmpDst + levelOffset,
|
||||
dstRemainingByteLength,
|
||||
&This->pData[cindex[level].byteOffset],
|
||||
cindex[level].byteLength,
|
||||
compressionLevel);
|
||||
if (ZSTD_isError(levelByteLengthCmp)) {
|
||||
free(workBuf);
|
||||
ZSTD_ErrorCode error = ZSTD_getErrorCode(levelByteLengthCmp);
|
||||
switch(error) {
|
||||
case ZSTD_error_parameter_outOfBound:
|
||||
result = KTX_INVALID_VALUE;
|
||||
goto cleanup;
|
||||
case ZSTD_error_dstSize_tooSmall:
|
||||
#ifdef DEBUG
|
||||
assert(false && "Deflate dstSize too small.");
|
||||
#else
|
||||
result = KTX_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
#endif
|
||||
case ZSTD_error_workSpace_tooSmall:
|
||||
#ifdef DEBUG
|
||||
assert(false && "Deflate workspace too small.");
|
||||
#else
|
||||
result = KTX_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
#endif
|
||||
case ZSTD_error_memory_allocation:
|
||||
result = KTX_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
default:
|
||||
// The remaining errors look like they should only
|
||||
// occur during decompression but just in case.
|
||||
#ifdef DEBUG
|
||||
assert(true);
|
||||
#else
|
||||
result = KTX_INVALID_OPERATION;
|
||||
goto cleanup;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
nindex[level].byteOffset = levelOffset;
|
||||
nindex[level].uncompressedByteLength = cindex[level].byteLength;
|
||||
nindex[level].byteLength = levelByteLengthCmp;
|
||||
byteLengthCmp += levelByteLengthCmp;
|
||||
levelOffset += levelByteLengthCmp;
|
||||
dstRemainingByteLength -= levelByteLengthCmp;
|
||||
}
|
||||
ZSTD_freeCCtx(cctx);
|
||||
|
||||
// Move the compressed data into a correctly sized buffer.
|
||||
cmpData = malloc(byteLengthCmp);
|
||||
if (cmpData == NULL) {
|
||||
free(workBuf);
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
}
|
||||
// Now modify the texture.
|
||||
memcpy(cmpData, pCmpDst, byteLengthCmp); // Copy data to sized buffer.
|
||||
memcpy(cindex, nindex, levelIndexByteLength); // Update level index
|
||||
free(workBuf);
|
||||
free(This->pData);
|
||||
This->pData = cmpData;
|
||||
This->dataSize = byteLengthCmp;
|
||||
This->supercompressionScheme = KTX_SS_ZSTD;
|
||||
This->_private->_requiredLevelAlignment = 1;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
ZSTD_freeCCtx(cctx);
|
||||
free(workBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @memberof ktxTexture2
|
||||
* @~English
|
||||
* @brief Deflate the data in a ktxTexture2 object using miniz (ZLIB).
|
||||
*
|
||||
* The texture's levelIndex, dataSize, DFD, data pointer, and supercompressionScheme will
|
||||
* all be updated after successful deflation to reflect the deflated data.
|
||||
*
|
||||
* @param[in] This pointer to the ktxTexture2 object of interest.
|
||||
* @param[in] compressionLevel set speed vs compression ratio trade-off. Values
|
||||
* between 1 and 9 are accepted. The lower the level the faster.
|
||||
*/
|
||||
KTX_error_code
|
||||
ktxTexture2_DeflateZLIB(ktxTexture2* This, ktx_uint32_t compressionLevel)
|
||||
{
|
||||
ktx_uint32_t levelIndexByteLength =
|
||||
This->numLevels * sizeof(ktxLevelIndexEntry);
|
||||
ktx_uint8_t* workBuf;
|
||||
ktx_uint8_t* cmpData;
|
||||
ktx_size_t dstRemainingByteLength = 0;
|
||||
ktx_size_t byteLengthCmp = 0;
|
||||
ktx_size_t levelOffset = 0;
|
||||
ktxLevelIndexEntry* cindex = This->_private->_levelIndex;
|
||||
ktxLevelIndexEntry* nindex;
|
||||
ktx_uint8_t* pCmpDst;
|
||||
|
||||
if (This->supercompressionScheme != KTX_SS_NONE)
|
||||
return KTX_INVALID_OPERATION;
|
||||
|
||||
// On rare occasions the deflated data can be a few bytes larger than
|
||||
// the source data. Calculating the dst buffer size using
|
||||
// mz_deflateBound provides a conservative size to account for that.
|
||||
for (int32_t level = This->numLevels - 1; level >= 0; level--) {
|
||||
dstRemainingByteLength += ktxCompressZLIBBounds(cindex[level].byteLength);
|
||||
}
|
||||
|
||||
workBuf = malloc(dstRemainingByteLength + levelIndexByteLength);
|
||||
if (workBuf == NULL)
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
nindex = (ktxLevelIndexEntry*)workBuf;
|
||||
pCmpDst = &workBuf[levelIndexByteLength];
|
||||
|
||||
for (int32_t level = This->numLevels - 1; level >= 0; level--) {
|
||||
size_t levelByteLengthCmp = dstRemainingByteLength;
|
||||
KTX_error_code result = ktxCompressZLIBInt(pCmpDst + levelOffset,
|
||||
&levelByteLengthCmp,
|
||||
&This->pData[cindex[level].byteOffset],
|
||||
cindex[level].byteLength,
|
||||
compressionLevel);
|
||||
if (result != KTX_SUCCESS) {
|
||||
free(workBuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
nindex[level].byteOffset = levelOffset;
|
||||
nindex[level].uncompressedByteLength = cindex[level].byteLength;
|
||||
nindex[level].byteLength = levelByteLengthCmp;
|
||||
byteLengthCmp += levelByteLengthCmp;
|
||||
levelOffset += levelByteLengthCmp;
|
||||
dstRemainingByteLength -= levelByteLengthCmp;
|
||||
}
|
||||
|
||||
// Move the compressed data into a correctly sized buffer.
|
||||
cmpData = malloc(byteLengthCmp);
|
||||
if (cmpData == NULL) {
|
||||
free(workBuf);
|
||||
return KTX_OUT_OF_MEMORY;
|
||||
}
|
||||
// Now modify the texture.
|
||||
memcpy(cmpData, pCmpDst, byteLengthCmp); // Copy data to sized buffer.
|
||||
memcpy(cindex, nindex, levelIndexByteLength); // Update level index
|
||||
free(workBuf);
|
||||
free(This->pData);
|
||||
This->pData = cmpData;
|
||||
This->dataSize = byteLengthCmp;
|
||||
This->supercompressionScheme = KTX_SS_ZLIB;
|
||||
This->_private->_requiredLevelAlignment = 1;
|
||||
|
||||
return KTX_SUCCESS;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
Reference in New Issue
Block a user