Browse Source

texturev: Added texture array support.

Branimir Karadžić 9 years ago
parent
commit
08438fa567

+ 1 - 0
include/bgfx/bgfx.h

@@ -615,6 +615,7 @@ namespace bgfx
 		uint16_t width;             //!< Texture width.
 		uint16_t height;            //!< Texture height.
 		uint16_t depth;             //!< Texture depth.
+		uint16_t numLayers;         //!< Number of layers in texture array.
 		uint8_t numMips;            //!< Number of MIP maps.
 		uint8_t bitsPerPixel;       //!< Format bits per pixel.
 		bool    cubeMap;            //!< Texture is cubemap.

+ 1 - 1
include/bgfx/bgfxdefines.h

@@ -6,7 +6,7 @@
 #ifndef BGFX_DEFINES_H_HEADER_GUARD
 #define BGFX_DEFINES_H_HEADER_GUARD
 
-#define BGFX_API_VERSION UINT32_C(19)
+#define BGFX_API_VERSION UINT32_C(20)
 
 ///
 #define BGFX_STATE_RGB_WRITE               UINT64_C(0x0000000000000001) //!< Enable RGB write.

+ 1 - 0
include/bgfx/c99/bgfx.h

@@ -382,6 +382,7 @@ typedef struct bgfx_texture_info
     uint16_t width;
     uint16_t height;
     uint16_t depth;
+    uint16_t numLayers;
     uint8_t numMips;
     uint8_t bitsPerPixel;
     bool    cubeMap;

+ 2 - 1
src/bgfx.cpp

@@ -2924,7 +2924,8 @@ error:
 		_info.height  = _height;
 		_info.depth   = _depth;
 		_info.numMips = numMips;
-		_info.cubeMap = _cubeMap;
+		_info.numLayers = _numLayers;
+		_info.cubeMap   = _cubeMap;
 		_info.storageSize  = size;
 		_info.bitsPerPixel = bpp;
 	}

+ 1 - 1
src/bgfx_p.h

@@ -3098,7 +3098,7 @@ namespace bgfx
 					, (uint16_t)imageContainer.m_depth
 					, imageContainer.m_cubeMap
 					, imageContainer.m_numMips > 1
-					, 1
+					, imageContainer.m_numLayers
 					, TextureFormat::Enum(imageContainer.m_format)
 					);
 			}

+ 28 - 20
tools/shaderc/shaderc.cpp

@@ -23,6 +23,7 @@ namespace bgfx
 	static const char* s_ARB_shader_texture_lod[] =
 	{
 		"texture2DLod",
+		"texture2DArrayLod", // BK - interacts with ARB_texture_array.
 		"texture2DProjLod",
 		"texture3DLod",
 		"texture3DProjLod",
@@ -1791,15 +1792,6 @@ namespace bgfx
 										bx::stringPrintf(code, "#version %s\n", need130 ? "130" : profile);
 									}
 
-									if (130 > glsl)
-									{
-										bx::stringPrintf(code,
-												"#define ivec2 vec2\n"
-												"#define ivec3 vec3\n"
-												"#define ivec4 vec4\n"
-												);
-									}
-
 									if (usesGpuShader5)
 									{
 										bx::stringPrintf(code
@@ -1814,11 +1806,6 @@ namespace bgfx
 											);
 									}
 
-									bx::stringPrintf(code
-										, "#define bgfxShadow2D shadow2D\n"
-										  "#define bgfxShadow2DProj shadow2DProj\n"
-										);
-
 									if (usesTextureLod
 									&&  130 > glsl)
 									{
@@ -1840,15 +1827,23 @@ namespace bgfx
 											, "#extension GL_EXT_texture_array : enable\n"
 											);
 									}
+
+									if (130 > glsl)
+									{
+										bx::stringPrintf(code,
+												"#define ivec2 vec2\n"
+												"#define ivec3 vec3\n"
+												"#define ivec4 vec4\n"
+												);
+									}
+
+									bx::stringPrintf(code
+										, "#define bgfxShadow2D shadow2D\n"
+										  "#define bgfxShadow2DProj shadow2DProj\n"
+										);
 								}
 								else
 								{
-									bx::stringPrintf(code,
-											"#define ivec2 vec2\n"
-											"#define ivec3 vec3\n"
-											"#define ivec4 vec4\n"
-											);
-
 									// Pretend that all extensions are available.
 									// This will be stripped later.
 									if (usesTextureLod)
@@ -1904,6 +1899,19 @@ namespace bgfx
 											  "#define gl_FragDepth gl_FragDepthEXT\n"
 											);
 									}
+
+									if (usesTextureArray)
+									{
+										bx::stringPrintf(code
+											, "#extension GL_EXT_texture_array : enable\n"
+											);
+									}
+
+									bx::stringPrintf(code,
+											"#define ivec2 vec2\n"
+											"#define ivec3 vec3\n"
+											"#define ivec4 vec4\n"
+											);
 								}
 
 								code += preprocessor.m_preprocessed;

+ 78 - 0
tools/texturev/fs_texture_array.bin.h

@@ -0,0 +1,78 @@
+static const uint8_t fs_texture_array_glsl[329] =
+{
+	0x46, 0x53, 0x48, 0x04, 0x01, 0x83, 0xf2, 0xe1, 0x02, 0x00, 0x0a, 0x73, 0x5f, 0x74, 0x65, 0x78, // FSH........s_tex
+	0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x08, 0x75, 0x5f, 0x70, 0x61, // Color.......u_pa
+	0x72, 0x61, 0x6d, 0x73, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x76, 0x61, // rams..........va
+	0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, // rying vec4 v_col
+	0x6f, 0x72, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, // or0;.varying vec
+	0x32, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, // 2 v_texcoord0;.u
+	0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, // niform sampler2D
+	0x41, 0x72, 0x72, 0x61, 0x79, 0x20, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, // Array s_texColor
+	0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x75, // ;.uniform vec4 u
+	0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, // _params;.void ma
+	0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x74, // in ().{.  vec3 t
+	0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // mpvar_1;.  tmpva
+	0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, // r_1.xy = v_texco
+	0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, // ord0;.  tmpvar_1
+	0x2e, 0x7a, 0x20, 0x3d, 0x20, 0x75, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x79, 0x3b, // .z = u_params.y;
+	0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, // .  gl_FragColor 
+	0x3d, 0x20, 0x28, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x41, 0x72, 0x72, 0x61, // = (texture2DArra
+	0x79, 0x4c, 0x6f, 0x64, 0x20, 0x28, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, // yLod (s_texColor
+	0x2c, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2c, 0x20, 0x75, 0x5f, 0x70, 0x61, // , tmpvar_1, u_pa
+	0x72, 0x61, 0x6d, 0x73, 0x2e, 0x78, 0x29, 0x20, 0x2a, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, // rams.x) * v_colo
+	0x72, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00,                                           // r0);.}...
+};
+static const uint8_t fs_texture_array_mtl[811] =
+{
+	0x46, 0x53, 0x48, 0x04, 0x01, 0x83, 0xf2, 0xe1, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, 0x75, 0x73, // FSH...........us
+	0x69, 0x6e, 0x67, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x6d, 0x65, // ing namespace me
+	0x74, 0x61, 0x6c, 0x3b, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, // tal;.struct xlat
+	0x4d, 0x74, 0x6c, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x7b, // MtlShaderInput {
+	0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, // .  float4 v_colo
+	0x72, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x20, 0x76, 0x5f, 0x74, // r0;.  float2 v_t
+	0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x73, 0x74, 0x72, // excoord0;.};.str
+	0x75, 0x63, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x53, 0x68, 0x61, 0x64, 0x65, // uct xlatMtlShade
+	0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x68, 0x61, 0x6c, 0x66, // rOutput {.  half
+	0x34, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, // 4 gl_FragColor;.
+	0x7d, 0x3b, 0x0a, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, // };.struct xlatMt
+	0x6c, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x7b, // lShaderUniform {
+	0x0a, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, 0x70, 0x61, 0x72, 0x61, // .  float4 u_para
+	0x6d, 0x73, 0x3b, 0x0a, 0x7d, 0x3b, 0x0a, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, // ms;.};.fragment 
+	0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x4f, 0x75, 0x74, // xlatMtlShaderOut
+	0x70, 0x75, 0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x4d, 0x61, 0x69, 0x6e, 0x20, // put xlatMtlMain 
+	0x28, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x49, 0x6e, // (xlatMtlShaderIn
+	0x70, 0x75, 0x74, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x69, 0x20, 0x5b, 0x5b, 0x73, 0x74, 0x61, // put _mtl_i [[sta
+	0x67, 0x65, 0x5f, 0x69, 0x6e, 0x5d, 0x5d, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, // ge_in]], constan
+	0x74, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x55, // t xlatMtlShaderU
+	0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x26, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x20, 0x5b, // niform& _mtl_u [
+	0x5b, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x0a, 0x20, 0x20, 0x2c, // [buffer(0)]].  ,
+	0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x64, 0x5f, 0x61, 0x72, 0x72, //    texture2d_arr
+	0x61, 0x79, 0x3c, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3e, 0x20, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, // ay<float> s_texC
+	0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x5b, 0x5b, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x30, // olor [[texture(0
+	0x29, 0x5d, 0x5d, 0x2c, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x20, 0x5f, 0x6d, 0x74, // )]], sampler _mt
+	0x6c, 0x73, 0x6d, 0x70, 0x5f, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, // lsmp_s_texColor 
+	0x5b, 0x5b, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x28, 0x30, 0x29, 0x5d, 0x5d, 0x29, 0x0a, // [[sampler(0)]]).
+	0x7b, 0x0a, 0x20, 0x20, 0x78, 0x6c, 0x61, 0x74, 0x4d, 0x74, 0x6c, 0x53, 0x68, 0x61, 0x64, 0x65, // {.  xlatMtlShade
+	0x72, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x6f, 0x3b, 0x0a, // rOutput _mtl_o;.
+	0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, //   float3 tmpvar_
+	0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, // 1;.  tmpvar_1.xy
+	0x20, 0x3d, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x69, 0x2e, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, //  = _mtl_i.v_texc
+	0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, // oord0;.  tmpvar_
+	0x31, 0x2e, 0x7a, 0x20, 0x3d, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x2e, 0x75, 0x5f, 0x70, // 1.z = _mtl_u.u_p
+	0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x79, 0x3b, 0x0a, 0x20, 0x20, 0x68, 0x61, 0x6c, 0x66, 0x34, // arams.y;.  half4
+	0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, //  tmpvar_2;.  tmp
+	0x76, 0x61, 0x72, 0x5f, 0x32, 0x20, 0x3d, 0x20, 0x68, 0x61, 0x6c, 0x66, 0x34, 0x28, 0x73, 0x5f, // var_2 = half4(s_
+	0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28, // texColor.sample(
+	0x5f, 0x6d, 0x74, 0x6c, 0x73, 0x6d, 0x70, 0x5f, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, // _mtlsmp_s_texCol
+	0x6f, 0x72, 0x2c, 0x20, 0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x32, 0x29, 0x28, 0x28, 0x74, 0x6d, // or, (float2)((tm
+	0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x29, 0x2e, 0x78, 0x79, 0x29, 0x2c, 0x20, 0x28, 0x75, 0x69, // pvar_1).xy), (ui
+	0x6e, 0x74, 0x29, 0x28, 0x28, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x29, 0x2e, 0x7a, // nt)((tmpvar_1).z
+	0x29, 0x2c, 0x20, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x28, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x75, 0x2e, // ), level(_mtl_u.
+	0x75, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2e, 0x78, 0x29, 0x29, 0x29, 0x3b, 0x0a, 0x20, // u_params.x)));. 
+	0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x6f, 0x2e, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, //  _mtl_o.gl_FragC
+	0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x28, 0x28, 0x68, 0x61, 0x6c, 0x66, 0x34, 0x29, 0x28, // olor = ((half4)(
+	0x28, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x29, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x32, // (float4)tmpvar_2
+	0x20, 0x2a, 0x20, 0x5f, 0x6d, 0x74, 0x6c, 0x5f, 0x69, 0x2e, 0x76, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, //  * _mtl_i.v_colo
+	0x72, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, // r0));.  return _
+	0x6d, 0x74, 0x6c, 0x5f, 0x6f, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00,                               // mtl_o;.}...
+};

+ 20 - 0
tools/texturev/fs_texture_array.sc

@@ -0,0 +1,20 @@
+$input v_texcoord0, v_color0
+
+/*
+ * Copyright 2011-2016 Branimir Karadzic. All rights reserved.
+ * License: http://www.opensource.org/licenses/BSD-2-Clause
+ */
+
+#include <bgfx_shader.sh>
+
+SAMPLER2DARRAY(s_texColor, 0);
+
+uniform vec4 u_params;
+#define u_textureLod   u_params.x
+#define u_textureLayer u_params.y
+
+void main()
+{
+	vec4 color = texture2DArrayLod(s_texColor, vec3(v_texcoord0, u_textureLayer), u_textureLod);
+	gl_FragColor = color * v_color0;
+}

+ 65 - 11
tools/texturev/texturev.cpp

@@ -19,6 +19,7 @@
 
 #include "vs_texture.bin.h"
 #include "fs_texture.bin.h"
+#include "fs_texture_array.bin.h"
 #include "vs_texture_cube.bin.h"
 #include "fs_texture_cube.bin.h"
 
@@ -82,6 +83,9 @@ static const InputBinding s_bindingView[] =
 	{ entry::Key::PageUp,    entry::Modifier::None,       1, NULL, "view file-pgup"   },
 	{ entry::Key::PageDown,  entry::Modifier::None,       1, NULL, "view file-pgdown" },
 
