// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // 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 "Image.hpp" #include "../libEGL/Context.hpp" #include "../libEGL/Texture.hpp" #include "../common/debug.h" #include "Common/Math.hpp" #include "Common/Thread.hpp" #include #include namespace { int getNumBlocks(int w, int h, int blockSizeX, int blockSizeY) { return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY); } enum DataType { Bytes_1, Bytes_2, Bytes_4, Bytes_8, Bytes_16, ByteRGB, UByteRGB, ShortRGB, UShortRGB, IntRGB, UIntRGB, RGB565, FloatRGB, HalfFloatRGB, RGBA4444, RGBA5551, RGB10A2UI, R11G11B10F, RGB9E5, SRGB, SRGBA, D16, D24, D32, D32F, S8, S24_8, }; template void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { UNIMPLEMENTED(); } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { memcpy(dest + xoffset, source, width); } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { memcpy(dest + xoffset * 2, source, width * 2); } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { memcpy(dest + xoffset * 4, source, width * 4); } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { memcpy(dest + xoffset * 8, source, width * 8); } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { memcpy(dest + xoffset * 16, source, width * 16); } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { unsigned char *destB = dest + xoffset * 4; for(int x = 0; x < width; x++) { destB[4 * x + 0] = source[x * 3 + 0]; destB[4 * x + 1] = source[x * 3 + 1]; destB[4 * x + 2] = source[x * 3 + 2]; destB[4 * x + 3] = 0x7F; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { unsigned char *destB = dest + xoffset * 4; for(int x = 0; x < width; x++) { destB[4 * x + 0] = source[x * 3 + 0]; destB[4 * x + 1] = source[x * 3 + 1]; destB[4 * x + 2] = source[x * 3 + 2]; destB[4 * x + 3] = 0xFF; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned short *sourceS = reinterpret_cast(source); unsigned short *destS = reinterpret_cast(dest + xoffset * 8); for(int x = 0; x < width; x++) { destS[4 * x + 0] = sourceS[x * 3 + 0]; destS[4 * x + 1] = sourceS[x * 3 + 1]; destS[4 * x + 2] = sourceS[x * 3 + 2]; destS[4 * x + 3] = 0x7FFF; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned short *sourceS = reinterpret_cast(source); unsigned short *destS = reinterpret_cast(dest + xoffset * 8); for(int x = 0; x < width; x++) { destS[4 * x + 0] = sourceS[x * 3 + 0]; destS[4 * x + 1] = sourceS[x * 3 + 1]; destS[4 * x + 2] = sourceS[x * 3 + 2]; destS[4 * x + 3] = 0xFFFF; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned int *sourceI = reinterpret_cast(source); unsigned int *destI = reinterpret_cast(dest + xoffset * 16); for(int x = 0; x < width; x++) { destI[4 * x + 0] = sourceI[x * 3 + 0]; destI[4 * x + 1] = sourceI[x * 3 + 1]; destI[4 * x + 2] = sourceI[x * 3 + 2]; destI[4 * x + 3] = 0x7FFFFFFF; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned int *sourceI = reinterpret_cast(source); unsigned int *destI = reinterpret_cast(dest + xoffset * 16); for(int x = 0; x < width; x++) { destI[4 * x + 0] = sourceI[x * 3 + 0]; destI[4 * x + 1] = sourceI[x * 3 + 1]; destI[4 * x + 2] = sourceI[x * 3 + 2]; destI[4 * x + 3] = 0xFFFFFFFF; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { memcpy(dest + xoffset * 2, source, width * 2); } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const float *sourceF = reinterpret_cast(source); float *destF = reinterpret_cast(dest + xoffset * 16); for(int x = 0; x < width; x++) { destF[4 * x + 0] = sourceF[x * 3 + 0]; destF[4 * x + 1] = sourceF[x * 3 + 1]; destF[4 * x + 2] = sourceF[x * 3 + 2]; destF[4 * x + 3] = 1.0f; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned short *sourceH = reinterpret_cast(source); unsigned short *destH = reinterpret_cast(dest + xoffset * 8); for(int x = 0; x < width; x++) { destH[4 * x + 0] = sourceH[x * 3 + 0]; destH[4 * x + 1] = sourceH[x * 3 + 1]; destH[4 * x + 2] = sourceH[x * 3 + 2]; destH[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned short *source4444 = reinterpret_cast(source); unsigned char *dest4444 = dest + xoffset * 4; for(int x = 0; x < width; x++) { unsigned short rgba = source4444[x]; dest4444[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); dest4444[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); dest4444[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); dest4444[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned short *source5551 = reinterpret_cast(source); unsigned char *dest5551 = dest + xoffset * 4; for(int x = 0; x < width; x++) { unsigned short rgba = source5551[x]; dest5551[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); dest5551[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); dest5551[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); dest5551[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned int *source1010102U = reinterpret_cast(source); unsigned short *dest16U = reinterpret_cast(dest + xoffset * 8); for(int x = 0; x < width; x++) { unsigned int rgba = source1010102U[x]; dest16U[4 * x + 0] = (rgba & 0x000003FF); dest16U[4 * x + 1] = (rgba & 0x000FFC00) >> 10; dest16U[4 * x + 2] = (rgba & 0x3FF00000) >> 20; dest16U[4 * x + 3] = (rgba & 0xC0000000) >> 30; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const sw::R11G11B10FData *sourceRGB = reinterpret_cast(source); float *destF = reinterpret_cast(dest + xoffset * 16); for(int x = 0; x < width; x++, sourceRGB++, destF+=4) { sourceRGB->toRGBFloats(destF); destF[3] = 1.0f; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const sw::RGB9E5Data *sourceRGB = reinterpret_cast(source); float *destF = reinterpret_cast(dest + xoffset * 16); for(int x = 0; x < width; x++, sourceRGB++, destF += 4) { sourceRGB->toRGBFloats(destF); destF[3] = 1.0f; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { dest += xoffset * 4; for(int x = 0; x < width; x++) { for(int rgb = 0; rgb < 3; ++rgb) { *dest++ = sw::sRGB8toLinear8(*source++); } *dest++ = 255; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { dest += xoffset * 4; for(int x = 0; x < width; x++) { for(int rgb = 0; rgb < 3; ++rgb) { *dest++ = sw::sRGB8toLinear8(*source++); } *dest++ = *source++; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned short *sourceD16 = reinterpret_cast(source); float *destF = reinterpret_cast(dest + xoffset * 4); for(int x = 0; x < width; x++) { destF[x] = (float)sourceD16[x] / 0xFFFF; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned int *sourceD24 = reinterpret_cast(source); float *destF = reinterpret_cast(dest + xoffset * 4); for(int x = 0; x < width; x++) { destF[x] = (float)(sourceD24[x] & 0xFFFFFF00) / 0xFFFFFF00; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned int *sourceD32 = reinterpret_cast(source); float *destF = reinterpret_cast(dest + xoffset * 4); for(int x = 0; x < width; x++) { destF[x] = (float)sourceD32[x] / 0xFFFFFFFF; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { const unsigned int *sourceI = reinterpret_cast(source); unsigned char *destI = dest + xoffset; for(int x = 0; x < width; x++) { destI[x] = static_cast(sourceI[x] & 0x000000FF); // FIXME: Quad layout } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { struct D32FS8 { float depth32f; unsigned int stencil24_8; }; const D32FS8 *sourceD32FS8 = reinterpret_cast(source); float *destF = reinterpret_cast(dest + xoffset * 4); for(int x = 0; x < width; x++) { destF[x] = sourceD32FS8[x].depth32f; } } template<> void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) { struct D32FS8 { float depth32f; unsigned int stencil24_8; }; const D32FS8 *sourceD32FS8 = reinterpret_cast(source); unsigned char *destI = dest + xoffset; for(int x = 0; x < width; x++) { destI[x] = static_cast(sourceD32FS8[x].stencil24_8 & 0x000000FF); // FIXME: Quad layout } } template void LoadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, int destPitch, GLsizei destHeight, const void *input, void *buffer) { for(int z = 0; z < depth; ++z) { const unsigned char *inputStart = static_cast(input) + (z * inputPitch * inputHeight); unsigned char *destStart = static_cast(buffer) + ((zoffset + z) * destPitch * destHeight); for(int y = 0; y < height; ++y) { const unsigned char *source = inputStart + y * inputPitch; unsigned char *dest = destStart + (y + yoffset) * destPitch; LoadImageRow(source, dest, xoffset, width); } } } } namespace egl { sw::Format ConvertFormatType(GLenum format, GLenum type) { switch(format) { case GL_LUMINANCE: switch(type) { case GL_UNSIGNED_BYTE: return sw::FORMAT_L8; case GL_HALF_FLOAT: return sw::FORMAT_L16F; case GL_HALF_FLOAT_OES: return sw::FORMAT_L16F; case GL_FLOAT: return sw::FORMAT_L32F; default: UNREACHABLE(type); } break; case GL_LUMINANCE8_EXT: return sw::FORMAT_L8; case GL_LUMINANCE16F_EXT: return sw::FORMAT_L16F; case GL_LUMINANCE32F_EXT: return sw::FORMAT_L32F; case GL_LUMINANCE_ALPHA: switch(type) { case GL_UNSIGNED_BYTE: return sw::FORMAT_A8L8; case GL_HALF_FLOAT: return sw::FORMAT_A16L16F; case GL_HALF_FLOAT_OES: return sw::FORMAT_A16L16F; case GL_FLOAT: return sw::FORMAT_A32L32F; default: UNREACHABLE(type); } break; case GL_LUMINANCE8_ALPHA8_EXT: return sw::FORMAT_A8L8; case GL_LUMINANCE_ALPHA16F_EXT: return sw::FORMAT_A16L16F; case GL_LUMINANCE_ALPHA32F_EXT: return sw::FORMAT_A32L32F; case GL_RGBA: switch(type) { case GL_UNSIGNED_BYTE: return sw::FORMAT_A8B8G8R8; case GL_UNSIGNED_SHORT_4_4_4_4: return sw::FORMAT_R4G4B4A4; case GL_UNSIGNED_SHORT_5_5_5_1: return sw::FORMAT_R5G5B5A1; case GL_HALF_FLOAT: return sw::FORMAT_A16B16G16R16F; case GL_HALF_FLOAT_OES: return sw::FORMAT_A16B16G16R16F; case GL_FLOAT: return sw::FORMAT_A32B32G32R32F; default: UNREACHABLE(type); } break; case GL_BGRA_EXT: case GL_BGRA8_EXT: switch(type) { case GL_UNSIGNED_BYTE: return sw::FORMAT_A8R8G8B8; case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return sw::FORMAT_A4R4G4B4; case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return sw::FORMAT_A1R5G5B5; default: UNREACHABLE(type); } break; case GL_RGB: switch(type) { case GL_UNSIGNED_BYTE: return sw::FORMAT_B8G8R8; case GL_UNSIGNED_SHORT_5_6_5: return sw::FORMAT_R5G6B5; case GL_HALF_FLOAT: return sw::FORMAT_B16G16R16F; case GL_HALF_FLOAT_OES: return sw::FORMAT_B16G16R16F; case GL_FLOAT: return sw::FORMAT_B32G32R32F; default: UNREACHABLE(type); } break; case GL_ALPHA: switch(type) { case GL_UNSIGNED_BYTE: return sw::FORMAT_A8; case GL_HALF_FLOAT: return sw::FORMAT_A16F; case GL_HALF_FLOAT_OES: return sw::FORMAT_A16F; case GL_FLOAT: return sw::FORMAT_A32F; default: UNREACHABLE(type); } break; case GL_ALPHA8_EXT: return sw::FORMAT_A8; case GL_ALPHA16F_EXT: return sw::FORMAT_A16F; case GL_ALPHA32F_EXT: return sw::FORMAT_A32F; case GL_RED_INTEGER: switch(type) { case GL_INT: return sw::FORMAT_R32I; case GL_UNSIGNED_INT: return sw::FORMAT_R32UI; default: UNREACHABLE(type); } break; case GL_RG_INTEGER: switch(type) { case GL_INT: return sw::FORMAT_G32R32I; case GL_UNSIGNED_INT: return sw::FORMAT_G32R32UI; default: UNREACHABLE(type); } break; case GL_RGBA_INTEGER: switch(type) { case GL_INT: return sw::FORMAT_A32B32G32R32I; case GL_UNSIGNED_INT: return sw::FORMAT_A32B32G32R32UI; default: UNREACHABLE(type); } break; case GL_DEPTH_COMPONENT: switch(type) { case GL_UNSIGNED_SHORT: return sw::FORMAT_D16; case GL_UNSIGNED_INT_24_8_OES: return sw::FORMAT_D24S8; case GL_UNSIGNED_INT: return sw::FORMAT_D32; case GL_FLOAT: return sw::FORMAT_D32F; default: UNREACHABLE(type); } break; default: UNREACHABLE(format); } return sw::FORMAT_NULL; } sw::Format SelectInternalFormat(GLenum format, GLenum type) { switch(format) { case GL_ETC1_RGB8_OES: return sw::FORMAT_ETC1; case GL_COMPRESSED_R11_EAC: return sw::FORMAT_R11_EAC; case GL_COMPRESSED_SIGNED_R11_EAC: return sw::FORMAT_SIGNED_R11_EAC; case GL_COMPRESSED_RG11_EAC: return sw::FORMAT_RG11_EAC; case GL_COMPRESSED_SIGNED_RG11_EAC: return sw::FORMAT_SIGNED_RG11_EAC; case GL_COMPRESSED_RGB8_ETC2: return sw::FORMAT_RGB8_ETC2; case GL_COMPRESSED_SRGB8_ETC2: return sw::FORMAT_SRGB8_ETC2; case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: return sw::FORMAT_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return sw::FORMAT_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; case GL_COMPRESSED_RGBA8_ETC2_EAC: return sw::FORMAT_RGBA8_ETC2_EAC; case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return sw::FORMAT_SRGB8_ALPHA8_ETC2_EAC; case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: return sw::FORMAT_RGBA_ASTC_4x4_KHR; case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: return sw::FORMAT_RGBA_ASTC_5x4_KHR; case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: return sw::FORMAT_RGBA_ASTC_5x5_KHR; case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: return sw::FORMAT_RGBA_ASTC_6x5_KHR; case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: return sw::FORMAT_RGBA_ASTC_6x6_KHR; case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: return sw::FORMAT_RGBA_ASTC_8x5_KHR; case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: return sw::FORMAT_RGBA_ASTC_8x6_KHR; case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: return sw::FORMAT_RGBA_ASTC_8x8_KHR; case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: return sw::FORMAT_RGBA_ASTC_10x5_KHR; case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: return sw::FORMAT_RGBA_ASTC_10x6_KHR; case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: return sw::FORMAT_RGBA_ASTC_10x8_KHR; case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: return sw::FORMAT_RGBA_ASTC_10x10_KHR; case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: return sw::FORMAT_RGBA_ASTC_12x10_KHR; case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: return sw::FORMAT_RGBA_ASTC_12x12_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_4x4_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x4_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_5x5_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x5_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_6x6_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x5_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x6_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_8x8_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x5_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x6_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x8_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_10x10_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x10_KHR; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return sw::FORMAT_SRGB8_ALPHA8_ASTC_12x12_KHR; #if S3TC_SUPPORT case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return sw::FORMAT_DXT1; case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: return sw::FORMAT_DXT3; case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: return sw::FORMAT_DXT5; #endif default: break; } switch(type) { case GL_FLOAT: switch(format) { case GL_ALPHA: case GL_ALPHA32F_EXT: return sw::FORMAT_A32F; case GL_LUMINANCE: case GL_LUMINANCE32F_EXT: return sw::FORMAT_L32F; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE_ALPHA32F_EXT: return sw::FORMAT_A32L32F; case GL_RED: case GL_R32F: return sw::FORMAT_R32F; case GL_RG: case GL_RG32F: return sw::FORMAT_G32R32F; case GL_RGB: case GL_RGB32F: return sw::FORMAT_X32B32G32R32F; case GL_RGBA: case GL_RGBA32F: return sw::FORMAT_A32B32G32R32F; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT32F: return sw::FORMAT_D32F; default: UNREACHABLE(format); } case GL_HALF_FLOAT: case GL_HALF_FLOAT_OES: switch(format) { case GL_ALPHA: case GL_ALPHA16F_EXT: return sw::FORMAT_A16F; case GL_LUMINANCE: case GL_LUMINANCE16F_EXT: return sw::FORMAT_L16F; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE_ALPHA16F_EXT: return sw::FORMAT_A16L16F; case GL_RED: case GL_R16F: return sw::FORMAT_R16F; case GL_RG: case GL_RG16F: return sw::FORMAT_G16R16F; case GL_RGB: case GL_RGB16F: case GL_RGBA: case GL_RGBA16F: return sw::FORMAT_A16B16G16R16F; default: UNREACHABLE(format); } case GL_BYTE: switch(format) { case GL_R8_SNORM: case GL_R8: case GL_RED: return sw::FORMAT_R8I_SNORM; case GL_R8I: case GL_RED_INTEGER: return sw::FORMAT_R8I; case GL_RG8_SNORM: case GL_RG8: case GL_RG: return sw::FORMAT_G8R8I_SNORM; case GL_RG8I: case GL_RG_INTEGER: return sw::FORMAT_G8R8I; case GL_RGB8_SNORM: case GL_RGB8: case GL_RGB: return sw::FORMAT_X8B8G8R8I_SNORM; case GL_RGB8I: case GL_RGB_INTEGER: return sw::FORMAT_X8B8G8R8I; case GL_RGBA8_SNORM: case GL_RGBA8: case GL_RGBA: return sw::FORMAT_A8B8G8R8I_SNORM; case GL_RGBA8I: case GL_RGBA_INTEGER: return sw::FORMAT_A8B8G8R8I; default: UNREACHABLE(format); } case GL_UNSIGNED_BYTE: switch(format) { case GL_LUMINANCE: case GL_LUMINANCE8_EXT: return sw::FORMAT_L8; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE8_ALPHA8_EXT: return sw::FORMAT_A8L8; case GL_R8_SNORM: case GL_R8: case GL_RED: return sw::FORMAT_R8; case GL_R8UI: case GL_RED_INTEGER: return sw::FORMAT_R8UI; case GL_RG8_SNORM: case GL_RG8: case GL_RG: return sw::FORMAT_G8R8; case GL_RG8UI: case GL_RG_INTEGER: return sw::FORMAT_G8R8UI; case GL_RGB8_SNORM: case GL_RGB8: case GL_RGB: case GL_SRGB8: return sw::FORMAT_X8B8G8R8; case GL_RGB8UI: case GL_RGB_INTEGER: return sw::FORMAT_X8B8G8R8UI; case GL_RGBA8_SNORM: case GL_RGBA8: case GL_RGBA: case GL_SRGB8_ALPHA8: return sw::FORMAT_A8B8G8R8; case GL_RGBA8UI: case GL_RGBA_INTEGER: return sw::FORMAT_A8B8G8R8UI; case GL_BGRA_EXT: case GL_BGRA8_EXT: return sw::FORMAT_A8R8G8B8; case GL_ALPHA: case GL_ALPHA8_EXT: return sw::FORMAT_A8; case SW_YV12_BT601: return sw::FORMAT_YV12_BT601; case SW_YV12_BT709: return sw::FORMAT_YV12_BT709; case SW_YV12_JFIF: return sw::FORMAT_YV12_JFIF; default: UNREACHABLE(format); } case GL_SHORT: switch(format) { case GL_R16I: case GL_RED_INTEGER: return sw::FORMAT_R16I; case GL_RG16I: case GL_RG_INTEGER: return sw::FORMAT_G16R16I; case GL_RGB16I: case GL_RGB_INTEGER: return sw::FORMAT_X16B16G16R16I; case GL_RGBA16I: case GL_RGBA_INTEGER: return sw::FORMAT_A16B16G16R16I; default: UNREACHABLE(format); } case GL_UNSIGNED_SHORT: switch(format) { case GL_R16UI: case GL_RED_INTEGER: return sw::FORMAT_R16UI; case GL_RG16UI: case GL_RG_INTEGER: return sw::FORMAT_G16R16UI; case GL_RGB16UI: case GL_RGB_INTEGER: return sw::FORMAT_X16B16G16R16UI; case GL_RGBA16UI: case GL_RGBA_INTEGER: return sw::FORMAT_A16B16G16R16UI; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16: return sw::FORMAT_D32FS8_TEXTURE; default: UNREACHABLE(format); } case GL_INT: switch(format) { case GL_RED_INTEGER: case GL_R32I: return sw::FORMAT_R32I; case GL_RG_INTEGER: case GL_RG32I: return sw::FORMAT_G32R32I; case GL_RGB_INTEGER: case GL_RGB32I: return sw::FORMAT_X32B32G32R32I; case GL_RGBA_INTEGER: case GL_RGBA32I: return sw::FORMAT_A32B32G32R32I; default: UNREACHABLE(format); } case GL_UNSIGNED_INT: switch(format) { case GL_RED_INTEGER: case GL_R32UI: return sw::FORMAT_R32UI; case GL_RG_INTEGER: case GL_RG32UI: return sw::FORMAT_G32R32UI; case GL_RGB_INTEGER: case GL_RGB32UI: return sw::FORMAT_X32B32G32R32UI; case GL_RGBA_INTEGER: case GL_RGBA32UI: return sw::FORMAT_A32B32G32R32UI; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32_OES: return sw::FORMAT_D32FS8_TEXTURE; default: UNREACHABLE(format); } case GL_UNSIGNED_INT_24_8_OES: if(format == GL_DEPTH_STENCIL || format == GL_DEPTH24_STENCIL8) { return sw::FORMAT_D32FS8_TEXTURE; } else UNREACHABLE(format); case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: if(format == GL_DEPTH_STENCIL || format == GL_DEPTH32F_STENCIL8) { return sw::FORMAT_D32FS8_TEXTURE; } else UNREACHABLE(format); case GL_UNSIGNED_SHORT_4_4_4_4: return sw::FORMAT_A8R8G8B8; case GL_UNSIGNED_SHORT_5_5_5_1: return sw::FORMAT_A8R8G8B8; case GL_UNSIGNED_SHORT_5_6_5: return sw::FORMAT_R5G6B5; case GL_UNSIGNED_INT_2_10_10_10_REV: if(format == GL_RGB10_A2UI) { return sw::FORMAT_A16B16G16R16UI; } else { return sw::FORMAT_A2B10G10R10; } case GL_UNSIGNED_INT_10F_11F_11F_REV: case GL_UNSIGNED_INT_5_9_9_9_REV: return sw::FORMAT_A32B32G32R32F; default: UNREACHABLE(type); } return sw::FORMAT_NULL; } // Returns the size, in bytes, of a single texel in an Image static int ComputePixelSize(GLenum format, GLenum type) { switch(type) { case GL_BYTE: switch(format) { case GL_R8: case GL_R8I: case GL_R8_SNORM: case GL_RED: return sizeof(char); case GL_RED_INTEGER: return sizeof(char); case GL_RG8: case GL_RG8I: case GL_RG8_SNORM: case GL_RG: return sizeof(char) * 2; case GL_RG_INTEGER: return sizeof(char) * 2; case GL_RGB8: case GL_RGB8I: case GL_RGB8_SNORM: case GL_RGB: return sizeof(char) * 3; case GL_RGB_INTEGER: return sizeof(char) * 3; case GL_RGBA8: case GL_RGBA8I: case GL_RGBA8_SNORM: case GL_RGBA: return sizeof(char) * 4; case GL_RGBA_INTEGER: return sizeof(char) * 4; default: UNREACHABLE(format); } break; case GL_UNSIGNED_BYTE: switch(format) { case GL_R8: case GL_R8UI: case GL_RED: return sizeof(unsigned char); case GL_RED_INTEGER: return sizeof(unsigned char); case GL_ALPHA8_EXT: case GL_ALPHA: return sizeof(unsigned char); case GL_LUMINANCE8_EXT: case GL_LUMINANCE: return sizeof(unsigned char); case GL_LUMINANCE8_ALPHA8_EXT: case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2; case GL_RG8: case GL_RG8UI: case GL_RG: return sizeof(unsigned char) * 2; case GL_RG_INTEGER: return sizeof(unsigned char) * 2; case GL_RGB8: case GL_RGB8UI: case GL_SRGB8: case GL_RGB: return sizeof(unsigned char) * 3; case GL_RGB_INTEGER: return sizeof(unsigned char) * 3; case GL_RGBA8: case GL_RGBA8UI: case GL_SRGB8_ALPHA8: case GL_RGBA: return sizeof(unsigned char) * 4; case GL_RGBA_INTEGER: return sizeof(unsigned char) * 4; case GL_BGRA_EXT: case GL_BGRA8_EXT: return sizeof(unsigned char)* 4; default: UNREACHABLE(format); } break; case GL_SHORT: switch(format) { case GL_R16I: case GL_RED_INTEGER: return sizeof(short); case GL_RG16I: case GL_RG_INTEGER: return sizeof(short) * 2; case GL_RGB16I: case GL_RGB_INTEGER: return sizeof(short) * 3; case GL_RGBA16I: case GL_RGBA_INTEGER: return sizeof(short) * 4; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT: switch(format) { case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT: return sizeof(unsigned short); case GL_R16UI: case GL_RED_INTEGER: return sizeof(unsigned short); case GL_RG16UI: case GL_RG_INTEGER: return sizeof(unsigned short) * 2; case GL_RGB16UI: case GL_RGB_INTEGER: return sizeof(unsigned short) * 3; case GL_RGBA16UI: case GL_RGBA_INTEGER: return sizeof(unsigned short) * 4; default: UNREACHABLE(format); } break; case GL_INT: switch(format) { case GL_R32I: case GL_RED_INTEGER: return sizeof(int); case GL_RG32I: case GL_RG_INTEGER: return sizeof(int) * 2; case GL_RGB32I: case GL_RGB_INTEGER: return sizeof(int) * 3; case GL_RGBA32I: case GL_RGBA_INTEGER: return sizeof(int) * 4; default: UNREACHABLE(format); } 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 sizeof(unsigned int); case GL_R32UI: case GL_RED_INTEGER: return sizeof(unsigned int); case GL_RG32UI: case GL_RG_INTEGER: return sizeof(unsigned int) * 2; case GL_RGB32UI: case GL_RGB_INTEGER: return sizeof(unsigned int) * 3; case GL_RGBA32UI: case GL_RGBA_INTEGER: return sizeof(unsigned int) * 4; default: UNREACHABLE(format); } 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 sizeof(unsigned short); 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 sizeof(unsigned int); case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return sizeof(float) + sizeof(unsigned int); case GL_FLOAT: switch(format) { case GL_DEPTH_COMPONENT32F: case GL_DEPTH_COMPONENT: return sizeof(float); case GL_ALPHA32F_EXT: case GL_ALPHA: return sizeof(float); case GL_LUMINANCE32F_EXT: case GL_LUMINANCE: return sizeof(float); case GL_LUMINANCE_ALPHA32F_EXT: case GL_LUMINANCE_ALPHA: return sizeof(float) * 2; case GL_RED: return sizeof(float); case GL_R32F: return sizeof(float); case GL_RG: return sizeof(float) * 2; case GL_RG32F: return sizeof(float) * 2; case GL_RGB: return sizeof(float) * 3; case GL_RGB32F: return sizeof(float) * 3; case GL_RGBA: return sizeof(float) * 4; case GL_RGBA32F: return sizeof(float) * 4; default: UNREACHABLE(format); } break; case GL_HALF_FLOAT: case GL_HALF_FLOAT_OES: switch(format) { case GL_ALPHA16F_EXT: case GL_ALPHA: return sizeof(unsigned short); case GL_LUMINANCE16F_EXT: case GL_LUMINANCE: return sizeof(unsigned short); case GL_LUMINANCE_ALPHA16F_EXT: case GL_LUMINANCE_ALPHA: return sizeof(unsigned short) * 2; case GL_RED: return sizeof(unsigned short); case GL_R16F: return sizeof(unsigned short); case GL_RG: return sizeof(unsigned short) * 2; case GL_RG16F: return sizeof(unsigned short) * 2; case GL_RGB: return sizeof(unsigned short) * 3; case GL_RGB16F: return sizeof(unsigned short) * 3; case GL_RGBA: return sizeof(unsigned short) * 4; case GL_RGBA16F: return sizeof(unsigned short) * 4; default: UNREACHABLE(format); } break; default: UNREACHABLE(type); } return 0; } GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment) { ASSERT(alignment > 0 && sw::isPow2(alignment)); GLsizei rawPitch = ComputePixelSize(format, type) * width; return (rawPitch + alignment - 1) & ~(alignment - 1); } size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, GLint alignment, GLint skipImages, GLint skipRows, GLint skipPixels) { GLsizei pitchB = ComputePitch(width, format, type, alignment); return (skipImages * height + skipRows) * pitchB + skipPixels * ComputePixelSize(format, type); } inline GLsizei ComputeCompressedPitch(GLsizei width, GLenum format) { return ComputeCompressedSize(width, 1, format); } GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format) { switch(format) { case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case GL_ETC1_RGB8_OES: case GL_COMPRESSED_R11_EAC: case GL_COMPRESSED_SIGNED_R11_EAC: case GL_COMPRESSED_RGB8_ETC2: case GL_COMPRESSED_SRGB8_ETC2: case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: return 8 * getNumBlocks(width, height, 4, 4); case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: case GL_COMPRESSED_RG11_EAC: case GL_COMPRESSED_SIGNED_RG11_EAC: case GL_COMPRESSED_RGBA8_ETC2_EAC: case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: return 16 * getNumBlocks(width, height, 4, 4); case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: return 16 * getNumBlocks(width, height, 5, 4); case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: return 16 * getNumBlocks(width, height, 5, 5); case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: return 16 * getNumBlocks(width, height, 6, 5); case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: return 16 * getNumBlocks(width, height, 6, 6); case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: return 16 * getNumBlocks(width, height, 8, 5); case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: return 16 * getNumBlocks(width, height, 8, 6); case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: return 16 * getNumBlocks(width, height, 8, 8); case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: return 16 * getNumBlocks(width, height, 10, 5); case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: return 16 * getNumBlocks(width, height, 10, 6); case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: return 16 * getNumBlocks(width, height, 10, 8); case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: return 16 * getNumBlocks(width, height, 10, 10); case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: return 16 * getNumBlocks(width, height, 12, 10); case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: return 16 * getNumBlocks(width, height, 12, 12); default: return 0; } } class ImageImplementation : public Image { public: ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type) : Image(parentTexture, width, height, format, type) {} ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type) : Image(parentTexture, width, height, depth, format, type) {} ImageImplementation(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP) : Image(width, height, format, type, pitchP) {} ImageImplementation(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable) : Image(width, height, internalFormat, multiSampleDepth, lockable) {} ~ImageImplementation() override { sync(); // Wait for any threads that use this image to finish. } void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override { return Image::lockInternal(x, y, z, lock, client); } void unlockInternal() override { return Image::unlockInternal(); } void release() override { return Image::release(); } }; Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type) { return new ImageImplementation(parentTexture, width, height, format, type); } Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type) { return new ImageImplementation(parentTexture, width, height, depth, format, type); } Image *Image::create(GLsizei width, GLsizei height, GLenum format, GLenum type, int pitchP) { return new ImageImplementation(width, height, format, type, pitchP); } Image *Image::create(GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable) { return new ImageImplementation(width, height, internalFormat, multiSampleDepth, lockable); } Image::~Image() { // sync() must be called in the destructor of the most derived class to ensure their vtable isn't destroyed // before all threads are done using this image. Image itself is abstract so it can't be the most derived. ASSERT(isUnlocked()); if(parentTexture) { parentTexture->release(); } ASSERT(!shared); } void *Image::lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) { return Surface::lockInternal(x, y, z, lock, client); } void Image::unlockInternal() { Surface::unlockInternal(); } void Image::release() { int refs = dereference(); if(refs > 0) { if(parentTexture) { parentTexture->sweep(); } } else { delete this; } } void Image::unbind(const egl::Texture *parent) { if(parentTexture == parent) { parentTexture = nullptr; } release(); } bool Image::isChildOf(const egl::Texture *parent) const { return parentTexture == parent; } void Image::loadImageData(Context *context, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const UnpackInfo& unpackInfo, const void *input) { sw::Format selectedInternalFormat = SelectInternalFormat(format, type); if(selectedInternalFormat == sw::FORMAT_NULL) { return; } GLsizei inputWidth = (unpackInfo.rowLength == 0) ? width : unpackInfo.rowLength; GLsizei inputPitch = ComputePitch(inputWidth, format, type, unpackInfo.alignment); GLsizei inputHeight = (unpackInfo.imageHeight == 0) ? height : unpackInfo.imageHeight; input = ((char*)input) + ComputePackingOffset(format, type, inputWidth, inputHeight, unpackInfo.alignment, unpackInfo.skipImages, unpackInfo.skipRows, unpackInfo.skipPixels); if(selectedInternalFormat == internalFormat) { void *buffer = lock(0, 0, sw::LOCK_WRITEONLY); if(buffer) { switch(type) { case GL_BYTE: switch(format) { case GL_R8: case GL_R8I: case GL_R8_SNORM: case GL_RED: case GL_RED_INTEGER: case GL_ALPHA: case GL_ALPHA8_EXT: case GL_LUMINANCE: case GL_LUMINANCE8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG8: case GL_RG8I: case GL_RG8_SNORM: case GL_RG: case GL_RG_INTEGER: case GL_LUMINANCE_ALPHA: case GL_LUMINANCE8_ALPHA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB8: case GL_RGB8I: case GL_RGB8_SNORM: case GL_RGB: case GL_RGB_INTEGER: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA8: case GL_RGBA8I: case GL_RGBA8_SNORM: case GL_RGBA: case GL_RGBA_INTEGER: case GL_BGRA_EXT: case GL_BGRA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_BYTE: switch(format) { case GL_R8: case GL_R8UI: case GL_R8_SNORM: case GL_RED: case GL_RED_INTEGER: case GL_ALPHA: case GL_ALPHA8_EXT: case GL_LUMINANCE: case GL_LUMINANCE8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG8: case GL_RG8UI: case GL_RG8_SNORM: case GL_RG: case GL_RG_INTEGER: case GL_LUMINANCE_ALPHA: case GL_LUMINANCE8_ALPHA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB8: case GL_RGB8UI: case GL_RGB8_SNORM: case GL_RGB: case GL_RGB_INTEGER: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA8: case GL_RGBA8UI: case GL_RGBA8_SNORM: case GL_RGBA: case GL_RGBA_INTEGER: case GL_BGRA_EXT: case GL_BGRA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_SRGB8: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_SRGB8_ALPHA8: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT_5_6_5: switch(format) { case GL_RGB565: case GL_RGB: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT_4_4_4_4: switch(format) { case GL_RGBA4: case GL_RGBA: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT_5_5_5_1: switch(format) { case GL_RGB5_A1: case GL_RGBA: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_INT_10F_11F_11F_REV: switch(format) { case GL_R11F_G11F_B10F: case GL_RGB: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_INT_5_9_9_9_REV: switch(format) { case GL_RGB9_E5: case GL_RGB: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_INT_2_10_10_10_REV: switch(format) { case GL_RGB10_A2UI: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB10_A2: case GL_RGBA: case GL_RGBA_INTEGER: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_FLOAT: switch(format) { // float textures are converted to RGBA, not BGRA case GL_ALPHA: case GL_ALPHA32F_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_LUMINANCE: case GL_LUMINANCE32F_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE_ALPHA32F_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RED: case GL_R32F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG: case GL_RG32F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB: case GL_RGB32F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA: case GL_RGBA32F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT32F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_HALF_FLOAT: case GL_HALF_FLOAT_OES: switch(format) { case GL_ALPHA: case GL_ALPHA16F_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_LUMINANCE: case GL_LUMINANCE16F_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_LUMINANCE_ALPHA: case GL_LUMINANCE_ALPHA16F_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RED: case GL_R16F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG: case GL_RG16F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB: case GL_RGB16F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA: case GL_RGBA16F: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_SHORT: switch(format) { case GL_R16I: case GL_RED: case GL_RED_INTEGER: case GL_ALPHA: case GL_LUMINANCE: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG16I: case GL_RG: case GL_RG_INTEGER: case GL_LUMINANCE_ALPHA: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB16I: case GL_RGB: case GL_RGB_INTEGER: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA16I: case GL_RGBA: case GL_RGBA_INTEGER: case GL_BGRA_EXT: case GL_BGRA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT: switch(format) { case GL_R16UI: case GL_RED: case GL_RED_INTEGER: case GL_ALPHA: case GL_LUMINANCE: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG16UI: case GL_RG: case GL_RG_INTEGER: case GL_LUMINANCE_ALPHA: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB16UI: case GL_RGB: case GL_RGB_INTEGER: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA16UI: case GL_RGBA: case GL_RGBA_INTEGER: case GL_BGRA_EXT: case GL_BGRA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT16: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_INT: switch(format) { case GL_R32I: case GL_RED: case GL_RED_INTEGER: case GL_ALPHA: case GL_LUMINANCE: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG32I: case GL_RG: case GL_RG_INTEGER: case GL_LUMINANCE_ALPHA: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB32I: case GL_RGB: case GL_RGB_INTEGER: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA32I: case GL_RGBA: case GL_RGBA_INTEGER: case GL_BGRA_EXT: case GL_BGRA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_INT: switch(format) { case GL_R32UI: case GL_RED: case GL_RED_INTEGER: case GL_ALPHA: case GL_LUMINANCE: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RG32UI: case GL_RG: case GL_RG_INTEGER: case GL_LUMINANCE_ALPHA: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGB32UI: case GL_RGB: case GL_RGB_INTEGER: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_RGBA32UI: case GL_RGBA: case GL_RGBA_INTEGER: case GL_BGRA_EXT: case GL_BGRA8_EXT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32_OES: case GL_DEPTH_COMPONENT: LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_INT_24_8_OES: loadD24S8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer); break; case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: loadD32FS8ImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, input, buffer); break; default: UNREACHABLE(type); } } unlock(); } else { sw::Surface *source = sw::Surface::create(width, height, depth, ConvertFormatType(format, type), const_cast(input), inputPitch, inputPitch * inputHeight); sw::Rect sourceRect(0, 0, width, height); sw::Rect destRect(xoffset, yoffset, xoffset + width, yoffset + height); context->blit(source, sourceRect, this, destRect); delete source; } } void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer) { LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); unsigned char *stencil = reinterpret_cast(lockStencil(0, 0, 0, sw::PUBLIC)); if(stencil) { LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil); unlockStencil(); } } void Image::loadD32FS8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer) { LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); unsigned char *stencil = reinterpret_cast(lockStencil(0, 0, 0, sw::PUBLIC)); if(stencil) { LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil); unlockStencil(); } } void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) { if(zoffset != 0 || depth != 1) { UNIMPLEMENTED(); // FIXME } int inputPitch = ComputeCompressedPitch(width, format); int rows = imageSize / inputPitch; void *buffer = lock(xoffset, yoffset, sw::LOCK_WRITEONLY); if(buffer) { for(int i = 0; i < rows; i++) { memcpy((void*)((GLbyte*)buffer + i * getPitch()), (void*)((GLbyte*)pixels + i * inputPitch), inputPitch); } } unlock(); } }