X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2FOpenGL%2Fcommon%2FImage.cpp;h=601876ef50ff3474020c523f0475bcbafb68f525;hb=607771b444748a7c1e5a6e4f8220053559870728;hp=2b4d97eaa70c0f5f44ddfc3090092a24aa6904d7;hpb=1c6f53c9027b6fbac27f58a1d510e2052f98149a;p=android-x86%2Fexternal-swiftshader.git diff --git a/src/OpenGL/common/Image.cpp b/src/OpenGL/common/Image.cpp index 2b4d97eaa..601876ef5 100644 --- a/src/OpenGL/common/Image.cpp +++ b/src/OpenGL/common/Image.cpp @@ -1,17 +1,19 @@ -// SwiftShader Software Renderer +// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // -// Copyright(c) 2005-2013 TransGaming Inc. +// 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 // -// All rights reserved. No part of this software may be copied, distributed, transmitted, -// transcribed, stored in a retrieval system, translated into any human or computer -// language by any means, or disclosed to third parties without the explicit written -// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express -// or implied, including but not limited to any patent rights, are granted to you. +// 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 "Renderer/Blitter.hpp" #include "../libEGL/Texture.hpp" #include "../common/debug.h" #include "Common/Math.hpp" @@ -20,129 +22,817 @@ #include #include +#include -namespace +#if defined(__APPLE__) +#include +#include +#endif + +namespace gl { - int getNumBlocks(int w, int h, int blockSizeX, int blockSizeY) + sw::Format ConvertReadFormatType(GLenum format, GLenum type) { - return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY); + 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_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_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; + case GL_UNSIGNED_INT_2_10_10_10_REV_EXT: return sw::FORMAT_A2B10G10R10; + default: UNREACHABLE(type); + } + break; + case GL_BGRA_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_RG: + switch(type) + { + case GL_UNSIGNED_BYTE: return sw::FORMAT_G8R8; + case GL_HALF_FLOAT: return sw::FORMAT_G16R16F; + case GL_HALF_FLOAT_OES: return sw::FORMAT_G16R16F; + case GL_FLOAT: return sw::FORMAT_G32R32F; + default: UNREACHABLE(type); + } + break; + case GL_RED: + switch(type) + { + case GL_UNSIGNED_BYTE: return sw::FORMAT_R8; + case GL_HALF_FLOAT: return sw::FORMAT_R16F; + case GL_HALF_FLOAT_OES: return sw::FORMAT_R16F; + case GL_FLOAT: return sw::FORMAT_R32F; + 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_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_RGB_INTEGER: + switch(type) + { + case GL_INT: return sw::FORMAT_X32B32G32R32I; + case GL_UNSIGNED_INT: return sw::FORMAT_X32B32G32R32UI; + 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; + case GL_UNSIGNED_INT_2_10_10_10_REV: return sw::FORMAT_A2B10G10R10UI; + 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_LOCKABLE; + default: UNREACHABLE(type); + } + break; + default: + UNREACHABLE(format); + break; + } + + return sw::FORMAT_NULL; } - 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, - }; + bool IsUnsizedInternalFormat(GLint internalformat) + { + switch(internalformat) + { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_RED: + case GL_RG: + case GL_RGB: + case GL_RGBA: + case GL_RED_INTEGER: + case GL_RG_INTEGER: + case GL_RGB_INTEGER: + case GL_RGBA_INTEGER: + case GL_BGRA_EXT: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + // GL_EXT_sRGB + // case GL_SRGB_EXT: + // case GL_SRGB_ALPHA_EXT: + return true; + default: + return false; + } + } - template - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + GLenum GetBaseInternalFormat(GLint internalformat) { - UNIMPLEMENTED(); + switch(internalformat) + { + // [OpenGL ES 3.0 Table 3.13] + case GL_R8: return GL_RED; + case GL_R8_SNORM: return GL_RED; + case GL_RG8: return GL_RG; + case GL_RG8_SNORM: return GL_RG; + case GL_RGB8: return GL_RGB; + case GL_RGB8_SNORM: return GL_RGB; + case GL_RGB565: return GL_RGB; + case GL_RGBA4: return GL_RGBA; + case GL_RGB5_A1: return GL_RGBA; + case GL_RGBA8: return GL_RGBA; + case GL_RGBA8_SNORM: return GL_RGBA; + case GL_RGB10_A2: return GL_RGBA; + case GL_RGB10_A2UI: return GL_RGBA; + case GL_SRGB8: return GL_RGB; + case GL_SRGB8_ALPHA8: return GL_RGBA; + case GL_R16F: return GL_RED; + case GL_RG16F: return GL_RG; + case GL_RGB16F: return GL_RGB; + case GL_RGBA16F: return GL_RGBA; + case GL_R32F: return GL_RED; + case GL_RG32F: return GL_RG; + case GL_RGB32F: return GL_RGB; + case GL_RGBA32F: return GL_RGBA; + case GL_R11F_G11F_B10F: return GL_RGB; + case GL_RGB9_E5: return GL_RGB; + case GL_R8I: return GL_RED; + case GL_R8UI: return GL_RED; + case GL_R16I: return GL_RED; + case GL_R16UI: return GL_RED; + case GL_R32I: return GL_RED; + case GL_R32UI: return GL_RED; + case GL_RG8I: return GL_RG; + case GL_RG8UI: return GL_RG; + case GL_RG16I: return GL_RG; + case GL_RG16UI: return GL_RG; + case GL_RG32I: return GL_RG; + case GL_RG32UI: return GL_RG; + case GL_RGB8I: return GL_RGB; + case GL_RGB8UI: return GL_RGB; + case GL_RGB16I: return GL_RGB; + case GL_RGB16UI: return GL_RGB; + case GL_RGB32I: return GL_RGB; + case GL_RGB32UI: return GL_RGB; + case GL_RGBA8I: return GL_RGBA; + case GL_RGBA8UI: return GL_RGBA; + case GL_RGBA16I: return GL_RGBA; + case GL_RGBA16UI: return GL_RGBA; + case GL_RGBA32I: return GL_RGBA; + case GL_RGBA32UI: return GL_RGBA; + + // GL_EXT_texture_storage + case GL_ALPHA8_EXT: return GL_ALPHA; + case GL_LUMINANCE8_EXT: return GL_LUMINANCE; + case GL_LUMINANCE8_ALPHA8_EXT: return GL_LUMINANCE_ALPHA; + case GL_ALPHA32F_EXT: return GL_ALPHA; + case GL_LUMINANCE32F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA32F_EXT: return GL_LUMINANCE_ALPHA; + case GL_ALPHA16F_EXT: return GL_ALPHA; + case GL_LUMINANCE16F_EXT: return GL_LUMINANCE; + case GL_LUMINANCE_ALPHA16F_EXT: return GL_LUMINANCE_ALPHA; + + case GL_BGRA8_EXT: return GL_BGRA_EXT; // GL_APPLE_texture_format_BGRA8888 + + case GL_DEPTH_COMPONENT24: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT32_OES: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT32F: return GL_DEPTH_COMPONENT; + case GL_DEPTH_COMPONENT16: return GL_DEPTH_COMPONENT; + case GL_DEPTH32F_STENCIL8: return GL_DEPTH_STENCIL; + case GL_DEPTH24_STENCIL8: return GL_DEPTH_STENCIL; + case GL_STENCIL_INDEX8: return GL_STENCIL_INDEX_OES; + default: + UNREACHABLE(internalformat); + break; + } + + return GL_NONE; } - template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + GLint GetSizedInternalFormat(GLint internalformat, GLenum type) + { + if(!IsUnsizedInternalFormat(internalformat)) + { + return internalformat; + } + + switch(internalformat) + { + case GL_RGBA: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_RGBA8; + case GL_BYTE: return GL_RGBA8_SNORM; + case GL_UNSIGNED_SHORT_4_4_4_4: return GL_RGBA4; + case GL_UNSIGNED_SHORT_5_5_5_1: return GL_RGB5_A1; + case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_RGB10_A2; + case GL_FLOAT: return GL_RGBA32F; + case GL_HALF_FLOAT: return GL_RGBA16F; + case GL_HALF_FLOAT_OES: return GL_RGBA16F; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_RGBA_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_RGBA8UI; + case GL_BYTE: return GL_RGBA8I; + case GL_UNSIGNED_SHORT: return GL_RGBA16UI; + case GL_SHORT: return GL_RGBA16I; + case GL_UNSIGNED_INT: return GL_RGBA32UI; + case GL_INT: return GL_RGBA32I; + case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_RGB10_A2UI; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_RGB: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_RGB8; + case GL_BYTE: return GL_RGB8_SNORM; + case GL_UNSIGNED_SHORT_5_6_5: return GL_RGB565; + case GL_UNSIGNED_INT_10F_11F_11F_REV: return GL_R11F_G11F_B10F; + case GL_UNSIGNED_INT_5_9_9_9_REV: return GL_RGB9_E5; + case GL_FLOAT: return GL_RGB32F; + case GL_HALF_FLOAT: return GL_RGB16F; + case GL_HALF_FLOAT_OES: return GL_RGB16F; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_RGB_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_RGB8UI; + case GL_BYTE: return GL_RGB8I; + case GL_UNSIGNED_SHORT: return GL_RGB16UI; + case GL_SHORT: return GL_RGB16I; + case GL_UNSIGNED_INT: return GL_RGB32UI; + case GL_INT: return GL_RGB32I; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_RG: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_RG8; + case GL_BYTE: return GL_RG8_SNORM; + case GL_FLOAT: return GL_RG32F; + case GL_HALF_FLOAT: return GL_RG16F; + case GL_HALF_FLOAT_OES: return GL_RG16F; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_RG_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_RG8UI; + case GL_BYTE: return GL_RG8I; + case GL_UNSIGNED_SHORT: return GL_RG16UI; + case GL_SHORT: return GL_RG16I; + case GL_UNSIGNED_INT: return GL_RG32UI; + case GL_INT: return GL_RG32I; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_RED: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_R8; + case GL_BYTE: return GL_R8_SNORM; + case GL_FLOAT: return GL_R32F; + case GL_HALF_FLOAT: return GL_R16F; + case GL_HALF_FLOAT_OES: return GL_R16F; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_RED_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_R8UI; + case GL_BYTE: return GL_R8I; + case GL_UNSIGNED_SHORT: return GL_R16UI; + case GL_SHORT: return GL_R16I; + case GL_UNSIGNED_INT: return GL_R32UI; + case GL_INT: return GL_R32I; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_LUMINANCE_ALPHA: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_ALPHA8_EXT; + case GL_FLOAT: return GL_LUMINANCE_ALPHA32F_EXT; + case GL_HALF_FLOAT: return GL_LUMINANCE_ALPHA16F_EXT; + case GL_HALF_FLOAT_OES: return GL_LUMINANCE_ALPHA16F_EXT; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_LUMINANCE: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_LUMINANCE8_EXT; + case GL_FLOAT: return GL_LUMINANCE32F_EXT; + case GL_HALF_FLOAT: return GL_LUMINANCE16F_EXT; + case GL_HALF_FLOAT_OES: return GL_LUMINANCE16F_EXT; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_ALPHA: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_ALPHA8_EXT; + case GL_FLOAT: return GL_ALPHA32F_EXT; + case GL_HALF_FLOAT: return GL_ALPHA16F_EXT; + case GL_HALF_FLOAT_OES: return GL_ALPHA16F_EXT; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_BGRA_EXT: + switch(type) + { + case GL_UNSIGNED_BYTE: return GL_BGRA8_EXT; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: // Only valid for glReadPixels calls. + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: // Only valid for glReadPixels calls. + default: UNREACHABLE(type); return GL_NONE; + } + case GL_DEPTH_COMPONENT: + switch(type) + { + case GL_UNSIGNED_SHORT: return GL_DEPTH_COMPONENT16; + case GL_UNSIGNED_INT: return GL_DEPTH_COMPONENT32_OES; + case GL_FLOAT: return GL_DEPTH_COMPONENT32F; + default: UNREACHABLE(type); return GL_NONE; + } + case GL_DEPTH_STENCIL: + switch(type) + { + case GL_UNSIGNED_INT_24_8: return GL_DEPTH24_STENCIL8; + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return GL_DEPTH32F_STENCIL8; + default: UNREACHABLE(type); return GL_NONE; + } + + // GL_OES_texture_stencil8 + // case GL_STENCIL_INDEX_OES / GL_UNSIGNED_BYTE: return GL_STENCIL_INDEX8; + + // GL_EXT_sRGB + // case GL_SRGB_EXT / GL_UNSIGNED_BYTE: return GL_SRGB8; + // case GL_SRGB_ALPHA_EXT / GL_UNSIGNED_BYTE: return GL_SRGB8_ALPHA8; + + default: + UNREACHABLE(internalformat); + } + + return GL_NONE; + } + + sw::Format SelectInternalFormat(GLint format) { - memcpy(dest + xoffset, source, width); + switch(format) + { + case GL_RGBA4: return sw::FORMAT_A8B8G8R8; + case GL_RGB5_A1: return sw::FORMAT_A8B8G8R8; + case GL_RGBA8: return sw::FORMAT_A8B8G8R8; + case GL_RGB565: return sw::FORMAT_R5G6B5; + case GL_RGB8: return sw::FORMAT_X8B8G8R8; + + case GL_DEPTH_COMPONENT32F: return sw::FORMAT_D32F_LOCKABLE; + case GL_DEPTH_COMPONENT16: return sw::FORMAT_D32F_LOCKABLE; + case GL_DEPTH_COMPONENT24: return sw::FORMAT_D32F_LOCKABLE; + case GL_DEPTH_COMPONENT32_OES: return sw::FORMAT_D32F_LOCKABLE; + case GL_DEPTH24_STENCIL8: return sw::FORMAT_D32FS8_TEXTURE; + case GL_DEPTH32F_STENCIL8: return sw::FORMAT_D32FS8_TEXTURE; + case GL_STENCIL_INDEX8: return sw::FORMAT_S8; + + case GL_R8: return sw::FORMAT_R8; + case GL_RG8: return sw::FORMAT_G8R8; + case GL_R8I: return sw::FORMAT_R8I; + case GL_RG8I: return sw::FORMAT_G8R8I; + case GL_RGB8I: return sw::FORMAT_X8B8G8R8I; + case GL_RGBA8I: return sw::FORMAT_A8B8G8R8I; + case GL_R8UI: return sw::FORMAT_R8UI; + case GL_RG8UI: return sw::FORMAT_G8R8UI; + case GL_RGB8UI: return sw::FORMAT_X8B8G8R8UI; + case GL_RGBA8UI: return sw::FORMAT_A8B8G8R8UI; + case GL_R16I: return sw::FORMAT_R16I; + case GL_RG16I: return sw::FORMAT_G16R16I; + case GL_RGB16I: return sw::FORMAT_X16B16G16R16I; + case GL_RGBA16I: return sw::FORMAT_A16B16G16R16I; + case GL_R16UI: return sw::FORMAT_R16UI; + case GL_RG16UI: return sw::FORMAT_G16R16UI; + case GL_RGB16UI: return sw::FORMAT_X16B16G16R16UI; + case GL_RGBA16UI: return sw::FORMAT_A16B16G16R16UI; + case GL_R32I: return sw::FORMAT_R32I; + case GL_RG32I: return sw::FORMAT_G32R32I; + case GL_RGB32I: return sw::FORMAT_X32B32G32R32I; + case GL_RGBA32I: return sw::FORMAT_A32B32G32R32I; + case GL_R32UI: return sw::FORMAT_R32UI; + case GL_RG32UI: return sw::FORMAT_G32R32UI; + case GL_RGB32UI: return sw::FORMAT_X32B32G32R32UI; + case GL_RGBA32UI: return sw::FORMAT_A32B32G32R32UI; + case GL_R16F: return sw::FORMAT_R16F; + case GL_RG16F: return sw::FORMAT_G16R16F; + case GL_R11F_G11F_B10F: return sw::FORMAT_X16B16G16R16F_UNSIGNED; + case GL_RGB16F: return sw::FORMAT_X16B16G16R16F; + case GL_RGBA16F: return sw::FORMAT_A16B16G16R16F; + case GL_R32F: return sw::FORMAT_R32F; + case GL_RG32F: return sw::FORMAT_G32R32F; + case GL_RGB32F: return sw::FORMAT_X32B32G32R32F; + case GL_RGBA32F: return sw::FORMAT_A32B32G32R32F; + case GL_RGB10_A2: return sw::FORMAT_A2B10G10R10; + case GL_RGB10_A2UI: return sw::FORMAT_A2B10G10R10UI; + case GL_SRGB8: return sw::FORMAT_SRGB8_X8; + case GL_SRGB8_ALPHA8: return sw::FORMAT_SRGB8_A8; + + 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; + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return sw::FORMAT_DXT1; + 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; + + case GL_ALPHA32F_EXT: return sw::FORMAT_A32F; + case GL_LUMINANCE32F_EXT: return sw::FORMAT_L32F; + case GL_LUMINANCE_ALPHA32F_EXT: return sw::FORMAT_A32L32F; + case GL_RGB9_E5: return sw::FORMAT_X16B16G16R16F_UNSIGNED; + case GL_ALPHA16F_EXT: return sw::FORMAT_A16F; + case GL_LUMINANCE16F_EXT: return sw::FORMAT_L16F; + case GL_LUMINANCE_ALPHA16F_EXT: return sw::FORMAT_A16L16F; + case GL_R8_SNORM: return sw::FORMAT_R8_SNORM; + case GL_RG8_SNORM: return sw::FORMAT_G8R8_SNORM; + case GL_RGB8_SNORM: return sw::FORMAT_X8B8G8R8_SNORM; + case GL_RGBA8_SNORM: return sw::FORMAT_A8B8G8R8_SNORM; + case GL_LUMINANCE8_EXT: return sw::FORMAT_L8; + case GL_LUMINANCE8_ALPHA8_EXT: return sw::FORMAT_A8L8; + case GL_BGRA8_EXT: return sw::FORMAT_A8R8G8B8; + 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); // Not a sized internal format. + return sw::FORMAT_NULL; + } } - template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + // Returns the size, in bytes, of a single client-side pixel. + // OpenGL ES 3.0.5 table 3.2. + static int ComputePixelSize(GLenum format, GLenum type) { - memcpy(dest + xoffset * 2, source, width * 2); + switch(format) + { + case GL_RED: + case GL_RED_INTEGER: + case GL_ALPHA: + case GL_LUMINANCE: + switch(type) + { + case GL_BYTE: return 1; + case GL_UNSIGNED_BYTE: return 1; + case GL_FLOAT: return 4; + case GL_HALF_FLOAT: return 2; + case GL_HALF_FLOAT_OES: return 2; + case GL_SHORT: return 2; + case GL_UNSIGNED_SHORT: return 2; + case GL_INT: return 4; + case GL_UNSIGNED_INT: return 4; + default: UNREACHABLE(type); + } + break; + case GL_RG: + case GL_RG_INTEGER: + case GL_LUMINANCE_ALPHA: + switch(type) + { + case GL_BYTE: return 2; + case GL_UNSIGNED_BYTE: return 2; + case GL_FLOAT: return 8; + case GL_HALF_FLOAT: return 4; + case GL_HALF_FLOAT_OES: return 4; + case GL_SHORT: return 4; + case GL_UNSIGNED_SHORT: return 4; + case GL_INT: return 8; + case GL_UNSIGNED_INT: return 8; + default: UNREACHABLE(type); + } + break; + case GL_RGB: + case GL_RGB_INTEGER: + switch(type) + { + case GL_BYTE: return 3; + case GL_UNSIGNED_BYTE: return 3; + case GL_UNSIGNED_SHORT_5_6_5: return 2; + case GL_UNSIGNED_INT_10F_11F_11F_REV: return 4; + case GL_UNSIGNED_INT_5_9_9_9_REV: return 4; + case GL_FLOAT: return 12; + case GL_HALF_FLOAT: return 6; + case GL_HALF_FLOAT_OES: return 6; + case GL_SHORT: return 6; + case GL_UNSIGNED_SHORT: return 6; + case GL_INT: return 12; + case GL_UNSIGNED_INT: return 12; + default: UNREACHABLE(type); + } + break; + case GL_RGBA: + case GL_RGBA_INTEGER: + case GL_BGRA_EXT: + switch(type) + { + case GL_BYTE: return 4; + case GL_UNSIGNED_BYTE: return 4; + case GL_UNSIGNED_SHORT_4_4_4_4: return 2; + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: return 2; + case GL_UNSIGNED_SHORT_5_5_5_1: return 2; + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: return 2; + case GL_UNSIGNED_INT_2_10_10_10_REV: return 4; + case GL_FLOAT: return 16; + case GL_HALF_FLOAT: return 8; + case GL_HALF_FLOAT_OES: return 8; + case GL_SHORT: return 8; + case GL_UNSIGNED_SHORT: return 8; + case GL_INT: return 16; + case GL_UNSIGNED_INT: return 16; + default: UNREACHABLE(type); + } + break; + case GL_DEPTH_COMPONENT: + switch(type) + { + case GL_FLOAT: return 4; + case GL_UNSIGNED_SHORT: return 2; + case GL_UNSIGNED_INT: return 4; + default: UNREACHABLE(type); + } + break; + case GL_DEPTH_STENCIL: + switch(type) + { + case GL_UNSIGNED_INT_24_8: return 4; + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return 8; + default: UNREACHABLE(type); + } + break; + default: + UNREACHABLE(format); + } + + return 0; } - template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment) { - memcpy(dest + xoffset * 4, source, width * 4); + ASSERT(alignment > 0 && sw::isPow2(alignment)); + + GLsizei rawPitch = ComputePixelSize(format, type) * width; + return (rawPitch + alignment - 1) & ~(alignment - 1); } - template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + size_t ComputePackingOffset(GLenum format, GLenum type, GLsizei width, GLsizei height, const gl::PixelStorageModes &storageModes) { - memcpy(dest + xoffset * 8, source, width * 8); + GLsizei pitchB = ComputePitch(width, format, type, storageModes.alignment); + return (storageModes.skipImages * height + storageModes.skipRows) * pitchB + storageModes.skipPixels * ComputePixelSize(format, type); } - template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + inline GLsizei ComputeCompressedPitch(GLsizei width, GLenum format) { - memcpy(dest + xoffset * 16, source, width * 16); + return ComputeCompressedSize(width, 1, format); } - template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + inline int GetNumCompressedBlocks(int w, int h, int blockSizeX, int blockSizeY) { - unsigned char *destB = dest + xoffset * 4; + return ((w + blockSizeX - 1) / blockSizeX) * ((h + blockSizeY - 1) / blockSizeY); + } - for(int x = 0; x < width; x++) + GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format) + { + switch(format) { - 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; + 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 * GetNumCompressedBlocks(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 * GetNumCompressedBlocks(width, height, 4, 4); + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + return 16 * GetNumCompressedBlocks(width, height, 5, 4); + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + return 16 * GetNumCompressedBlocks(width, height, 5, 5); + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + return 16 * GetNumCompressedBlocks(width, height, 6, 5); + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + return 16 * GetNumCompressedBlocks(width, height, 6, 6); + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + return 16 * GetNumCompressedBlocks(width, height, 8, 5); + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + return 16 * GetNumCompressedBlocks(width, height, 8, 6); + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + return 16 * GetNumCompressedBlocks(width, height, 8, 8); + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + return 16 * GetNumCompressedBlocks(width, height, 10, 5); + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + return 16 * GetNumCompressedBlocks(width, height, 10, 6); + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + return 16 * GetNumCompressedBlocks(width, height, 10, 8); + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + return 16 * GetNumCompressedBlocks(width, height, 10, 10); + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + return 16 * GetNumCompressedBlocks(width, height, 12, 10); + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: + return 16 * GetNumCompressedBlocks(width, height, 12, 12); + default: + UNREACHABLE(format); + return 0; } } +} - template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) +namespace egl +{ + // We assume the data can be indexed with a signed 32-bit offset, including any padding, + // so we must keep the image size reasonable. 1 GiB ought to be enough for anybody. + enum { IMPLEMENTATION_MAX_IMAGE_SIZE_BYTES = 0x40000000 }; + + enum TransferType { - unsigned char *destB = dest + xoffset * 4; + Bytes, + RGB8toRGBX8, + RGB16toRGBX16, + RGB32toRGBX32, + RGB32FtoRGBX32F, + RGB16FtoRGBX16F, + RGBA4toRGBA8, + RGBA5_A1toRGBA8, + R11G11B10FtoRGBX16F, + RGB9_E5FtoRGBX16F, + D16toD32F, + D24X8toD32F, + D32toD32F, + D32FtoD32F_CLAMPED, + D32FX32toD32F, + X24S8toS8, + X56S8toS8, + RGBA1010102toRGBA8, + RGB8toRGB565, + R32FtoR16F, + RG32FtoRG16F, + RGB32FtoRGB16F, + RGB32FtoRGB16F_UNSIGNED, + RGBA32FtoRGBA16F + }; - 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 TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes); + + template<> + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) + { + memcpy(dest, source, width * bytes); } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { - const unsigned short *sourceS = reinterpret_cast(source); - unsigned short *destS = reinterpret_cast(dest + xoffset * 8); + unsigned char *destB = dest; 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; + 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) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned short *sourceS = reinterpret_cast(source); - unsigned short *destS = reinterpret_cast(dest + xoffset * 8); + unsigned short *destS = reinterpret_cast(dest); for(int x = 0; x < width; x++) { @@ -154,46 +844,25 @@ namespace } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned int *sourceI = reinterpret_cast(source); - unsigned int *destI = reinterpret_cast(dest + xoffset * 16); + unsigned int *destI = reinterpret_cast(dest); 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); + 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) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const float *sourceF = reinterpret_cast(source); - float *destF = reinterpret_cast(dest + xoffset * 16); + float *destF = reinterpret_cast(dest); for(int x = 0; x < width; x++) { @@ -205,129 +874,183 @@ namespace } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned short *sourceH = reinterpret_cast(source); - unsigned short *destH = reinterpret_cast(dest + xoffset * 8); + unsigned short *destH = reinterpret_cast(dest); 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 + destH[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16-bit floating-point representation of 1.0 } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned short *source4444 = reinterpret_cast(source); - unsigned char *dest4444 = dest + xoffset * 4; + unsigned char *dest4444 = dest; 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 + 0] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); dest4444[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); - dest4444[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + dest4444[4 * x + 2] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); dest4444[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned short *source5551 = reinterpret_cast(source); - unsigned char *dest5551 = dest + xoffset * 4; + unsigned char *dest8888 = dest; 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; + dest8888[4 * x + 0] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + dest8888[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); + dest8888[4 * x + 2] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); + dest8888[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; + } + } + + template<> + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) + { + const unsigned int *source1010102 = reinterpret_cast(source); + unsigned char *dest8888 = dest; + + for(int x = 0; x < width; x++) + { + unsigned int rgba = source1010102[x]; + dest8888[4 * x + 0] = sw::unorm<8>((rgba & 0x000003FF) * (1.0f / 0x000003FF)); + dest8888[4 * x + 1] = sw::unorm<8>((rgba & 0x000FFC00) * (1.0f / 0x000FFC00)); + dest8888[4 * x + 2] = sw::unorm<8>((rgba & 0x3FF00000) * (1.0f / 0x3FF00000)); + dest8888[4 * x + 3] = sw::unorm<8>((rgba & 0xC0000000) * (1.0f / 0xC0000000)); } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { - const unsigned int *source1010102U = reinterpret_cast(source); - unsigned short *dest16U = reinterpret_cast(dest + xoffset * 8); + unsigned short *dest565 = reinterpret_cast(dest); for(int x = 0; x < width; x++) { - unsigned int rgba = source1010102U[x]; - dest16U[4 * x + 0] = (rgba & 0x00000FFC) >> 2; - dest16U[4 * x + 1] = (rgba & 0x003FF000) >> 12; - dest16U[4 * x + 2] = (rgba & 0xFFC00000) >> 22; - dest16U[4 * x + 3] = (rgba & 0x00000003); + float r = source[3 * x + 0] * (1.0f / 0xFF); + float g = source[3 * x + 1] * (1.0f / 0xFF); + float b = source[3 * x + 2] * (1.0f / 0xFF); + dest565[x] = (sw::unorm<5>(r) << 11) | (sw::unorm<6>(g) << 5) | (sw::unorm<5>(b) << 0); } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { - const sw::R11G11B10FData *sourceRGB = reinterpret_cast(source); - float *destF = reinterpret_cast(dest + xoffset * 16); + const sw::R11G11B10F *sourceRGB = reinterpret_cast(source); + sw::half *destF = reinterpret_cast(dest); - for(int x = 0; x < width; x++, sourceRGB++, destF+=4) + for(int x = 0; x < width; x++, sourceRGB++, destF += 4) { - sourceRGB->toRGBFloats(destF); + sourceRGB->toRGB16F(destF); destF[3] = 1.0f; } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { - const sw::RGB9E5Data *sourceRGB = reinterpret_cast(source); - float *destF = reinterpret_cast(dest + xoffset * 16); + const sw::RGB9E5 *sourceRGB = reinterpret_cast(source); + sw::half *destF = reinterpret_cast(dest); for(int x = 0; x < width; x++, sourceRGB++, destF += 4) { - sourceRGB->toRGBFloats(destF); + sourceRGB->toRGB16F(destF); destF[3] = 1.0f; } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { - dest += xoffset * 4; + const float *source32F = reinterpret_cast(source); + sw::half *dest16F = reinterpret_cast(dest); for(int x = 0; x < width; x++) { - for(int rgb = 0; rgb < 3; ++rgb) - { - *dest++ = sw::sRGB8toLinear8(*source++); - } - *dest++ = 255; + dest16F[x] = source32F[x]; } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { - dest += xoffset * 4; + const float *source32F = reinterpret_cast(source); + sw::half *dest16F = reinterpret_cast(dest); for(int x = 0; x < width; x++) { - for(int rgb = 0; rgb < 3; ++rgb) - { - *dest++ = sw::sRGB8toLinear8(*source++); - } - *dest++ = *source++; + dest16F[2 * x + 0] = source32F[2 * x + 0]; + dest16F[2 * x + 1] = source32F[2 * x + 1]; + } + } + + template<> + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) + { + const float *source32F = reinterpret_cast(source); + sw::half *dest16F = reinterpret_cast(dest); + + for(int x = 0; x < width; x++) + { + dest16F[4 * x + 0] = source32F[3 * x + 0]; + dest16F[4 * x + 1] = source32F[3 * x + 1]; + dest16F[4 * x + 2] = source32F[3 * x + 2]; + dest16F[4 * x + 3] = 1.0f; + } + } + + template<> + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) + { + const float *source32F = reinterpret_cast(source); + sw::half *dest16F = reinterpret_cast(dest); + + for(int x = 0; x < width; x++) + { + dest16F[4 * x + 0] = std::max(source32F[3 * x + 0], 0.0f); + dest16F[4 * x + 1] = std::max(source32F[3 * x + 1], 0.0f); + dest16F[4 * x + 2] = std::max(source32F[3 * x + 2], 0.0f); + dest16F[4 * x + 3] = 1.0f; } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) + { + const float *source32F = reinterpret_cast(source); + sw::half *dest16F = reinterpret_cast(dest); + + for(int x = 0; x < width; x++) + { + dest16F[4 * x + 0] = source32F[4 * x + 0]; + dest16F[4 * x + 1] = source32F[4 * x + 1]; + dest16F[4 * x + 2] = source32F[4 * x + 2]; + dest16F[4 * x + 3] = source32F[4 * x + 3]; + } + } + + template<> + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned short *sourceD16 = reinterpret_cast(source); - float *destF = reinterpret_cast(dest + xoffset * 4); + float *destF = reinterpret_cast(dest); for(int x = 0; x < width; x++) { @@ -336,10 +1059,10 @@ namespace } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned int *sourceD24 = reinterpret_cast(source); - float *destF = reinterpret_cast(dest + xoffset * 4); + float *destF = reinterpret_cast(dest); for(int x = 0; x < width; x++) { @@ -348,10 +1071,10 @@ namespace } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { const unsigned int *sourceD32 = reinterpret_cast(source); - float *destF = reinterpret_cast(dest + xoffset * 4); + float *destF = reinterpret_cast(dest); for(int x = 0; x < width; x++) { @@ -360,36 +1083,48 @@ namespace } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { - const unsigned int *sourceI = reinterpret_cast(source); - unsigned char *destI = dest + xoffset; + const float *sourceF = reinterpret_cast(source); + float *destF = reinterpret_cast(dest); for(int x = 0; x < width; x++) { - destI[x] = static_cast(sourceI[x] & 0x000000FF); // FIXME: Quad layout + destF[x] = sw::clamp(sourceF[x], 0.0f, 1.0f); } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { struct D32FS8 { float depth32f; unsigned int stencil24_8; }; const D32FS8 *sourceD32FS8 = reinterpret_cast(source); - float *destF = reinterpret_cast(dest + xoffset * 4); + float *destF = reinterpret_cast(dest); + + for(int x = 0; x < width; x++) + { + destF[x] = sw::clamp(sourceD32FS8[x].depth32f, 0.0f, 1.0f); + } + } + + template<> + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) + { + const unsigned int *sourceI = reinterpret_cast(source); + unsigned char *destI = dest; for(int x = 0; x < width; x++) { - destF[x] = sourceD32FS8[x].depth32f; + destI[x] = static_cast(sourceI[x] & 0x000000FF); // FIXME: Quad layout } } template<> - void LoadImageRow(const unsigned char *source, unsigned char *dest, GLint xoffset, GLsizei width) + void TransferRow(unsigned char *dest, const unsigned char *source, GLsizei width, GLsizei bytes) { struct D32FS8 { float depth32f; unsigned int stencil24_8; }; const D32FS8 *sourceD32FS8 = reinterpret_cast(source); - unsigned char *destI = dest + xoffset; + unsigned char *destI = dest; for(int x = 0; x < width; x++) { @@ -397,766 +1132,344 @@ namespace } } - 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) + struct Rectangle + { + GLsizei bytes; + GLsizei width; + GLsizei height; + GLsizei depth; + int inputPitch; + int inputHeight; + int destPitch; + GLsizei destSlice; + }; + + template + void Transfer(void *buffer, const void *input, const Rectangle &rect) { - for(int z = 0; z < depth; ++z) + for(int z = 0; z < rect.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 *inputStart = static_cast(input) + (z * rect.inputPitch * rect.inputHeight); + unsigned char *destStart = static_cast(buffer) + (z * rect.destSlice); + for(int y = 0; y < rect.height; y++) { - const unsigned char *source = inputStart + y * inputPitch; - unsigned char *dest = destStart + (y + yoffset) * destPitch; + const unsigned char *source = inputStart + y * rect.inputPitch; + unsigned char *dest = destStart + y * rect.destPitch; - LoadImageRow(source, dest, xoffset, width); + TransferRow(dest, source, rect.width, rect.bytes); } } } -} -namespace egl -{ - sw::Format ConvertFormatType(GLenum format, GLenum type) + class ImageImplementation : public Image { - switch(format) + public: + ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLint internalformat) + : Image(parentTexture, width, height, internalformat) {} + ImageImplementation(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat) + : Image(parentTexture, width, height, depth, border, internalformat) {} + ImageImplementation(GLsizei width, GLsizei height, GLint internalformat, int pitchP) + : Image(width, height, internalformat, pitchP) {} + ImageImplementation(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable) + : Image(width, height, internalformat, multiSampleDepth, lockable) {} + + ~ImageImplementation() override { - 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; - 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; - default: - UNREACHABLE(format); + sync(); // Wait for any threads that use this image to finish. } - return sw::FORMAT_NULL; + 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, GLint internalformat) + { + if(size(width, height, 1, 0, 1, internalformat) > IMPLEMENTATION_MAX_IMAGE_SIZE_BYTES) + { + return nullptr; + } + + return new ImageImplementation(parentTexture, width, height, internalformat); } - sw::Format SelectInternalFormat(GLenum format, GLenum type) + Image *Image::create(Texture *parentTexture, GLsizei width, GLsizei height, GLsizei depth, int border, GLint internalformat) { - switch(format) + if(size(width, height, depth, border, 1, internalformat) > IMPLEMENTATION_MAX_IMAGE_SIZE_BYTES) { - 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; + return nullptr; } - switch(type) + return new ImageImplementation(parentTexture, width, height, depth, border, internalformat); + } + + Image *Image::create(GLsizei width, GLsizei height, GLint internalformat, int pitchP) + { + if(size(pitchP, height, 1, 0, 1, internalformat) > IMPLEMENTATION_MAX_IMAGE_SIZE_BYTES) { - 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: - 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 nullptr; + } + + return new ImageImplementation(width, height, internalformat, pitchP); + } + + Image *Image::create(GLsizei width, GLsizei height, GLint internalformat, int multiSampleDepth, bool lockable) + { + if(size(width, height, 1, 0, multiSampleDepth, internalformat) > IMPLEMENTATION_MAX_IMAGE_SIZE_BYTES) + { + return nullptr; + } + + return new ImageImplementation(width, height, internalformat, multiSampleDepth, lockable); + } + + size_t Image::size(int width, int height, int depth, int border, int samples, GLint internalformat) + { + return sw::Surface::size(width, height, depth, border, samples, gl::SelectInternalFormat(internalformat)); + } + + int ClientBuffer::getWidth() const + { + return width; + } + + int ClientBuffer::getHeight() const + { + return height; + } + + sw::Format ClientBuffer::getFormat() const + { + return format; + } + + size_t ClientBuffer::getPlane() const + { + return plane; + } + + int ClientBuffer::pitchP() const + { +#if defined(__APPLE__) + if(buffer) + { + IOSurfaceRef ioSurface = reinterpret_cast(buffer); + int pitchB = static_cast(IOSurfaceGetBytesPerRowOfPlane(ioSurface, plane)); + int bytesPerPixel = sw::Surface::bytes(format); + ASSERT((pitchB % bytesPerPixel) == 0); + return pitchB / bytesPerPixel; + } + + return 0; +#else + return sw::Surface::pitchP(width, 0, format, false); +#endif + } + + void ClientBuffer::retain() + { +#if defined(__APPLE__) + if(buffer) + { + CFRetain(reinterpret_cast(buffer)); } +#endif + } - return sw::FORMAT_NULL; + void ClientBuffer::release() + { +#if defined(__APPLE__) + if(buffer) + { + CFRelease(reinterpret_cast(buffer)); + buffer = nullptr; + } +#endif } - // Returns the size, in bytes, of a single texel in an Image - static int ComputePixelSize(GLenum format, GLenum type) + void* ClientBuffer::lock(int x, int y, int z) { - switch(type) +#if defined(__APPLE__) + if(buffer) + { + IOSurfaceRef ioSurface = reinterpret_cast(buffer); + IOSurfaceLock(ioSurface, 0, nullptr); + void* pixels = IOSurfaceGetBaseAddressOfPlane(ioSurface, plane); + int bytes = sw::Surface::bytes(format); + int pitchB = static_cast(IOSurfaceGetBytesPerRowOfPlane(ioSurface, plane)); + int sliceB = static_cast(IOSurfaceGetHeightOfPlane(ioSurface, plane)) * pitchB; + return (unsigned char*)pixels + x * bytes + y * pitchB + z * sliceB; + } + + return nullptr; +#else + int bytes = sw::Surface::bytes(format); + int pitchB = sw::Surface::pitchB(width, 0, format, false); + int sliceB = height * pitchB; + return (unsigned char*)buffer + x * bytes + y * pitchB + z * sliceB; +#endif + } + + void ClientBuffer::unlock() + { +#if defined(__APPLE__) + if(buffer) + { + IOSurfaceRef ioSurface = reinterpret_cast(buffer); + IOSurfaceUnlock(ioSurface, 0, nullptr); + } +#endif + } + + class ClientBufferImage : public egl::Image + { + public: + explicit ClientBufferImage(const ClientBuffer& clientBuffer) : + egl::Image(clientBuffer.getWidth(), + clientBuffer.getHeight(), + getClientBufferInternalFormat(clientBuffer.getFormat()), + clientBuffer.pitchP()), + clientBuffer(clientBuffer) + { + shared = false; + this->clientBuffer.retain(); + } + + private: + ClientBuffer clientBuffer; + + ~ClientBufferImage() override + { + sync(); // Wait for any threads that use this image to finish. + + clientBuffer.release(); + } + + static GLint getClientBufferInternalFormat(sw::Format format) { - 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); + case sw::FORMAT_R8: return GL_R8; + case sw::FORMAT_G8R8: return GL_RG8; + case sw::FORMAT_A8R8G8B8: return GL_BGRA8_EXT; + case sw::FORMAT_R16UI: return GL_R16UI; + case sw::FORMAT_A16B16G16R16F: return GL_RGBA16F; + default: return GL_NONE; } - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_5_6_5: - 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) + } + + void *lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) override + { + LOGLOCK("image=%p op=%s.swsurface lock=%d", this, __FUNCTION__, lock); + + // Always do this for reference counting. + void *data = sw::Surface::lockInternal(x, y, z, lock, client); + + if(x != 0 || y != 0 || z != 0) { - 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); + LOGLOCK("badness: %s called with unsupported parms: image=%p x=%d y=%d z=%d", __FUNCTION__, this, x, y, z); } - break; - case GL_HALF_FLOAT: - case GL_HALF_FLOAT_OES: - switch(format) + + LOGLOCK("image=%p op=%s.ani lock=%d", this, __FUNCTION__, lock); + + // Lock the ClientBuffer and use its address. + data = clientBuffer.lock(x, y, z); + + if(lock == sw::LOCK_UNLOCKED) { - 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); + // We're never going to get a corresponding unlock, so unlock + // immediately. This keeps the reference counts sane. + clientBuffer.unlock(); } - break; - default: UNREACHABLE(type); + + return data; } - return 0; - } + void unlockInternal() override + { + LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__); + clientBuffer.unlock(); - GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment) - { - ASSERT(alignment > 0 && sw::isPow2(alignment)); + LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__); + sw::Surface::unlockInternal(); + } - GLsizei rawPitch = ComputePixelSize(format, type) * width; - return (rawPitch + alignment - 1) & ~(alignment - 1); - } + void *lock(int x, int y, int z, sw::Lock lock) override + { + LOGLOCK("image=%p op=%s lock=%d", this, __FUNCTION__, lock); + (void)sw::Surface::lockExternal(x, y, z, lock, sw::PUBLIC); - inline GLsizei ComputeCompressedPitch(GLsizei width, GLenum format) + return clientBuffer.lock(x, y, z); + } + + void unlock() override + { + LOGLOCK("image=%p op=%s.ani", this, __FUNCTION__); + clientBuffer.unlock(); + + LOGLOCK("image=%p op=%s.swsurface", this, __FUNCTION__); + sw::Surface::unlockExternal(); + } + + void release() override + { + Image::release(); + } + }; + + Image *Image::create(const egl::ClientBuffer& clientBuffer) { - return ComputeCompressedSize(width, 1, format); + return new ClientBufferImage(clientBuffer); } - GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format) + Image::~Image() { - switch(format) + // 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) { - 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; + parentTexture->release(); } + + ASSERT(!shared); } - Image::~Image() + void *Image::lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) { - ASSERT(referenceCount == 0); + return Surface::lockInternal(x, y, z, lock, client); } - void Image::addRef() + void Image::unlockInternal() { - if(parentTexture) - { - return parentTexture->addRef(); - } - int newCount = sw::atomicIncrement(&referenceCount); - LOGLOCK("%s image=%p referenceCount=%d", __FUNCTION__, this, newCount); + Surface::unlockInternal(); } void Image::release() { - if(parentTexture) + int refs = dereference(); + + if(refs > 0) { - return parentTexture->release(); + if(parentTexture) + { + parentTexture->sweep(); + } } - - int newCount = sw::atomicDecrement(&referenceCount); - LOGLOCK("%s image=%p referenceCount=%d", __FUNCTION__, this, newCount); - if (newCount == 0) + else { - ASSERT(!shared); // Should still hold a reference if eglDestroyImage hasn't been called delete this; } } @@ -1165,437 +1478,392 @@ namespace egl { if(parentTexture == parent) { - parentTexture = 0; + parentTexture = nullptr; } release(); } - void Image::loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const UnpackInfo& unpackInfo, const void *input) + bool Image::isChildOf(const egl::Texture *parent) const { - GLsizei inputPitch = ComputePitch((unpackInfo.rowLength == 0) ? width : unpackInfo.rowLength, format, type, unpackInfo.alignment); - GLsizei inputHeight = (unpackInfo.imageHeight == 0) ? height : unpackInfo.imageHeight; - input = ((char*)input) + (unpackInfo.skipImages * inputHeight + unpackInfo.skipRows) * inputPitch + unpackInfo.skipPixels; - sw::Format selectedInternalFormat = SelectInternalFormat(format, type); - if(selectedInternalFormat == sw::FORMAT_NULL) - { - return; - } + return parentTexture == parent; + } - if(selectedInternalFormat == internalFormat) + void Image::loadImageData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, const void *input, void *buffer) + { + Rectangle rect; + rect.bytes = gl::ComputePixelSize(format, type); + rect.width = width; + rect.height = height; + rect.depth = depth; + rect.inputPitch = inputPitch; + rect.inputHeight = inputHeight; + rect.destPitch = getPitch(); + rect.destSlice = getSlice(); + + // [OpenGL ES 3.0.5] table 3.2 and 3.3. + switch(format) { - void *buffer = lock(0, 0, sw::LOCK_WRITEONLY); - - if(buffer) + case GL_RGBA: + switch(type) { - switch(type) + case GL_UNSIGNED_BYTE: + switch(internalformat) + { + case GL_RGBA8: + case GL_SRGB8_ALPHA8: + return Transfer(buffer, input, rect); + case GL_RGB5_A1: + case GL_RGBA4: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A8B8G8R8); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(internalformat); + } + case GL_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RGBA8_SNORM && getExternalFormat() == sw::FORMAT_A8B8G8R8_SNORM); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT_4_4_4_4: + ASSERT_OR_RETURN(internalformat == GL_RGBA4 && getExternalFormat() == sw::FORMAT_A8B8G8R8); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT_5_5_5_1: + ASSERT_OR_RETURN(internalformat == GL_RGB5_A1 && getExternalFormat() == sw::FORMAT_A8B8G8R8); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT_2_10_10_10_REV: + switch(internalformat) + { + case GL_RGB10_A2: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A2B10G10R10); + return Transfer(buffer, input, rect); + case GL_RGB5_A1: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_A8B8G8R8); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(internalformat); + } + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + ASSERT_OR_RETURN(internalformat == GL_RGBA16F && getExternalFormat() == sw::FORMAT_A16B16G16R16F); + return Transfer(buffer, input, rect); + case GL_FLOAT: + switch(internalformat) { - 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); + case GL_RGBA32F: return Transfer(buffer, input, rect); + case GL_RGBA16F: return Transfer(buffer, input, rect); + default: UNREACHABLE(internalformat); } + default: + UNREACHABLE(type); } - - unlock(); - } - else - { - sw::Surface source(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); - sw::blitter.blit(&source, sourceRect, this, destRect, false); + case GL_RGBA_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RGBA8UI && getExternalFormat() == sw::FORMAT_A8B8G8R8UI); + return Transfer(buffer, input, rect); + case GL_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RGBA8I && getExternalFormat() == sw::FORMAT_A8B8G8R8I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT: + ASSERT_OR_RETURN(internalformat == GL_RGBA16UI && getExternalFormat() == sw::FORMAT_A16B16G16R16UI); + return Transfer(buffer, input, rect); + case GL_SHORT: + ASSERT_OR_RETURN(internalformat == GL_RGBA16I && getExternalFormat() == sw::FORMAT_A16B16G16R16I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT: + ASSERT_OR_RETURN(internalformat == GL_RGBA32UI && getExternalFormat() == sw::FORMAT_A32B32G32R32UI); + return Transfer(buffer, input, rect); + case GL_INT: + ASSERT_OR_RETURN(internalformat == GL_RGBA32I && getExternalFormat() == sw::FORMAT_A32B32G32R32I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT_2_10_10_10_REV: + ASSERT_OR_RETURN(internalformat == GL_RGB10_A2UI && getExternalFormat() == sw::FORMAT_A2B10G10R10UI); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(type); + } + case GL_BGRA_EXT: + switch(type) + { + case GL_UNSIGNED_BYTE: + ASSERT_OR_RETURN(internalformat == GL_BGRA8_EXT && getExternalFormat() == sw::FORMAT_A8R8G8B8); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT: // Only valid for glReadPixels calls. + case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT: // Only valid for glReadPixels calls. + default: + UNREACHABLE(type); + } + case GL_RGB: + switch(type) + { + case GL_UNSIGNED_BYTE: + switch(internalformat) + { + case GL_RGB8: return Transfer(buffer, input, rect); + case GL_SRGB8: return Transfer(buffer, input, rect); + case GL_RGB565: return Transfer(buffer, input, rect); + default: UNREACHABLE(internalformat); + } + case GL_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RGB8_SNORM && getExternalFormat() == sw::FORMAT_X8B8G8R8_SNORM); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT_5_6_5: + ASSERT_OR_RETURN(internalformat == GL_RGB565 && getExternalFormat() == sw::FORMAT_R5G6B5); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT_10F_11F_11F_REV: + ASSERT_OR_RETURN(internalformat == GL_R11F_G11F_B10F && getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT_5_9_9_9_REV: + ASSERT_OR_RETURN(internalformat == GL_RGB9_E5 && getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED); + return Transfer(buffer, input, rect); + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + switch(internalformat) + { + case GL_RGB16F: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F); + return Transfer(buffer, input, rect); + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(internalformat); + } + case GL_FLOAT: + switch(internalformat) + { + case GL_RGB32F: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X32B32G32R32F); + return Transfer(buffer, input, rect); + case GL_RGB16F: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F); + return Transfer(buffer, input, rect); + case GL_R11F_G11F_B10F: + case GL_RGB9_E5: + ASSERT_OR_RETURN(getExternalFormat() == sw::FORMAT_X16B16G16R16F_UNSIGNED); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(internalformat); + } + default: + UNREACHABLE(type); + } + case GL_RGB_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RGB8UI && getExternalFormat() == sw::FORMAT_X8B8G8R8UI); + return Transfer(buffer, input, rect); + case GL_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RGB8I && getExternalFormat() == sw::FORMAT_X8B8G8R8I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT: + ASSERT_OR_RETURN(internalformat == GL_RGB16UI && getExternalFormat() == sw::FORMAT_X16B16G16R16UI); + return Transfer(buffer, input, rect); + case GL_SHORT: + ASSERT_OR_RETURN(internalformat == GL_RGB16I && getExternalFormat() == sw::FORMAT_X16B16G16R16I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT: + ASSERT_OR_RETURN(internalformat == GL_RGB32UI && getExternalFormat() == sw::FORMAT_X32B32G32R32UI); + return Transfer(buffer, input, rect); + case GL_INT: + ASSERT_OR_RETURN(internalformat == GL_RGB32I && getExternalFormat() == sw::FORMAT_X32B32G32R32I); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(type); + } + case GL_RG: + switch(type) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + return Transfer(buffer, input, rect); + case GL_FLOAT: + switch(internalformat) + { + case GL_RG32F: return Transfer(buffer, input, rect); + case GL_RG16F: return Transfer(buffer, input, rect); + default: UNREACHABLE(internalformat); + } + default: + UNREACHABLE(type); + } + case GL_RG_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RG8UI && getExternalFormat() == sw::FORMAT_G8R8UI); + return Transfer(buffer, input, rect); + case GL_BYTE: + ASSERT_OR_RETURN(internalformat == GL_RG8I && getExternalFormat() == sw::FORMAT_G8R8I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT: + ASSERT_OR_RETURN(internalformat == GL_RG16UI && getExternalFormat() == sw::FORMAT_G16R16UI); + return Transfer(buffer, input, rect); + case GL_SHORT: + ASSERT_OR_RETURN(internalformat == GL_RG16I && getExternalFormat() == sw::FORMAT_G16R16I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT: + ASSERT_OR_RETURN(internalformat == GL_RG32UI && getExternalFormat() == sw::FORMAT_G32R32UI); + return Transfer(buffer, input, rect); + case GL_INT: + ASSERT_OR_RETURN(internalformat == GL_RG32I && getExternalFormat() == sw::FORMAT_G32R32I); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(type); + } + case GL_RED: + switch(type) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + return Transfer(buffer, input, rect); + case GL_FLOAT: + switch(internalformat) + { + case GL_R32F: return Transfer(buffer, input, rect); + case GL_R16F: return Transfer(buffer, input, rect); + default: UNREACHABLE(internalformat); + } + default: + UNREACHABLE(type); + } + case GL_RED_INTEGER: + switch(type) + { + case GL_UNSIGNED_BYTE: + ASSERT_OR_RETURN(internalformat == GL_R8UI && getExternalFormat() == sw::FORMAT_R8UI); + return Transfer(buffer, input, rect); + case GL_BYTE: + ASSERT_OR_RETURN(internalformat == GL_R8I && getExternalFormat() == sw::FORMAT_R8I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_SHORT: + ASSERT_OR_RETURN(internalformat == GL_R16UI && getExternalFormat() == sw::FORMAT_R16UI); + return Transfer(buffer, input, rect); + case GL_SHORT: + ASSERT_OR_RETURN(internalformat == GL_R16I && getExternalFormat() == sw::FORMAT_R16I); + return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT: + ASSERT_OR_RETURN(internalformat == GL_R32UI && getExternalFormat() == sw::FORMAT_R32UI); + return Transfer(buffer, input, rect); + case GL_INT: + ASSERT_OR_RETURN(internalformat == GL_R32I && getExternalFormat() == sw::FORMAT_R32I); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(type); + } + case GL_DEPTH_COMPONENT: + switch(type) + { + case GL_UNSIGNED_SHORT: return Transfer(buffer, input, rect); + case GL_UNSIGNED_INT: return Transfer(buffer, input, rect); + case GL_FLOAT: return Transfer(buffer, input, rect); + case GL_DEPTH_COMPONENT24: // Only valid for glRenderbufferStorage calls. + case GL_DEPTH_COMPONENT32_OES: // Only valid for glRenderbufferStorage calls. + default: UNREACHABLE(type); + } + case GL_DEPTH_STENCIL: + switch(type) + { + case GL_UNSIGNED_INT_24_8: return Transfer(buffer, input, rect); + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return Transfer(buffer, input, rect); + default: UNREACHABLE(type); + } + case GL_LUMINANCE_ALPHA: + switch(type) + { + case GL_UNSIGNED_BYTE: + return Transfer(buffer, input, rect); + case GL_FLOAT: + switch(internalformat) + { + case GL_LUMINANCE_ALPHA32F_EXT: return Transfer(buffer, input, rect); + case GL_LUMINANCE_ALPHA16F_EXT: return Transfer(buffer, input, rect); + default: UNREACHABLE(internalformat); + } + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + ASSERT_OR_RETURN(internalformat == GL_LUMINANCE_ALPHA16F_EXT); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(type); + } + case GL_LUMINANCE: + case GL_ALPHA: + switch(type) + { + case GL_UNSIGNED_BYTE: + return Transfer(buffer, input, rect); + case GL_FLOAT: + switch(internalformat) + { + case GL_LUMINANCE32F_EXT: return Transfer(buffer, input, rect); + case GL_LUMINANCE16F_EXT: return Transfer(buffer, input, rect); + case GL_ALPHA32F_EXT: return Transfer(buffer, input, rect); + case GL_ALPHA16F_EXT: return Transfer(buffer, input, rect); + default: UNREACHABLE(internalformat); + } + case GL_HALF_FLOAT: + case GL_HALF_FLOAT_OES: + ASSERT_OR_RETURN(internalformat == GL_LUMINANCE16F_EXT || internalformat == GL_ALPHA16F_EXT); + return Transfer(buffer, input, rect); + default: + UNREACHABLE(type); + } + default: + UNREACHABLE(format); } } - void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer) + void Image::loadStencilData(GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, GLenum format, GLenum type, 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, sw::PUBLIC)); + Rectangle rect; + rect.bytes = gl::ComputePixelSize(format, type); + rect.width = width; + rect.height = height; + rect.depth = depth; + rect.inputPitch = inputPitch; + rect.inputHeight = inputHeight; + rect.destPitch = getStencilPitchB(); + rect.destSlice = getStencilSliceB(); - if(stencil) + switch(type) { - LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil); - - unlockStencil(); + case GL_UNSIGNED_INT_24_8: return Transfer(buffer, input, rect); + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: return Transfer(buffer, input, rect); + default: UNREACHABLE(format); } } - void Image::loadD32FS8ImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, int inputPitch, int inputHeight, const void *input, void *buffer) + void Image::loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelStorageModes &unpackParameters, const void *pixels) { - LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getPitch(), getHeight(), input, buffer); + GLsizei inputWidth = (unpackParameters.rowLength == 0) ? width : unpackParameters.rowLength; + GLsizei inputPitch = gl::ComputePitch(inputWidth, format, type, unpackParameters.alignment); + GLsizei inputHeight = (unpackParameters.imageHeight == 0) ? height : unpackParameters.imageHeight; + char *input = ((char*)pixels) + gl::ComputePackingOffset(format, type, inputWidth, inputHeight, unpackParameters); + + void *buffer = lock(xoffset, yoffset, zoffset, sw::LOCK_WRITEONLY); + + if(buffer) + { + loadImageData(width, height, depth, inputPitch, inputHeight, format, type, input, buffer); + } - unsigned char *stencil = reinterpret_cast(lockStencil(0, sw::PUBLIC)); + unlock(); - if(stencil) + if(hasStencil()) { - LoadImageData(xoffset, yoffset, zoffset, width, height, depth, inputPitch, inputHeight, getStencilPitchB(), getHeight(), input, stencil); + unsigned char *stencil = reinterpret_cast(lockStencil(xoffset, yoffset, zoffset, sw::PUBLIC)); + + if(stencil) + { + loadStencilData(width, height, depth, inputPitch, inputHeight, format, type, input, stencil); + } unlockStencil(); } @@ -1603,20 +1871,22 @@ namespace egl 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 = gl::ComputeCompressedPitch(width, internalformat); + int inputSlice = imageSize / depth; + int rows = inputSlice / inputPitch; - int inputPitch = ComputeCompressedPitch(width, format); - int rows = imageSize / inputPitch; - void *buffer = lock(xoffset, yoffset, sw::LOCK_WRITEONLY); + void *buffer = lock(xoffset, yoffset, zoffset, sw::LOCK_WRITEONLY); if(buffer) { - for(int i = 0; i < rows; i++) + for(int z = 0; z < depth; z++) { - memcpy((void*)((GLbyte*)buffer + i * getPitch()), (void*)((GLbyte*)pixels + i * inputPitch), inputPitch); + for(int y = 0; y < rows; y++) + { + GLbyte *dest = (GLbyte*)buffer + y * getPitch() + z * getSlice(); + GLbyte *source = (GLbyte*)pixels + y * inputPitch + z * inputSlice; + memcpy(dest, source, inputPitch); + } } }