+	{ entry::Key::Left,      entry::Modifier::None,       1, NULL, "view layer prev"  },
+	{ entry::Key::Right,     entry::Modifier::None,       1, NULL, "view layer next"  },
+
 	{ entry::Key::KeyR,      entry::Modifier::None,       1, NULL, "view rgb r"       },
 	{ entry::Key::KeyG,      entry::Modifier::None,       1, NULL, "view rgb g"       },
 	{ entry::Key::KeyB,      entry::Modifier::None,       1, NULL, "view rgb b"       },
@@ -112,6 +116,7 @@ struct View
 		: m_fileIndex(0)
 		, m_scaleFn(0)
 		, m_mip(0)
+		, m_layer(0)
 		, m_abgr(UINT32_MAX)
 		, m_zoom(1.0f)
 		, m_filter(true)
@@ -156,6 +161,35 @@ struct View
 					m_mip = 0;
 				}
 			}
+			if (0 == strcmp(_argv[1], "layer") )
+			{
+				if (_argc >= 3)
+				{
+					uint32_t layer = m_layer;
+					if (0 == strcmp(_argv[2], "next") )
+					{
+						++layer;
+					}
+					else if (0 == strcmp(_argv[2], "prev") )
+					{
+						--layer;
+					}
+					else if (0 == strcmp(_argv[2], "last") )
+					{
+						layer = INT32_MAX;
+					}
+					else
+					{
+						layer = atoi(_argv[2]);
+					}
+
+					m_layer = bx::uint32_iclamp(layer, 0, m_info.numLayers-1);
+				}
+				else
+				{
+					m_layer = 0;
+				}
+			}
 			else if (0 == strcmp(_argv[1], "zoom") )
 			{
 				if (_argc >= 3)
@@ -296,6 +330,7 @@ struct View
 	uint32_t m_fileIndex;
 	uint32_t m_scaleFn;
 	uint32_t m_mip;
+	uint32_t m_layer;
 	uint32_t m_abgr;
 	float    m_zoom;
 	bool     m_filter;
@@ -611,6 +646,7 @@ int _main_(int _argc, char** _argv)
 
 	const bgfx::Memory* vs_texture;
 	const bgfx::Memory* fs_texture;
+	const bgfx::Memory* fs_texture_array;
 	const bgfx::Memory* vs_texture_cube;
 	const bgfx::Memory* fs_texture_cube;
 
@@ -632,19 +668,31 @@ int _main_(int _argc, char** _argv)
 		break;
 
 	default:
-		vs_texture      = bgfx::makeRef(vs_texture_glsl,      sizeof(vs_texture_glsl) );
-		fs_texture      = bgfx::makeRef(fs_texture_glsl,      sizeof(fs_texture_glsl) );
-		vs_texture_cube = bgfx::makeRef(vs_texture_cube_glsl, sizeof(vs_texture_cube_glsl) );
-		fs_texture_cube = bgfx::makeRef(fs_texture_cube_glsl, sizeof(fs_texture_cube_glsl) );
+		vs_texture       = bgfx::makeRef(vs_texture_glsl,       sizeof(vs_texture_glsl) );
+		fs_texture       = bgfx::makeRef(fs_texture_glsl,       sizeof(fs_texture_glsl) );
+		fs_texture_array = bgfx::makeRef(fs_texture_array_glsl, sizeof(fs_texture_array_glsl) );
+		fs_texture       = bgfx::makeRef(fs_texture_glsl,       sizeof(fs_texture_glsl) );
+		vs_texture_cube  = bgfx::makeRef(vs_texture_cube_glsl,  sizeof(vs_texture_cube_glsl) );
+		fs_texture_cube  = bgfx::makeRef(fs_texture_cube_glsl,  sizeof(fs_texture_cube_glsl) );
 		break;
 	}
 
