diff --git a/include/bgfx.h b/include/bgfx.h index 1eb6468b..061065f2 100644 --- a/include/bgfx.h +++ b/include/bgfx.h @@ -302,12 +302,14 @@ namespace bgfx { enum Enum { - BC1, // DXT1 - BC2, // DXT3 - BC3, // DXT5 - BC4, // LATC1/ATI1 - BC5, // LATC2/ATI2 - ETC1, + BC1, // DXT1 + BC2, // DXT3 + BC3, // DXT5 + BC4, // LATC1/ATI1 + BC5, // LATC2/ATI2 + ETC1, // ETC1_RGB8 + PTC12, // PVRTC1_2BPP_RGBA + PTC14, // PVRTC1_4BPP_RGBA Unknown, L8, BGRX8, diff --git a/src/bgfx.cpp b/src/bgfx.cpp index df5b9e8c..9638b065 100755 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -1001,6 +1001,8 @@ namespace bgfx 4, // BC4 8, // BC5 4, // ETC1 + 2, // PVRTC1_2BPP_RGBA + 4, // PVRTC1_2BPP_RGBA 0, // Unknown 8, // L8 32, // BGRX8 diff --git a/src/image.cpp b/src/image.cpp index 0b8e53d8..a5755a27 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -9,6 +9,7 @@ #include "image.h" +// DDS #define DDS_MAGIC BX_MAKEFOURCC('D', 'D', 'S', ' ') #define DDS_HEADER_SIZE 124 #define DDS_IMAGE_DATA_OFFSET (DDS_HEADER_SIZE + 4) @@ -61,6 +62,7 @@ #define DDSCAPS2_VOLUME 0x00200000 +// KTX #define KTX_MAGIC BX_MAKEFOURCC(0xAB, 'K', 'T', 'X') #define KTX_HEADER_SIZE 64 @@ -87,6 +89,28 @@ #define KTX_RGBA16 0x805B #define KTX_RGBA16F 0x881A +// PVR3 +#define PVR3_MAKE8CC(_a, _b, _c, _d, _e, _f, _g, _h) (uint64_t(BX_MAKEFOURCC(_a, _b, _c, _d) ) | (uint64_t(BX_MAKEFOURCC(_e, _f, _g, _h) )<<32) ) + +#define PVR3_MAGIC BX_MAKEFOURCC('P', 'V', 'R', 3) +#define PVR3_HEADER_SIZE 52 + +#define PVR3_PVRTC1_2BPP_RGB 0 +#define PVR3_PVRTC1_2BPP_RGBA 1 +#define PVR3_PVRTC1_4BPP_RGB 2 +#define PVR3_PVRTC1_4BPP_RGBA 3 +#define PVR3_ETC1 6 +#define PVR3_DXT1 7 +#define PVR3_DXT2 8 +#define PVR3_DXT3 9 +#define PVR3_DXT4 10 +#define PVR3_DXT5 11 +#define PVR3_BC4 12 +#define PVR3_BC5 13 +#define PVR3_RGBA16 PVR3_MAKE8CC('r', 'g', 'b', 'a', 16, 16, 16, 16) + +#define PVR3_CHANNEL_TYPE_FLOAT 12 + namespace bgfx { void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst) @@ -98,7 +122,7 @@ namespace bgfx } } - void imageChessboard(uint32_t _width, uint32_t _height, uint32_t _step, uint32_t _0, uint32_t _1, void* _dst) + void imageCheckerboard(uint32_t _width, uint32_t _height, uint32_t _step, uint32_t _0, uint32_t _1, void* _dst) { uint32_t* dst = (uint32_t*)_dst; for (uint32_t yy = 0; yy < _height; ++yy) @@ -738,6 +762,11 @@ namespace bgfx } } break; + + default: + // Decompression not implemented... Make ugly red-yellow checkerboard texture. + imageCheckerboard(m_width, m_height, 16, UINT32_C(0xffff0000), UINT32_C(0xffffff00), _dst); + break; } } else @@ -927,10 +956,6 @@ namespace bgfx bpp = 8; break; - // type = TextureFormat::A8; - // bpp = 1; - // break; - default: bpp = 0; break; @@ -983,29 +1008,29 @@ namespace bgfx uint32_t glBaseInternalFormat; bx::readHE(_reader, glBaseInternalFormat, fromLittleEndian); - uint32_t pixelWidth; - bx::readHE(_reader, pixelWidth, fromLittleEndian); + uint32_t width; + bx::readHE(_reader, width, fromLittleEndian); - uint32_t pixelHeight; - bx::readHE(_reader, pixelHeight, fromLittleEndian); + uint32_t height; + bx::readHE(_reader, height, fromLittleEndian); - uint32_t pixelDepth; - bx::readHE(_reader, pixelDepth, fromLittleEndian); + uint32_t depth; + bx::readHE(_reader, depth, fromLittleEndian); uint32_t numberOfArrayElements; bx::readHE(_reader, numberOfArrayElements, fromLittleEndian); - uint32_t numberOfFaces; - bx::readHE(_reader, numberOfFaces, fromLittleEndian); + uint32_t numFaces; + bx::readHE(_reader, numFaces, fromLittleEndian); - uint32_t numberOfMipmapLevels; - bx::readHE(_reader, numberOfMipmapLevels, fromLittleEndian); + uint32_t numMips; + bx::readHE(_reader, numMips, fromLittleEndian); - uint32_t bytesOfKeyValueData; - bx::readHE(_reader, bytesOfKeyValueData, fromLittleEndian); + uint32_t metaDataSize; + bx::readHE(_reader, metaDataSize, fromLittleEndian); // skip meta garbage... - int64_t offset = bx::skip(_reader, bytesOfKeyValueData); + int64_t offset = bx::skip(_reader, metaDataSize); uint8_t bpp = 0; uint8_t blockSize = 1; @@ -1014,12 +1039,6 @@ namespace bgfx switch (glInternalFormat) { - case KTX_ETC1_RGB8_OES: - type = TextureFormat::ETC1; - bpp = 4; - blockSize = 4*4*bpp/8; - break; - case KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT: type = TextureFormat::BC1; bpp = 4; @@ -1050,6 +1069,26 @@ namespace bgfx blockSize = 4*4*bpp/8; break; + case KTX_ETC1_RGB8_OES: + type = TextureFormat::ETC1; + bpp = 4; + blockSize = 4*4*bpp/8; + break; + + case KTX_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: + case KTX_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: + type = TextureFormat::PTC12; + bpp = 2; + blockSize = 4*4*bpp/8; + break; + + case KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: + case KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: + type = TextureFormat::PTC14; + bpp = 2; + blockSize = 4*4*bpp/8; + break; + case KTX_RGBA16: type = TextureFormat::RGBA16; blockSize = 8; @@ -1072,29 +1111,147 @@ namespace bgfx case KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: case KTX_COMPRESSED_RGBA8_ETC2_EAC: case KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: - case KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: - case KTX_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: - case KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: - case KTX_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: default: break; } _imageContainer.m_type = type; _imageContainer.m_offset = (uint32_t)offset; - _imageContainer.m_width = pixelWidth; - _imageContainer.m_height = pixelHeight; - _imageContainer.m_depth = pixelDepth; + _imageContainer.m_width = width; + _imageContainer.m_height = height; + _imageContainer.m_depth = depth; _imageContainer.m_blockSize = blockSize; - _imageContainer.m_numMips = numberOfMipmapLevels; + _imageContainer.m_numMips = numMips; _imageContainer.m_bpp = bpp; _imageContainer.m_hasAlpha = hasAlpha; - _imageContainer.m_cubeMap = numberOfFaces > 1; + _imageContainer.m_cubeMap = numFaces > 1; _imageContainer.m_ktx = true; return TextureFormat::Unknown != type; } + bool imageParsePvr3(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader) + { + uint32_t flags; + bx::read(_reader, flags); + + uint64_t pixelFormat; + bx::read(_reader, pixelFormat); + + uint32_t colorSpace; + bx::read(_reader, colorSpace); // 0 - linearRGB, 1 - sRGB + + uint32_t channelType; + bx::read(_reader, channelType); + + uint32_t height; + bx::read(_reader, height); + + uint32_t width; + bx::read(_reader, width); + + uint32_t depth; + bx::read(_reader, depth); + + uint32_t numSurfaces; + bx::read(_reader, numSurfaces); + + uint32_t numFaces; + bx::read(_reader, numFaces); + + uint32_t numMips; + bx::read(_reader, numMips); + + uint32_t metaDataSize; + bx::read(_reader, metaDataSize); + + // skip meta garbage... + int64_t offset = bx::skip(_reader, metaDataSize); + + uint8_t bpp = 0; + uint8_t blockSize = 1; + TextureFormat::Enum type = TextureFormat::Unknown; + bool hasAlpha = false; + + switch (pixelFormat) + { + case PVR3_PVRTC1_2BPP_RGB: + case PVR3_PVRTC1_2BPP_RGBA: + type = TextureFormat::PTC12; + bpp = 2; + blockSize = 4*4*bpp/8; + break; + + case PVR3_PVRTC1_4BPP_RGB: + case PVR3_PVRTC1_4BPP_RGBA: + type = TextureFormat::PTC14; + bpp = 2; + blockSize = 4*4*bpp/8; + break; + + case PVR3_ETC1: + type = TextureFormat::ETC1; + bpp = 4; + blockSize = 4*4*bpp/8; + break; + + case PVR3_DXT1: + type = TextureFormat::BC1; + bpp = 4; + blockSize = 4*4*bpp/8; + break; + + case PVR3_DXT2: + case PVR3_DXT3: + type = TextureFormat::BC2; + bpp = 8; + blockSize = 4*4*bpp/8; + break; + + case PVR3_DXT4: + case PVR3_DXT5: + type = TextureFormat::BC3; + bpp = 8; + blockSize = 4*4*bpp/8; + break; + + case PVR3_BC4: + type = TextureFormat::BC4; + bpp = 4; + blockSize = 4*4*bpp/8; + break; + + case PVR3_BC5: + type = TextureFormat::BC5; + bpp = 8; + blockSize = 4*4*bpp/8; + break; + + case PVR3_RGBA16: + type = PVR3_CHANNEL_TYPE_FLOAT == channelType + ? TextureFormat::RGBA16F + : TextureFormat::RGBA16 + ; + blockSize = 8; + bpp = 64; + break; + } + + _imageContainer.m_type = type; + _imageContainer.m_offset = (uint32_t)offset; + _imageContainer.m_width = width; + _imageContainer.m_height = height; + _imageContainer.m_depth = depth; + _imageContainer.m_blockSize = blockSize; + _imageContainer.m_numMips = numMips; + _imageContainer.m_bpp = bpp; + _imageContainer.m_hasAlpha = hasAlpha; + _imageContainer.m_cubeMap = numFaces > 1; + _imageContainer.m_ktx = false; + + return TextureFormat::Unknown != type; + } + bool imageParse(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader) { uint32_t magic; @@ -1108,6 +1265,10 @@ namespace bgfx { return imageParseKtx(_imageContainer, _reader); } + else if (PVR3_MAGIC == magic) + { + return imageParsePvr3(_imageContainer, _reader); + } return false; } diff --git a/src/image.h b/src/image.h index c21f9938..3fff3acd 100644 --- a/src/image.h +++ b/src/image.h @@ -43,7 +43,7 @@ namespace bgfx void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst); /// - void imageChessboard(uint32_t _width, uint32_t _height, uint32_t _step, uint32_t _0, uint32_t _1, void* _dst); + void imageCheckerboard(uint32_t _width, uint32_t _height, uint32_t _step, uint32_t _0, uint32_t _1, void* _dst); /// void imageRgba8Downsample2x2(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst); diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 1909786b..dd2172ba 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -188,7 +188,9 @@ namespace bgfx { DXGI_FORMAT_BC3_UNORM }, { DXGI_FORMAT_BC4_UNORM }, { DXGI_FORMAT_BC5_UNORM }, - { DXGI_FORMAT_UNKNOWN }, + { DXGI_FORMAT_UNKNOWN }, // ETC1 + { DXGI_FORMAT_UNKNOWN }, // PVRTC1_2BPP_RGBA + { DXGI_FORMAT_UNKNOWN }, // PVRTC1_4BPP_RGBA { DXGI_FORMAT_UNKNOWN }, { DXGI_FORMAT_R8_UNORM }, { DXGI_FORMAT_B8G8R8A8_UNORM }, @@ -1634,9 +1636,7 @@ namespace bgfx if (imageParse(imageContainer, _mem->data, _mem->size) ) { - bool decompress = false - || (TextureFormat::ETC1 == imageContainer.m_type) - ; + bool decompress = DXGI_FORMAT_UNKNOWN == s_textureFormat[imageContainer.m_type].m_fmt; if (imageContainer.m_cubeMap) { diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index e433013a..c08a8bc6 100644 --- a/src/renderer_d3d9.cpp +++ b/src/renderer_d3d9.cpp @@ -193,7 +193,9 @@ namespace bgfx { D3DFMT_DXT5, 8 }, { D3DFMT_ATI1, 4 }, { D3DFMT_ATI2, 8 }, - { D3DFMT_UNKNOWN, 0 }, + { D3DFMT_UNKNOWN, 0 }, // ETC1 + { D3DFMT_UNKNOWN, 0 }, // PVRTC1_2BPP_RGBA + { D3DFMT_UNKNOWN, 0 }, // PVRTC1_4BPP_RGBA { D3DFMT_UNKNOWN, 0 }, { D3DFMT_L8, 8 }, { D3DFMT_X8R8G8B8, 32 }, @@ -1515,7 +1517,7 @@ namespace bgfx bool decompress = false || (TextureFormat::BC4 == imageContainer.m_type && !s_extendedFormats[ExtendedFormat::Ati1].m_supported) || (TextureFormat::BC5 == imageContainer.m_type && !s_extendedFormats[ExtendedFormat::Ati2].m_supported) - || (TextureFormat::ETC1 == imageContainer.m_type) + || (D3DFMT_UNKNOWN == tfi.m_fmt) ; D3DFORMAT format = decompress ? D3DFMT_A8R8G8B8 : tfi.m_fmt; diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index f1ddf958..d9ab62a2 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -200,6 +200,8 @@ namespace bgfx { GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL_COMPRESSED_LUMINANCE_LATC1_EXT, GL_ZERO, false }, { GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, GL_ZERO, false }, { GL_ETC1_RGB8_OES, GL_ETC1_RGB8_OES, GL_ZERO, false }, + { GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_ZERO, false }, + { GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_ZERO, false }, { GL_ZERO, GL_ZERO, GL_ZERO, true }, { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, true }, { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true }, @@ -218,6 +220,7 @@ namespace bgfx { ANGLE_instanced_arrays, ANGLE_translated_shader_source, + APPLE_texture_format_BGRA8888, ARB_debug_output, ARB_depth_clamp, ARB_framebuffer_sRGB, @@ -256,13 +259,16 @@ namespace bgfx EXT_texture_type_2_10_10_10_REV, EXT_timer_query, IMG_multisampled_render_to_texture, + IMG_read_format, IMG_shader_binary, IMG_texture_compression_pvrtc, + IMG_texture_compression_pvrtc2, IMG_texture_format_BGRA8888, NVX_gpu_memory_info, OES_compressed_ETC1_RGB8_texture, OES_depth_texture, OES_get_program_binary, + OES_read_format, OES_rgb8_rgba8, OES_standard_derivatives, OES_texture_float, @@ -285,6 +291,7 @@ namespace bgfx { { "GL_ANGLE_instanced_arrays", false, true }, { "GL_ANGLE_translated_shader_source", false, true }, + { "GL_APPLE_texture_format_BGRA8888", false, true }, { "GL_ARB_debug_output", BGFX_CONFIG_RENDERER_OPENGL >= 43, true }, { "GL_ARB_depth_clamp", BGFX_CONFIG_RENDERER_OPENGL >= 31, true }, { "GL_ARB_framebuffer_sRGB", false, true }, @@ -323,13 +330,16 @@ namespace bgfx { "GL_EXT_texture_type_2_10_10_10_REV", false, true }, { "GL_EXT_timer_query", false, true }, { "GL_IMG_multisampled_render_to_texture", false, true }, + { "GL_IMG_read_format", false, true }, { "GL_IMG_shader_binary", false, true }, { "GL_IMG_texture_compression_pvrtc", false, true }, + { "GL_IMG_texture_compression_pvrtc2", false, true }, { "GL_IMG_texture_format_BGRA8888", false, true }, { "GL_NVX_gpu_memory_info", false, true }, { "GL_OES_compressed_ETC1_RGB8_texture", false, true }, { "GL_OES_depth_texture", false, true }, - { "GL_OES_get_program_binary", false, false }, + { "GL_OES_get_program_binary", false, true }, + { "GL_OES_read_format", false, true }, { "GL_OES_rgb8_rgba8", false, true }, { "GL_OES_standard_derivatives", false, true }, { "GL_OES_texture_float", false, true }, @@ -2475,8 +2485,14 @@ namespace bgfx ; s_textureFormat[TextureFormat::BC4].m_supported = bc45Supported; s_textureFormat[TextureFormat::BC5].m_supported = bc45Supported; + s_textureFormat[TextureFormat::ETC1].m_supported = s_extension[Extension::OES_compressed_ETC1_RGB8_texture].m_supported; + bool pvr1Supported = s_extension[Extension::IMG_texture_compression_pvrtc ].m_supported; +// bool pvr2Supported = s_extension[Extension::IMG_texture_compression_pvrtc2].m_supported; + s_textureFormat[TextureFormat::PTC12].m_supported = pvr1Supported; + s_textureFormat[TextureFormat::PTC14].m_supported = pvr1Supported; + s_renderCtx.m_vaoSupport = !!BGFX_CONFIG_RENDERER_OPENGLES3 || s_extension[Extension::ARB_vertex_array_object].m_supported || s_extension[Extension::OES_vertex_array_object].m_supported @@ -2509,10 +2525,20 @@ namespace bgfx } #endif // BGFX_CONFIG_RENDERER_OPENGL|BGFX_CONFIG_RENDERER_OPENGLES3 - s_renderCtx.m_readPixelsFmt = GL_RGBA; + if (s_extension[Extension::IMG_read_format].m_supported + && s_extension[Extension::OES_read_format].m_supported) + { + s_renderCtx.m_readPixelsFmt = GL_BGRA_EXT; + } + else + { + s_renderCtx.m_readPixelsFmt = GL_RGBA; + } if (s_extension[Extension::EXT_texture_format_BGRA8888].m_supported - || s_extension[Extension::EXT_bgra].m_supported) + || s_extension[Extension::EXT_bgra].m_supported + || s_extension[Extension::IMG_texture_format_BGRA8888].m_supported + || s_extension[Extension::APPLE_texture_format_BGRA8888].m_supported) { #if BGFX_CONFIG_RENDERER_OPENGL s_renderCtx.m_readPixelsFmt = GL_BGRA_EXT; diff --git a/src/renderer_gl.h b/src/renderer_gl.h index fa400916..5d05be54 100755 --- a/src/renderer_gl.h +++ b/src/renderer_gl.h @@ -175,6 +175,22 @@ typedef void (*PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC)(GLuint shader, GLsizei b # define GL_ETC1_RGB8_OES 0x8D64 # endif // GL_ETC1_RGB8_OES +# ifndef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG +# define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +# endif // GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG + +# ifndef GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG +# define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +# endif // GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG + +# ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG +# define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +# endif // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG + +# ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG +# define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +# endif // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG + # ifndef GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE # define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 # endif // GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE