blob: bd6e8df810ef455f1b9b832754946b8787d61a5f [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <GLcommon/TextureUtils.h>
#include <GLcommon/GLESmacros.h>
#include <GLcommon/GLDispatch.h>
#include <GLcommon/GLESvalidate.h>
#include <stdio.h>
#include <cmath>
#include <memory>
#include "aemu/base/AlignedBuf.h"
#include "compressedTextureFormats/AstcCpuDecompressor.h"
using android::AlignedBuf;
using gfxstream::vk::AstcCpuDecompressor;
#define GL_R16 0x822A
#define GL_RG16 0x822C
#define GL_R16_SNORM 0x8F98
#define GL_RG16_SNORM 0x8F99
static constexpr size_t kASTCFormatsCount = 28;
#define ASTC_FORMATS_LIST(EXPAND_MACRO) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, 4, 4, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_5x4_KHR, 5, 4, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_5x5_KHR, 5, 5, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_6x5_KHR, 6, 5, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, 6, 6, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x5_KHR, 8, 5, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x6_KHR, 8, 6, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, 8, 8, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x5_KHR, 10, 5, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x6_KHR, 10, 6, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x8_KHR, 10, 8, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, 10, 10, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_12x10_KHR, 12, 10, false) \
EXPAND_MACRO(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, 12, 12, false) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, 4, 4, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, 5, 4, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, 5, 5, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, 6, 5, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, 6, 6, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, 8, 5, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, 8, 6, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, 8, 8, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, 10, 5, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, 10, 6, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, 10, 8, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, 10, 10, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, 12, 10, true) \
EXPAND_MACRO(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, 12, 12, true) \
int getCompressedFormats(int majorVersion, int* formats) {
static constexpr size_t kCount = MAX_SUPPORTED_PALETTE + MAX_ETC_SUPPORTED + kASTCFormatsCount;
int res = kCount;
if (majorVersion > 1) {
res -= MAX_SUPPORTED_PALETTE;
}
if (formats) {
size_t i = 0;
if (1 == majorVersion) {
// Palette
formats[i++] = GL_PALETTE4_RGBA8_OES;
formats[i++] = GL_PALETTE4_RGBA4_OES;
formats[i++] = GL_PALETTE8_RGBA8_OES;
formats[i++] = GL_PALETTE8_RGBA4_OES;
formats[i++] = GL_PALETTE4_RGB8_OES;
formats[i++] = GL_PALETTE8_RGB8_OES;
formats[i++] = GL_PALETTE4_RGB5_A1_OES;
formats[i++] = GL_PALETTE8_RGB5_A1_OES;
formats[i++] = GL_PALETTE4_R5_G6_B5_OES;
formats[i++] = GL_PALETTE8_R5_G6_B5_OES;
}
// ETC
formats[i++] = GL_ETC1_RGB8_OES;
formats[i++] = GL_COMPRESSED_RGB8_ETC2;
formats[i++] = GL_COMPRESSED_SIGNED_R11_EAC;
formats[i++] = GL_COMPRESSED_RG11_EAC;
formats[i++] = GL_COMPRESSED_SIGNED_RG11_EAC;
formats[i++] = GL_COMPRESSED_RGB8_ETC2;
formats[i++] = GL_COMPRESSED_SRGB8_ETC2;
formats[i++] = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
formats[i++] = GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
formats[i++] = GL_COMPRESSED_RGBA8_ETC2_EAC;
formats[i++] = GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
formats[i++] = GL_COMPRESSED_R11_EAC;
// ASTC
#define ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \
formats[i++] = typeName;
ASTC_FORMATS_LIST(ASTC_FORMAT)
#undef ASTC_FORMAT
}
return res;
}
ETC2ImageFormat getEtcFormat(GLenum internalformat) {
ETC2ImageFormat etcFormat = EtcRGB8;
switch (internalformat) {
case GL_COMPRESSED_RGB8_ETC2:
case GL_ETC1_RGB8_OES:
break;
case GL_COMPRESSED_RGBA8_ETC2_EAC:
etcFormat = EtcRGBA8;
break;
case GL_COMPRESSED_SRGB8_ETC2:
break;
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
etcFormat = EtcRGBA8;
break;
case GL_COMPRESSED_R11_EAC:
etcFormat = EtcR11;
break;
case GL_COMPRESSED_SIGNED_R11_EAC:
etcFormat = EtcSignedR11;
break;
case GL_COMPRESSED_RG11_EAC:
etcFormat = EtcRG11;
break;
case GL_COMPRESSED_SIGNED_RG11_EAC:
etcFormat = EtcSignedRG11;
break;
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
etcFormat = EtcRGB8A1;
break;
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
etcFormat = EtcRGB8A1;
break;
}
return etcFormat;
}
void getAstcFormatInfo(GLenum internalformat, uint32_t* width, uint32_t* height, bool* srgb) {
switch (internalformat) {
#define ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \
case typeName: \
*width = blockWidth; *height = blockHeight; *srgb = srgbValue; break; \
ASTC_FORMATS_LIST(ASTC_FORMAT)
#undef ASTC_FORMAT
default:
assert(false && "Invalid ASTC format");
break;
}
}
// Helper function to decompress an ASTC image.
bool astcDecompress(const uint8_t* astcData, size_t astcDataSize, uint32_t width, uint32_t height,
uint32_t blockWidth, uint32_t blockHeight, uint8_t* outBuffer,
size_t outBufferSize) {
if (outBufferSize < width * height * 4) {
WARN("ASTC output buffer too small: %d bytes for %d x %d", outBufferSize, width, height);
return false;
}
int32_t status = AstcCpuDecompressor::get().decompress(width, height, blockWidth, blockHeight,
astcData, astcDataSize, outBuffer);
if (status != 0) {
WARN("astc decompression failed: %s", AstcCpuDecompressor::get().getStatusString(status));
return false;
}
return true;
}
bool isAstcFormat(GLenum internalformat) {
switch (internalformat) {
#define ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \
case typeName:
ASTC_FORMATS_LIST(ASTC_FORMAT)
#undef ASTC_FORMAT
return true;
default:
return false;
}
}
bool isEtcFormat(GLenum internalformat) {
switch (internalformat) {
case GL_ETC1_RGB8_OES:
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return true;
}
return false;
}
bool isEtc2Format(GLenum internalformat) {
switch (internalformat) {
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return true;
}
return false;
}
bool isBptcFormat(GLenum internalformat) {
switch (internalformat) {
case GL_COMPRESSED_RGBA_BPTC_UNORM_EXT:
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:
case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT:
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT:
return true;
}
return false;
}
bool isS3tcFormat(GLenum internalformat) {
switch (internalformat) {
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
return true;
}
return false;
}
bool isPaletteFormat(GLenum internalformat) {
switch (internalformat) {
case GL_PALETTE4_RGB8_OES:
case GL_PALETTE4_RGBA8_OES:
case GL_PALETTE4_R5_G6_B5_OES:
case GL_PALETTE4_RGBA4_OES:
case GL_PALETTE4_RGB5_A1_OES:
case GL_PALETTE8_RGB8_OES:
case GL_PALETTE8_RGBA8_OES:
case GL_PALETTE8_R5_G6_B5_OES:
case GL_PALETTE8_RGBA4_OES:
case GL_PALETTE8_RGB5_A1_OES:
return true;
}
return false;
}
GLenum decompressedInternalFormat(GLEScontext* ctx, GLenum compressedFormat) {
bool needSizedInternalFormat =
isCoreProfile() ||
(ctx->getMajorVersion() >= 3);
GLenum glrgb = needSizedInternalFormat ? GL_RGB8 : GL_RGB;
GLenum glrgba = needSizedInternalFormat ? GL_RGBA8 : GL_RGBA;
switch (compressedFormat) {
// ETC2 formats
case GL_COMPRESSED_RGB8_ETC2:
case GL_ETC1_RGB8_OES:
return glrgb;
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return glrgba;
case GL_COMPRESSED_SRGB8_ETC2:
return GL_SRGB8;
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
return GL_SRGB8_ALPHA8;
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
return GL_R32F;
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
return GL_RG32F;
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return GL_SRGB8_ALPHA8;
// ASTC formats
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
return glrgba;
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
return GL_SRGB8_ALPHA8;
// palette formats
case GL_PALETTE4_RGB8_OES:
case GL_PALETTE4_R5_G6_B5_OES:
case GL_PALETTE8_RGB8_OES:
case GL_PALETTE8_R5_G6_B5_OES:
return glrgb;
case GL_PALETTE4_RGBA8_OES:
case GL_PALETTE4_RGBA4_OES:
case GL_PALETTE4_RGB5_A1_OES:
case GL_PALETTE8_RGBA8_OES:
case GL_PALETTE8_RGBA4_OES:
case GL_PALETTE8_RGB5_A1_OES:
return glrgba;
case GL_COMPRESSED_RED_RGTC1_EXT: // BC4U
return GL_R8;
case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: // BC4S
return GL_R8_SNORM;
case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: // BC5U
return GL_RG8;
case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: // BC5S
return GL_RG8_SNORM;
default:
return compressedFormat;
}
}
class ScopedFetchUnpackData {
public:
ScopedFetchUnpackData(GLEScontext* ctx, GLintptr offset,
GLsizei dataSize) : mCtx(ctx) {
mData = ctx->dispatcher().glMapBufferRange(
GL_PIXEL_UNPACK_BUFFER,
offset, dataSize, GL_MAP_READ_BIT);
if (mData) {
ctx->dispatcher().glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING,
&mUnpackBuffer);
ctx->dispatcher().glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
0);
}
}
~ScopedFetchUnpackData() {
if (mData) {
mCtx->dispatcher().glBindBuffer(GL_PIXEL_UNPACK_BUFFER,
mUnpackBuffer);
mCtx->dispatcher().glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
}
}
void* data() {
return mData;
}
private:
const GLEScontext* mCtx;
void* mData = nullptr;
GLint mUnpackBuffer = 0;
};
void doCompressedTexImage2D(GLEScontext* ctx, GLenum target, GLint level,
GLenum internalformat, GLsizei width,
GLsizei height, GLint border,
GLsizei imageSize, const GLvoid* data,
glTexImage2D_t glTexImage2DPtr) {
/* XXX: This is just a hack to fix the resolve of glTexImage2D problem
It will be removed when we'll no longer link against ligGL */
/*typedef void (GLAPIENTRY *glTexImage2DPtr_t ) (
GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, const GLvoid *pixels);
glTexImage2DPtr_t glTexImage2DPtr;
glTexImage2DPtr = (glTexImage2DPtr_t)funcPtr;*/
bool needUnpackBuffer = false;
if (ctx->getMajorVersion() >= 3) {
GLint unpackBuffer = 0;
ctx->dispatcher().glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING,
&unpackBuffer);
needUnpackBuffer = unpackBuffer;
}
TextureUnpackReset unpack(ctx);
const int32_t unpackAlignment = TextureUnpackReset::kUnpackAlignment;
if (isEtcFormat(internalformat)) {
GLint format = GL_RGB;
GLint type = GL_UNSIGNED_BYTE;
GLint convertedInternalFormat = decompressedInternalFormat(ctx, internalformat);
ETC2ImageFormat etcFormat = EtcRGB8;
switch (internalformat) {
case GL_COMPRESSED_RGB8_ETC2:
case GL_ETC1_RGB8_OES:
break;
case GL_COMPRESSED_RGBA8_ETC2_EAC:
etcFormat = EtcRGBA8;
format = GL_RGBA;
break;
case GL_COMPRESSED_SRGB8_ETC2:
break;
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
etcFormat = EtcRGBA8;
format = GL_RGBA;
break;
case GL_COMPRESSED_R11_EAC:
etcFormat = EtcR11;
format = GL_RED;
type = GL_FLOAT;
break;
case GL_COMPRESSED_SIGNED_R11_EAC:
etcFormat = EtcSignedR11;
format = GL_RED;
type = GL_FLOAT;
break;
case GL_COMPRESSED_RG11_EAC:
etcFormat = EtcRG11;
format = GL_RG;
type = GL_FLOAT;
break;
case GL_COMPRESSED_SIGNED_RG11_EAC:
etcFormat = EtcSignedRG11;
format = GL_RG;
type = GL_FLOAT;
break;
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
etcFormat = EtcRGB8A1;
format = GL_RGBA;
break;
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
etcFormat = EtcRGB8A1;
format = GL_RGBA;
break;
}
int pixelSize = etc_get_decoded_pixel_size(etcFormat);
GLsizei compressedSize =
etc_get_encoded_data_size(etcFormat, width, height);
SET_ERROR_IF((compressedSize != imageSize), GL_INVALID_VALUE);
std::unique_ptr<ScopedFetchUnpackData> unpackData;
std::unique_ptr<char[]> emulatedData;
if (needUnpackBuffer) {
unpackData.reset(new ScopedFetchUnpackData(ctx,
reinterpret_cast<GLintptr>(data), compressedSize));
data = unpackData->data();
SET_ERROR_IF(!data, GL_INVALID_OPERATION);
} else {
if (!data) {
emulatedData.reset(new char[compressedSize]);
data = emulatedData.get();
}
}
const int32_t align = unpackAlignment - 1;
const int32_t bpr = ((width * pixelSize) + align) & ~align;
const size_t size = bpr * height;
std::unique_ptr<etc1_byte[]> pOut(new etc1_byte[size]);
int res =
etc2_decode_image(
(const etc1_byte*)data, etcFormat, pOut.get(),
width, height, bpr);
SET_ERROR_IF(res!=0, GL_INVALID_VALUE);
glTexImage2DPtr(target, level, convertedInternalFormat,
width, height, border, format, type, pOut.get());
} else if (isAstcFormat(internalformat)) {
std::unique_ptr<ScopedFetchUnpackData> unpackData;
std::unique_ptr<char[]> emulatedData;
if (needUnpackBuffer) {
unpackData.reset(
new ScopedFetchUnpackData(ctx, reinterpret_cast<GLintptr>(data), imageSize));
data = unpackData->data();
SET_ERROR_IF(!data, GL_INVALID_OPERATION);
} else {
if (!data) {
emulatedData.reset(new char[imageSize]);
data = emulatedData.get();
}
}
uint32_t blockWidth = 0;
uint32_t blockHeight = 0;
bool srgb;
getAstcFormatInfo(internalformat, &blockWidth, &blockHeight, &srgb);
const int32_t align = unpackAlignment - 1;
const int32_t stride = ((width * 4) + align) & ~align;
const size_t size = stride * height;
AlignedBuf<uint8_t, 64> alignedUncompressedData(size);
const bool result = astcDecompress(
reinterpret_cast<const uint8_t*>(data), imageSize, width,
height, blockWidth, blockHeight, alignedUncompressedData.data(), size);
SET_ERROR_IF(!result, GL_INVALID_VALUE);
glTexImage2DPtr(target, level, srgb ? GL_SRGB8_ALPHA8 : GL_RGBA8, width,
height, border, GL_RGBA, GL_UNSIGNED_BYTE,
alignedUncompressedData.data());
} else if (isPaletteFormat(internalformat)) {
// TODO: fix the case when GL_PIXEL_UNPACK_BUFFER is bound
SET_ERROR_IF(
level > log2(ctx->getMaxTexSize()) ||
border !=0 || level > 0 ||
!GLESvalidate::texImgDim(
width, height, ctx->getMaxTexSize() + 2),
GL_INVALID_VALUE);
SET_ERROR_IF(!data,GL_INVALID_OPERATION);
//the decoder fully packed the pixels.
ctx->dispatcher().glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int nMipmaps = -level + 1;
GLsizei tmpWidth = width;
GLsizei tmpHeight = height;
for(int i = 0; i < nMipmaps; i++)
{
GLenum uncompressedFrmt;
unsigned char* uncompressed =
uncompressTexture(internalformat, uncompressedFrmt,
width, height, imageSize, data, i);
glTexImage2DPtr(target, i, uncompressedFrmt,
tmpWidth, tmpHeight, border,
uncompressedFrmt, GL_UNSIGNED_BYTE, uncompressed);
tmpWidth /= 2;
tmpHeight /= 2;
delete [] uncompressed;
}
} else if (isRgtcFormat(internalformat)) {
GLint format, type;
GLint convertedInternalFormat = decompressedInternalFormat(ctx, internalformat);
RGTCImageFormat rgtcFormat;
switch (internalformat) {
case GL_COMPRESSED_RED_RGTC1_EXT: // BC4U
format = GL_RED;
type = GL_UNSIGNED_BYTE;
rgtcFormat = BC4_UNORM;
break;
case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: // BC4S
format = GL_RED;
type = GL_BYTE;
rgtcFormat = BC4_SNORM;
break;
case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: // BC5U
format = GL_RG;
type = GL_UNSIGNED_BYTE;
rgtcFormat = BC5_UNORM;
break;
case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: // BC5S
format = GL_RG;
type = GL_BYTE;
rgtcFormat = BC5_SNORM;
break;
}
size_t pixelSize = rgtc_get_decoded_pixel_size(rgtcFormat);
GLsizei compressedSize = rgtc_get_encoded_image_size(rgtcFormat, width, height);
SET_ERROR_IF((compressedSize != imageSize), GL_INVALID_VALUE);
std::unique_ptr<ScopedFetchUnpackData> unpackData;
std::unique_ptr<char[]> emulatedData;
if (needUnpackBuffer) {
unpackData.reset(
new ScopedFetchUnpackData(ctx, reinterpret_cast<GLintptr>(data), compressedSize));
data = unpackData->data();
SET_ERROR_IF(!data, GL_INVALID_OPERATION);
} else {
if (!data) {
emulatedData.reset(new char[compressedSize]);
data = emulatedData.get();
}
}
const int32_t align = unpackAlignment - 1;
const int32_t bpr = ((width * pixelSize) + align) & ~align;
const size_t size = bpr * height;
std::unique_ptr<uint8_t[]> pOut(new uint8_t[size]);
int res =
rgtc_decode_image((const uint8_t*)data, rgtcFormat, pOut.get(), width, height, bpr);
SET_ERROR_IF(res != 0, GL_INVALID_VALUE);
glTexImage2DPtr(target, level, convertedInternalFormat, width, height, border, format, type,
pOut.get());
} else {
SET_ERROR_IF(1, GL_INVALID_ENUM);
}
}
void deleteRenderbufferGlobal(GLuint rbo) {
if (rbo) {
GLEScontext::dispatcher().glDeleteRenderbuffers(1, &rbo);
}
}
bool isCubeMapFaceTarget(GLenum target) {
switch (target) {
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
return true;
}
return false;
}
bool isCoreProfileEmulatedFormat(GLenum format) {
switch (format) {
case GL_ALPHA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
return true;
default:
return false;
}
}
GLenum getCoreProfileEmulatedFormat(GLenum format) {
switch (format) {
case GL_ALPHA:
case GL_LUMINANCE:
return GL_RED;
case GL_LUMINANCE_ALPHA:
return GL_RG;
}
return format;
}
GLint getCoreProfileEmulatedInternalFormat(GLint internalformat, GLenum type) {
switch (internalformat) {
case GL_ALPHA:
case GL_LUMINANCE:
switch (type) {
case GL_UNSIGNED_BYTE:
return GL_R8;
case GL_FLOAT:
return GL_R32F;
case GL_HALF_FLOAT:
return GL_R16F;
}
return GL_R8;
case GL_LUMINANCE_ALPHA:
switch (type) {
case GL_UNSIGNED_BYTE:
return GL_RG8;
case GL_FLOAT:
return GL_RG32F;
case GL_HALF_FLOAT:
return GL_RG16F;
}
return GL_RG8;
}
fprintf(stderr,
"%s: warning: unsupported alpha/luminance internal format 0x%x type 0x%x\n",
__func__, internalformat, type);
return GL_R8;
}
TextureSwizzle getSwizzleForEmulatedFormat(GLenum format) {
TextureSwizzle res;
switch (format) {
case GL_ALPHA:
res.toRed = GL_ZERO;
res.toGreen = GL_ZERO;
res.toBlue = GL_ZERO;
res.toAlpha = GL_RED;
break;
case GL_LUMINANCE:
res.toRed = GL_RED;
res.toGreen = GL_RED;
res.toBlue = GL_RED;
res.toAlpha = GL_ONE;
break;
case GL_LUMINANCE_ALPHA:
res.toRed = GL_RED;
res.toGreen = GL_RED;
res.toBlue = GL_RED;
res.toAlpha = GL_GREEN;
break;
default:
break;
}
return res;
}
// Inverse swizzle: if we were writing fragments back to this texture,
// how should the components be re-arranged?
TextureSwizzle getInverseSwizzleForEmulatedFormat(GLenum format) {
TextureSwizzle res;
switch (format) {
case GL_ALPHA:
res.toRed = GL_ALPHA;
res.toGreen = GL_ZERO;
res.toBlue = GL_ZERO;
res.toAlpha = GL_ZERO;
break;
case GL_LUMINANCE:
res.toRed = GL_RED;
res.toGreen = GL_ZERO;
res.toBlue = GL_ZERO;
res.toAlpha = GL_ZERO;
break;
case GL_LUMINANCE_ALPHA:
res.toRed = GL_RED;
res.toGreen = GL_ALPHA;
res.toBlue = GL_ZERO;
res.toAlpha = GL_ZERO;
break;
default:
break;
}
return res;
}
GLenum swizzleComponentOf(const TextureSwizzle& s, GLenum component) {
switch (component) {
case GL_RED: return s.toRed;
case GL_GREEN: return s.toGreen;
case GL_BLUE: return s.toBlue;
case GL_ALPHA: return s.toAlpha;
}
// Identity map for GL_ZERO / GL_ONE
return component;
}
TextureSwizzle concatSwizzles(const TextureSwizzle& first,
const TextureSwizzle& next) {
TextureSwizzle result;
result.toRed = swizzleComponentOf(first, next.toRed);
result.toGreen = swizzleComponentOf(first, next.toGreen);
result.toBlue = swizzleComponentOf(first, next.toBlue);
result.toAlpha = swizzleComponentOf(first, next.toAlpha);
return result;
}
bool isSwizzleParam(GLenum pname) {
switch (pname) {
case GL_TEXTURE_SWIZZLE_R:
case GL_TEXTURE_SWIZZLE_G:
case GL_TEXTURE_SWIZZLE_B:
case GL_TEXTURE_SWIZZLE_A:
return true;
default:
return false;
}
}
bool isIntegerInternalFormat(GLint internalformat) {
switch (internalformat) {
case GL_R8I:
case GL_R8UI:
case GL_R16I:
case GL_R16UI:
case GL_R32I:
case GL_R32UI:
case GL_RG8I:
case GL_RG8UI:
case GL_RG16I:
case GL_RG16UI:
case GL_RG32I:
case GL_RG32UI:
case GL_RGB8I:
case GL_RGB8UI:
case GL_RGB16I:
case GL_RGB16UI:
case GL_RGB32I:
case GL_RGB32UI:
case GL_RGBA8I:
case GL_RGBA8UI:
case GL_RGBA16I:
case GL_RGBA16UI:
case GL_RGBA32I:
case GL_RGBA32UI:
return true;
default:
return false;
}
}
void doCompressedTexImage2DNative(GLEScontext* ctx, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
// AlignedBuf<uint8_t, 64> alignedData(imageSize);
// memcpy(alignedData.data(), data, imageSize);
// GLint err = ctx->dispatcher().glGetError();
ctx->dispatcher().glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
// fprintf(stderr, "%s: tex %u target 0x%x level 0x%x iformat 0x%x w h b %d %d %d imgSize %d\n", __func__, ctx->getBindedTexture(target), target, level, internalformat, width, height, border, imageSize);
// err = ctx->dispatcher().glGetError(); if (err) {
// fprintf(stderr, "%s:%d err 0x%x\n", __func__, __LINE__, err);
// }
}
void doCompressedTexSubImage2DNative(GLEScontext* ctx, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) {
// AlignedBuf<uint8_t, 64> alignedData(imageSize);
// memcpy(alignedData.data(), data, imageSize);
// GLint err = ctx->dispatcher().glGetError();
ctx->dispatcher().glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
// fprintf(stderr, "%s: tex %u target 0x%x level 0x%x format 0x%x x y w h %d %d %d %d imgSize %d\n", __func__, ctx->getBindedTexture(target), target, level, format, xoffset, yoffset, width, height, imageSize);
// err = ctx->dispatcher().glGetError(); if (err) {
// fprintf(stderr, "%s:%d err 0x%x\n", __func__, __LINE__, err);
// }
}
void forEachEtc2Format(std::function<void(GLint format)> f) {
f(GL_COMPRESSED_RGB8_ETC2);
f(GL_COMPRESSED_SRGB8_ETC2);
f(GL_COMPRESSED_RGBA8_ETC2_EAC);
f(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC);
f(GL_COMPRESSED_R11_EAC);
f(GL_COMPRESSED_SIGNED_R11_EAC);
f(GL_COMPRESSED_RG11_EAC);
f(GL_COMPRESSED_SIGNED_RG11_EAC);
f(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2);
f(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2);
}
void forEachAstcFormat(std::function<void(GLint format)> f) {
#define CALL_ON_ASTC_FORMAT(typeName, blockWidth, blockHeight, srgbValue) \
f(typeName);
ASTC_FORMATS_LIST(CALL_ON_ASTC_FORMAT)
}
void forEachBptcFormat(std::function<void(GLint format)> f) {
f(GL_COMPRESSED_RGBA_BPTC_UNORM_EXT);
f(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT);
f(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT);
f(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT);
}
void forEachS3tcFormat(std::function<void(GLint format)> f) {
f(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
f(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
f(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
f(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
f(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT);
f(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT);
f(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT);
f(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT);
}
bool isRgtcFormat(GLenum format) {
switch (format) {
case GL_COMPRESSED_RED_RGTC1_EXT: // BC4U
case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: // BC4S
case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: // BC5U
case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: // BC5S
return true;
default:
break;
}
return false;
}
bool isEtc2OrAstcFormat(GLenum format) {
switch (format) {
case GL_COMPRESSED_RGB8_ETC2:
case GL_COMPRESSED_SRGB8_ETC2:
case GL_COMPRESSED_RGBA8_ETC2_EAC:
case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case GL_COMPRESSED_R11_EAC:
case GL_COMPRESSED_SIGNED_R11_EAC:
case GL_COMPRESSED_RG11_EAC:
case GL_COMPRESSED_SIGNED_RG11_EAC:
case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return true;
default:
break;
}
return isAstcFormat(format);
}
bool shouldPassthroughCompressedFormat(GLEScontext* ctx, GLenum internalformat) {
if (isEtc2Format(internalformat)) {
return ctx->getCaps()->hasEtc2Support;
} else if (isAstcFormat(internalformat)) {
return ctx->getCaps()->hasAstcSupport;
} else if (isBptcFormat(internalformat)) {
return ctx->getCaps()->hasBptcSupport;
} else if (isS3tcFormat(internalformat)) {
return ctx->getCaps()->hasS3tcSupport;
} else if (isRgtcFormat(internalformat)) {
return ctx->getCaps()->hasRgtcSupport;
}
return false;
}
static uint32_t s_texAlign(uint32_t v, uint32_t align) {
uint32_t rem = v % align;
return rem ? (v + (align - rem)) : v;
}
// s_computePixelSize is both in the host and the guest. Consider moving it to
// android-emugl/shared
static int s_computePixelSize(GLenum format, GLenum type) {
#define FORMAT_ERROR(format, type) \
fprintf(stderr, "%s:%d unknown format/type 0x%x 0x%x\n", __FUNCTION__, \
__LINE__, format, type);
switch (type) {
case GL_BYTE:
switch (format) {
case GL_R8:
case GL_R8I:
case GL_R8_SNORM:
case GL_RED:
return 1;
case GL_RED_INTEGER:
return 1;
case GL_RG8:
case GL_RG8I:
case GL_RG8_SNORM:
case GL_RG:
return 1 * 2;
case GL_RG_INTEGER:
return 1 * 2;
case GL_RGB8:
case GL_RGB8I:
case GL_RGB8_SNORM:
case GL_RGB:
return 1 * 3;
case GL_RGB_INTEGER:
return 1 * 3;
case GL_RGBA8:
case GL_RGBA8I:
case GL_RGBA8_SNORM:
case GL_RGBA:
return 1 * 4;
case GL_RGBA_INTEGER:
return 1 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
case GL_UNSIGNED_BYTE:
switch (format) {
case GL_R8:
case GL_R8UI:
case GL_RED:
return 1;
case GL_RED_INTEGER:
return 1;
case GL_ALPHA8_EXT:
case GL_ALPHA:
return 1;
case GL_LUMINANCE8_EXT:
case GL_LUMINANCE:
return 1;
case GL_LUMINANCE8_ALPHA8_EXT:
case GL_LUMINANCE_ALPHA:
return 1 * 2;
case GL_RG8:
case GL_RG8UI:
case GL_RG:
return 1 * 2;
case GL_RG_INTEGER:
return 1 * 2;
case GL_RGB8:
case GL_RGB8UI:
case GL_SRGB8:
case GL_RGB:
return 1 * 3;
case GL_RGB_INTEGER:
return 1 * 3;
case GL_RGBA8:
case GL_RGBA8UI:
case GL_SRGB8_ALPHA8:
case GL_RGBA:
return 1 * 4;
case GL_RGBA_INTEGER:
return 1 * 4;
case GL_BGRA_EXT:
case GL_BGRA8_EXT:
return 1 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
case GL_SHORT:
switch (format) {
case GL_R16I:
case GL_RED_INTEGER:
return 2;
case GL_RG16I:
case GL_RG_INTEGER:
return 2 * 2;
case GL_RGB16I:
case GL_RGB_INTEGER:
return 2 * 3;
case GL_RGBA16I:
case GL_RGBA_INTEGER:
return 2 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
case GL_UNSIGNED_SHORT:
switch (format) {
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT:
return 2;
case GL_R16UI:
case GL_RED_INTEGER:
return 2;
case GL_RG16UI:
case GL_RG_INTEGER:
return 2 * 2;
case GL_RGB16UI:
case GL_RGB_INTEGER:
return 2 * 3;
case GL_RGBA16UI:
case GL_RGBA_INTEGER:
return 2 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
case GL_INT:
switch (format) {
case GL_R32I:
case GL_RED_INTEGER:
return 4;
case GL_RG32I:
case GL_RG_INTEGER:
return 4 * 2;
case GL_RGB32I:
case GL_RGB_INTEGER:
return 4 * 3;
case GL_RGBA32I:
case GL_RGBA_INTEGER:
return 4 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
case GL_UNSIGNED_INT:
switch (format) {
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT24:
case GL_DEPTH_COMPONENT32_OES:
case GL_DEPTH_COMPONENT:
return 4;
case GL_R32UI:
case GL_RED_INTEGER:
return 4;
case GL_RG32UI:
case GL_RG_INTEGER:
return 4 * 2;
case GL_RGB32UI:
case GL_RGB_INTEGER:
return 4 * 3;
case GL_RGBA32UI:
case GL_RGBA_INTEGER:
return 4 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
return 2;
case GL_UNSIGNED_INT_10F_11F_11F_REV:
case GL_UNSIGNED_INT_5_9_9_9_REV:
case GL_UNSIGNED_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_24_8_OES:
return 4;
case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
return 4 + 4;
case GL_FLOAT:
switch (format) {
case GL_DEPTH_COMPONENT32F:
case GL_DEPTH_COMPONENT:
return 4;
case GL_ALPHA32F_EXT:
case GL_ALPHA:
return 4;
case GL_LUMINANCE32F_EXT:
case GL_LUMINANCE:
return 4;
case GL_LUMINANCE_ALPHA32F_EXT:
case GL_LUMINANCE_ALPHA:
return 4 * 2;
case GL_RED:
return 4;
case GL_R32F:
return 4;
case GL_RG:
return 4 * 2;
case GL_RG32F:
return 4 * 2;
case GL_RGB:
return 4 * 3;
case GL_RGB32F:
return 4 * 3;
case GL_RGBA:
return 4 * 4;
case GL_RGBA32F:
return 4 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
case GL_HALF_FLOAT:
case GL_HALF_FLOAT_OES:
switch (format) {
case GL_ALPHA16F_EXT:
case GL_ALPHA:
return 2;
case GL_LUMINANCE16F_EXT:
case GL_LUMINANCE:
return 2;
case GL_LUMINANCE_ALPHA16F_EXT:
case GL_LUMINANCE_ALPHA:
return 2 * 2;
case GL_RED:
return 2;
case GL_R16F:
return 2;
case GL_RG:
return 2 * 2;
case GL_RG16F:
return 2 * 2;
case GL_RGB:
return 2 * 3;
case GL_RGB16F:
return 2 * 3;
case GL_RGBA:
return 2 * 4;
case GL_RGBA16F:
return 2 * 4;
default:
FORMAT_ERROR(format, type);
}
break;
default:
FORMAT_ERROR(format, type);
}
return 0;
}
uint32_t texImageSize(GLenum internalformat,
GLenum type,
int unpackAlignment,
GLsizei width,
GLsizei height) {
uint32_t alignedWidth = s_texAlign(width, unpackAlignment);
uint32_t pixelSize = s_computePixelSize(internalformat, type);
uint32_t totalSize = pixelSize * alignedWidth * height;
return totalSize;
}
GLenum getFormatFromInternalFormat(GLint internalFormat) {
switch (internalFormat) {
case GL_R8:
return GL_RED;
case GL_RG8:
return GL_RG;
case GL_RGB8:
case GL_RGB565:
case GL_RGB16F:
return GL_RGB;
case GL_RGBA8:
case GL_RGB5_A1_OES:
case GL_RGBA4_OES:
case GL_UNSIGNED_INT_10_10_10_2_OES:
case GL_RGB10_A2:
case GL_RGBA16F:
return GL_RGBA;
case GL_BGRA8_EXT:
return GL_BGRA_EXT;
default: // already unsized
return internalFormat;
}
}
GLenum getTypeFromInternalFormat(GLint internalFormat) {
switch (internalFormat) {
case GL_RGB:
case GL_RGB8:
return GL_UNSIGNED_BYTE;
case GL_RGB565_OES:
return GL_UNSIGNED_SHORT_5_6_5;
case GL_RGBA:
case GL_RGBA8:
case GL_RGB5_A1_OES:
case GL_RGBA4_OES:
return GL_UNSIGNED_BYTE;
case GL_UNSIGNED_INT_10_10_10_2_OES:
return GL_UNSIGNED_SHORT;
case GL_RGB10_A2:
return GL_UNSIGNED_INT_2_10_10_10_REV;
case GL_RGB16F:
return GL_HALF_FLOAT;
case GL_RGBA16F:
return GL_HALF_FLOAT;
case GL_LUMINANCE:
return GL_UNSIGNED_SHORT;
case GL_BGRA_EXT:
return GL_UNSIGNED_BYTE;
case GL_R8:
case GL_RED:
return GL_UNSIGNED_BYTE;
case GL_RG8:
case GL_RG:
return GL_UNSIGNED_BYTE;
default:
fprintf(stderr, "%s: Unknown format 0x%x\n", __func__,
internalFormat);
return GL_UNSIGNED_BYTE;
}
}
GLint TextureUnpackReset::unpackCheckAndUpdate(GLenum name, GLint newValue) {
GLint curValue;
glesContext->dispatcher().glGetIntegerv(name, &curValue);
if (curValue != newValue) {
glesContext->dispatcher().glPixelStorei(name, newValue);
}
return curValue;
}
TextureUnpackReset::TextureUnpackReset(GLEScontext* ctx) : glesContext(ctx) {
unpackAlignment = unpackCheckAndUpdate(GL_UNPACK_ALIGNMENT, kUnpackAlignment);
if (glesContext->getMajorVersion() >= 3) {
unpackRowLength = unpackCheckAndUpdate(GL_UNPACK_ROW_LENGTH, kUnpackRowLength);
unpackImageHeight = unpackCheckAndUpdate(GL_UNPACK_IMAGE_HEIGHT, kUnpackImageHeight);
unpackSkipRows = unpackCheckAndUpdate(GL_UNPACK_SKIP_ROWS, kUnpackSkipRows);
unpackSkipPixels = unpackCheckAndUpdate(GL_UNPACK_SKIP_PIXELS, kUnpackSkipPixels);
unpackSkipImages = unpackCheckAndUpdate(GL_UNPACK_SKIP_IMAGES, kUnpackSkipImages);
} else {
// avoid clang-tidy warnings on uninitialized values
unpackRowLength = 0;
unpackImageHeight = 0;
unpackSkipRows = 0;
unpackSkipPixels = 0;
unpackSkipImages = 0;
}
}
TextureUnpackReset::~TextureUnpackReset() {
unpackCheckAndUpdate(GL_UNPACK_ALIGNMENT, unpackAlignment);
if (glesContext->getMajorVersion() >= 3) {
unpackCheckAndUpdate(GL_UNPACK_ROW_LENGTH, unpackRowLength);
unpackCheckAndUpdate(GL_UNPACK_IMAGE_HEIGHT, unpackImageHeight);
unpackCheckAndUpdate(GL_UNPACK_SKIP_ROWS, unpackSkipRows);
unpackCheckAndUpdate(GL_UNPACK_SKIP_PIXELS, unpackSkipPixels);
unpackCheckAndUpdate(GL_UNPACK_SKIP_IMAGES, unpackSkipImages);
}
}