+	bgfx::ShaderHandle vsTexture = bgfx::createShader(vs_texture);
+
 	bgfx::ProgramHandle textureProgram = bgfx::createProgram(
-			  bgfx::createShader(vs_texture)
+			  vsTexture
 			, bgfx::createShader(fs_texture)
 			, true
 			);
 
+	bgfx::ProgramHandle textureArrayProgram = bgfx::createProgram(
+			  vsTexture
+			, bgfx::createShader(fs_texture_array)
+			, true
+			);
+
+	bgfx::destroyShader(vsTexture);
+
 	bgfx::ProgramHandle textureCubeProgram = bgfx::createProgram(
 			  bgfx::createShader(vs_texture_cube)
 			, bgfx::createShader(fs_texture_cube)
@@ -658,9 +706,10 @@ int _main_(int _argc, char** _argv)
 	float speed = 0.37f;
 	float time  = 0.0f;
 
-	Interpolator mip(0.0);
-	Interpolator zoom(1.0);
-	Interpolator scale(1.0);
+	Interpolator mip(0.0f);
+	Interpolator layer(0.0f);
+	Interpolator zoom(1.0f);
+	Interpolator scale(1.0f);
 
 	const char* filePath = _argc < 2 ? "" : _argv[1];
 	bool directory = false;
@@ -849,9 +898,10 @@ int _main_(int _argc, char** _argv)
 			bx::mtxRotateXY(mtx, 0.0f, time);
 			bgfx::setUniform(u_mtx, mtx);
 
-			mip.set( float(view.m_mip), 0.5f);
+			mip.set(float(view.m_mip), 0.5f);
+			layer.set(float(view.m_layer), 0.25f);
 
-			float params[4] = { mip.getValue(), 0.0f, 0.0f, 0.0f };
+			float params[4] = { mip.getValue(), layer.getValue(), 0.0f, 0.0f };
 			bgfx::setUniform(u_params, params);
 
 			bgfx::setTexture(0
@@ -869,7 +919,10 @@ int _main_(int _argc, char** _argv)
 				| BGFX_STATE_ALPHA_WRITE
 				| (view.m_alpha ? BGFX_STATE_BLEND_ALPHA : BGFX_STATE_NONE)
 				);
-			bgfx::submit(0, view.m_info.cubeMap ? textureCubeProgram : textureProgram);
+			bgfx::submit(0, view.m_info.cubeMap ? textureCubeProgram
+					: 1 < view.m_info.numLayers ? textureArrayProgram
+												: textureProgram
+					);
 
 			bgfx::frame();
 		}
@@ -883,6 +936,7 @@ int _main_(int _argc, char** _argv)
 	bgfx::destroyUniform(u_mtx);
 	bgfx::destroyUniform(u_params);
 	bgfx::destroyProgram(textureProgram);
+	bgfx::destroyProgram(textureArrayProgram);
 	bgfx::destroyProgram(textureCubeProgram);
 
 	imguiDestroy();