| /* |
| * 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); |
| } |
| } |
| |