Add Vulkan port of the GLES3 texture mipmap tests
authorZoltan Janos Szabo <zjs.u-szeged@partner.samsung.com>
Fri, 15 Jul 2016 10:21:05 +0000 (12:21 +0200)
committerPyry Haulos <phaulos@google.com>
Thu, 15 Sep 2016 21:38:29 +0000 (14:38 -0700)
Change-Id: I5c5d9d83a7f284cf0f561d4a4725f95e37cb2842

android/cts/master/vk-master.txt
external/vulkancts/modules/vulkan/texture/CMakeLists.txt
external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/texture/vktTextureTests.cpp
external/vulkancts/mustpass/1.0.1/src/excluded-tests.txt
external/vulkancts/mustpass/1.0.1/vk-default.txt

index f2e4dbd..72aae55 100644 (file)
@@ -118983,3 +118983,239 @@ dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_cla
 dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_clamp_to_edge_mirror_clamp_to_edge_clamp_to_edge
 dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_clamp_to_edge_mirror_clamp_to_edge_clamp_to_border
 dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_clamp_to_edge_mirror_clamp_to_edge_mirror_clamp_to_edge
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_mirror_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_clamp
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_repeat
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_mirror
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_mirror_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_clamp
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_repeat
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_mirror
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_mirror_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_clamp
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_repeat
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_mirror
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_mirror_non_square
+dEQP-VK.texture.mipmap.2d.affine.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.2d.affine.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.2d.affine.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.2d.affine.linear_nearest_clamp
+dEQP-VK.texture.mipmap.2d.affine.linear_nearest_repeat
+dEQP-VK.texture.mipmap.2d.affine.linear_nearest_mirror
+dEQP-VK.texture.mipmap.2d.affine.nearest_linear_clamp
+dEQP-VK.texture.mipmap.2d.affine.nearest_linear_repeat
+dEQP-VK.texture.mipmap.2d.affine.nearest_linear_mirror
+dEQP-VK.texture.mipmap.2d.affine.linear_linear_clamp
+dEQP-VK.texture.mipmap.2d.affine.linear_linear_repeat
+dEQP-VK.texture.mipmap.2d.affine.linear_linear_mirror
+dEQP-VK.texture.mipmap.2d.projected.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.2d.projected.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.2d.projected.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.2d.projected.linear_nearest_clamp
+dEQP-VK.texture.mipmap.2d.projected.linear_nearest_repeat
+dEQP-VK.texture.mipmap.2d.projected.linear_nearest_mirror
+dEQP-VK.texture.mipmap.2d.projected.nearest_linear_clamp
+dEQP-VK.texture.mipmap.2d.projected.nearest_linear_repeat
+dEQP-VK.texture.mipmap.2d.projected.nearest_linear_mirror
+dEQP-VK.texture.mipmap.2d.projected.linear_linear_clamp
+dEQP-VK.texture.mipmap.2d.projected.linear_linear_repeat
+dEQP-VK.texture.mipmap.2d.projected.linear_linear_mirror
+dEQP-VK.texture.mipmap.2d.bias.nearest_nearest
+dEQP-VK.texture.mipmap.2d.bias.linear_nearest
+dEQP-VK.texture.mipmap.2d.bias.nearest_linear
+dEQP-VK.texture.mipmap.2d.bias.linear_linear
+dEQP-VK.texture.mipmap.2d.min_lod.nearest_nearest
+dEQP-VK.texture.mipmap.2d.min_lod.linear_nearest
+dEQP-VK.texture.mipmap.2d.min_lod.nearest_linear
+dEQP-VK.texture.mipmap.2d.min_lod.linear_linear
+dEQP-VK.texture.mipmap.2d.max_lod.nearest_nearest
+dEQP-VK.texture.mipmap.2d.max_lod.linear_nearest
+dEQP-VK.texture.mipmap.2d.max_lod.nearest_linear
+dEQP-VK.texture.mipmap.2d.max_lod.linear_linear
+dEQP-VK.texture.mipmap.2d.base_level.nearest_nearest
+dEQP-VK.texture.mipmap.2d.base_level.linear_nearest
+dEQP-VK.texture.mipmap.2d.base_level.nearest_linear
+dEQP-VK.texture.mipmap.2d.base_level.linear_linear
+dEQP-VK.texture.mipmap.2d.max_level.nearest_nearest
+dEQP-VK.texture.mipmap.2d.max_level.linear_nearest
+dEQP-VK.texture.mipmap.2d.max_level.nearest_linear
+dEQP-VK.texture.mipmap.2d.max_level.linear_linear
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.min_lod.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.min_lod.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.min_lod.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.min_lod.linear_linear
+dEQP-VK.texture.mipmap.cubemap.max_lod.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.max_lod.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.max_lod.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.max_lod.linear_linear
+dEQP-VK.texture.mipmap.cubemap.base_level.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.base_level.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.base_level.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.base_level.linear_linear
+dEQP-VK.texture.mipmap.cubemap.max_level.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.max_level.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.max_level.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.max_level.linear_linear
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_mirror_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_clamp
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_repeat
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_mirror
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_mirror_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_clamp
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_repeat
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_mirror
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_mirror_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_clamp
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_repeat
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_mirror
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_mirror_npot
+dEQP-VK.texture.mipmap.3d.affine.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.3d.affine.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.3d.affine.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.3d.affine.linear_nearest_clamp
+dEQP-VK.texture.mipmap.3d.affine.linear_nearest_repeat
+dEQP-VK.texture.mipmap.3d.affine.linear_nearest_mirror
+dEQP-VK.texture.mipmap.3d.affine.nearest_linear_clamp
+dEQP-VK.texture.mipmap.3d.affine.nearest_linear_repeat
+dEQP-VK.texture.mipmap.3d.affine.nearest_linear_mirror
+dEQP-VK.texture.mipmap.3d.affine.linear_linear_clamp
+dEQP-VK.texture.mipmap.3d.affine.linear_linear_repeat
+dEQP-VK.texture.mipmap.3d.affine.linear_linear_mirror
+dEQP-VK.texture.mipmap.3d.projected.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.3d.projected.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.3d.projected.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.3d.projected.linear_nearest_clamp
+dEQP-VK.texture.mipmap.3d.projected.linear_nearest_repeat
+dEQP-VK.texture.mipmap.3d.projected.linear_nearest_mirror
+dEQP-VK.texture.mipmap.3d.projected.nearest_linear_clamp
+dEQP-VK.texture.mipmap.3d.projected.nearest_linear_repeat
+dEQP-VK.texture.mipmap.3d.projected.nearest_linear_mirror
+dEQP-VK.texture.mipmap.3d.projected.linear_linear_clamp
+dEQP-VK.texture.mipmap.3d.projected.linear_linear_repeat
+dEQP-VK.texture.mipmap.3d.projected.linear_linear_mirror
+dEQP-VK.texture.mipmap.3d.bias.nearest_nearest
+dEQP-VK.texture.mipmap.3d.bias.linear_nearest
+dEQP-VK.texture.mipmap.3d.bias.nearest_linear
+dEQP-VK.texture.mipmap.3d.bias.linear_linear
+dEQP-VK.texture.mipmap.3d.min_lod.nearest_nearest
+dEQP-VK.texture.mipmap.3d.min_lod.linear_nearest
+dEQP-VK.texture.mipmap.3d.min_lod.nearest_linear
+dEQP-VK.texture.mipmap.3d.min_lod.linear_linear
+dEQP-VK.texture.mipmap.3d.max_lod.nearest_nearest
+dEQP-VK.texture.mipmap.3d.max_lod.linear_nearest
+dEQP-VK.texture.mipmap.3d.max_lod.nearest_linear
+dEQP-VK.texture.mipmap.3d.max_lod.linear_linear
+dEQP-VK.texture.mipmap.3d.base_level.nearest_nearest
+dEQP-VK.texture.mipmap.3d.base_level.linear_nearest
+dEQP-VK.texture.mipmap.3d.base_level.nearest_linear
+dEQP-VK.texture.mipmap.3d.base_level.linear_linear
+dEQP-VK.texture.mipmap.3d.max_level.nearest_nearest
+dEQP-VK.texture.mipmap.3d.max_level.linear_nearest
+dEQP-VK.texture.mipmap.3d.max_level.nearest_linear
+dEQP-VK.texture.mipmap.3d.max_level.linear_linear
index 530b74e..5b217e0 100644 (file)
@@ -7,6 +7,8 @@ set(DEQP_VK_TEXTURE_SRCS
        vktTextureTestUtil.hpp
        vktTextureFilteringTests.cpp
        vktTextureFilteringTests.hpp
+       vktTextureMipmapTests.cpp
+       vktTextureMipmapTests.hpp
        )
 
 set(DEQP_VK_TEXTURE_LIBS
diff --git a/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.cpp b/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.cpp
new file mode 100644 (file)
index 0000000..4c210d7
--- /dev/null
@@ -0,0 +1,2154 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Mipmapping tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTextureMipmapTests.hpp"
+
+#include "deRandom.hpp"
+#include "deString.h"
+#include "gluShaderUtil.hpp"
+#include "gluTextureTestUtil.hpp"
+#include "tcuMatrix.hpp"
+#include "tcuMatrixUtil.hpp"
+#include "tcuPixelFormat.hpp"
+#include "tcuTexLookupVerifier.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuVectorUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vktTextureTestUtil.hpp"
+
+using namespace vk;
+
+namespace vkt
+{
+namespace texture
+{
+namespace
+{
+
+using std::string;
+using std::vector;
+using tcu::TestLog;
+using tcu::Vec2;
+using tcu::Vec3;
+using tcu::Vec4;
+using tcu::IVec4;
+using tcu::Sampler;
+using tcu::TextureFormat;
+using namespace texture::util;
+using namespace glu::TextureTestUtil;
+
+float getMinLodForCell (int cellNdx)
+{
+       static const float s_values[] =
+       {
+               1.0f,
+               3.5f,
+               2.0f,
+               -2.0f,
+               0.0f,
+               3.0f,
+               10.0f,
+               4.8f,
+               5.8f,
+               5.7f,
+               -1.9f,
+               4.0f,
+               6.5f,
+               7.1f,
+               -1e10,
+               1000.f
+       };
+       return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
+}
+
+float getMaxLodForCell (int cellNdx)
+{
+       static const float s_values[] =
+       {
+               0.0f,
+               0.2f,
+               0.7f,
+               0.4f,
+               1.3f,
+               0.0f,
+               0.5f,
+               1.2f,
+               -2.0f,
+               1.0f,
+               0.1f,
+               0.3f,
+               2.7f,
+               1.2f,
+               10.0f,
+               -1000.f,
+               1e10f
+       };
+       return s_values[cellNdx % DE_LENGTH_OF_ARRAY(s_values)];
+}
+
+enum CoordType
+{
+       COORDTYPE_BASIC,                //!< texCoord = translateScale(position).
+       COORDTYPE_BASIC_BIAS,   //!< Like basic, but with bias values.
+       COORDTYPE_AFFINE,               //!< texCoord = translateScaleRotateShear(position).
+       COORDTYPE_PROJECTED,    //!< Projected coordinates, w != 1
+
+       COORDTYPE_LAST
+};
+
+struct TextureMipmapCommonTestCaseParameters
+{
+                                                       TextureMipmapCommonTestCaseParameters           (void);
+       CoordType                               coordType;
+       const char*                             minFilterName;
+};
+
+TextureMipmapCommonTestCaseParameters::TextureMipmapCommonTestCaseParameters (void)
+       : coordType                             (COORDTYPE_BASIC)
+       , minFilterName                 (NULL)
+{
+}
+
+struct Texture2DMipmapTestCaseParameters : public Texture2DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
+{
+};
+
+struct TextureCubeMipmapTestCaseParameters : public TextureCubeTestCaseParameters, public TextureMipmapCommonTestCaseParameters
+{
+};
+
+struct Texture3DMipmapTestCaseParameters : public Texture3DTestCaseParameters, public TextureMipmapCommonTestCaseParameters
+{
+};
+
+// Texture2DMipmapTestInstance
+class Texture2DMipmapTestInstance : public TestInstance
+{
+public:
+       typedef Texture2DMipmapTestCaseParameters       ParameterType;
+
+                                                                       Texture2DMipmapTestInstance             (Context& context, const ParameterType& testParameters);
+                                                                       ~Texture2DMipmapTestInstance    (void);
+
+       virtual tcu::TestStatus                 iterate                                                 (void);
+
+private:
+                                                                       Texture2DMipmapTestInstance             (const Texture2DMipmapTestInstance& other);
+       Texture2DMipmapTestInstance&    operator=                                               (const Texture2DMipmapTestInstance& other);
+
+       const ParameterType                             m_testParameters;
+       TestTexture2DSp                                 m_texture;
+       TextureRenderer                                 m_renderer;
+};
+
+Texture2DMipmapTestInstance::Texture2DMipmapTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
+       : TestInstance          (context)
+       , m_testParameters      (testParameters)
+       , m_renderer            (context, testParameters.sampleCount, testParameters.width*4, testParameters.height*4)
+{
+       TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
+
+       m_texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height));
+
+       const int numLevels = deLog2Floor32(de::max(m_testParameters.width, m_testParameters.height))+1;
+
+       // Fill texture with colored grid.
+       for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+       {
+               const deUint32  step    = 0xff / (numLevels-1);
+               const deUint32  inc             = deClamp32(step*levelNdx, 0x00, 0xff);
+               const deUint32  dec             = 0xff - inc;
+               const deUint32  rgb             = (inc << 16) | (dec << 8) | 0xff;
+               const deUint32  color   = 0xff000000 | rgb;
+
+               tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec());
+       }
+
+       // Upload texture data.
+       m_renderer.add2DTexture(m_texture);
+}
+
+Texture2DMipmapTestInstance::~Texture2DMipmapTestInstance (void)
+{
+}
+
+static void getBasicTexCoord2D (std::vector<float>& dst, int cellNdx)
+{
+       static const struct
+       {
+               const Vec2      bottomLeft;
+               const Vec2      topRight;
+       } s_basicCoords[] =
+       {
+               { Vec2(-0.1f,  0.1f), Vec2( 0.8f,  1.0f) },
+               { Vec2(-0.3f, -0.6f), Vec2( 0.7f,  0.4f) },
+               { Vec2(-0.3f,  0.6f), Vec2( 0.7f, -0.9f) },
+               { Vec2(-0.8f,  0.6f), Vec2( 0.7f, -0.9f) },
+
+               { Vec2(-0.5f, -0.5f), Vec2( 1.5f,  1.5f) },
+               { Vec2( 1.0f, -1.0f), Vec2(-1.3f,  1.0f) },
+               { Vec2( 1.2f, -1.0f), Vec2(-1.3f,  1.6f) },
+               { Vec2( 2.2f, -1.1f), Vec2(-1.3f,  0.8f) },
+
+               { Vec2(-1.5f,  1.6f), Vec2( 1.7f, -1.4f) },
+               { Vec2( 2.0f,  1.6f), Vec2( 2.3f, -1.4f) },
+               { Vec2( 1.3f, -2.6f), Vec2(-2.7f,  2.9f) },
+               { Vec2(-0.8f, -6.6f), Vec2( 6.0f, -0.9f) },
+
+               { Vec2( -8.0f,   9.0f), Vec2(  8.3f,  -7.0f) },
+               { Vec2(-16.0f,  10.0f), Vec2( 18.3f,  24.0f) },
+               { Vec2( 30.2f,  55.0f), Vec2(-24.3f,  -1.6f) },
+               { Vec2(-33.2f,  64.1f), Vec2( 32.1f, -64.1f) },
+       };
+
+       DE_ASSERT(de::inBounds(cellNdx, 0, DE_LENGTH_OF_ARRAY(s_basicCoords)));
+
+       const Vec2& bottomLeft  = s_basicCoords[cellNdx].bottomLeft;
+       const Vec2& topRight    = s_basicCoords[cellNdx].topRight;
+
+       computeQuadTexCoord2D(dst, bottomLeft, topRight);
+}
+
+static void getAffineTexCoord2D (std::vector<float>& dst, int cellNdx)
+{
+       // Use basic coords as base.
+       getBasicTexCoord2D(dst, cellNdx);
+
+       // Rotate based on cell index.
+       const float             angle           = 2.0f*DE_PI * ((float)cellNdx / 16.0f);
+       const tcu::Mat2 rotMatrix       = tcu::rotationMatrix(angle);
+
+       // Second and third row are sheared.
+       const float             shearX          = de::inRange(cellNdx, 4, 11) ? (float)(15-cellNdx) / 16.0f : 0.0f;
+       const tcu::Mat2 shearMatrix     = tcu::shearMatrix(tcu::Vec2(shearX, 0.0f));
+
+       const tcu::Mat2 transform       = rotMatrix * shearMatrix;
+       const Vec2              p0                      = transform * Vec2(dst[0], dst[1]);
+       const Vec2              p1                      = transform * Vec2(dst[2], dst[3]);
+       const Vec2              p2                      = transform * Vec2(dst[4], dst[5]);
+       const Vec2              p3                      = transform * Vec2(dst[6], dst[7]);
+
+       dst[0] = p0.x();        dst[1] = p0.y();
+       dst[2] = p1.x();        dst[3] = p1.y();
+       dst[4] = p2.x();        dst[5] = p2.y();
+       dst[6] = p3.x();        dst[7] = p3.y();
+}
+
+tcu::TestStatus Texture2DMipmapTestInstance::iterate (void)
+{
+       const Sampler::FilterMode       magFilter               = Sampler::NEAREST;
+       const int                                       viewportWidth   = m_renderer.getRenderWidth();
+       const int                                       viewportHeight  = m_renderer.getRenderHeight();
+
+       ReferenceParams                         refParams               (TEXTURETYPE_2D);
+       vector<float>                           texCoord;
+
+       const bool                                      isProjected             = m_testParameters.coordType == COORDTYPE_PROJECTED;
+       const bool                                      useLodBias              = m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
+
+       tcu::Surface                            renderedFrame   (viewportWidth, viewportHeight);
+
+       // Viewport is divided into 4x4 grid.
+       const int                                       gridWidth               = 4;
+       const int                                       gridHeight              = 4;
+       const int                                       cellWidth               = viewportWidth / gridWidth;
+       const int                                       cellHeight              = viewportHeight / gridHeight;
+
+       // Sampling parameters.
+       refParams.sampler               = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, magFilter);
+       refParams.samplerType   = getSamplerType(vk::mapVkFormat(m_testParameters.format));
+       refParams.flags                 = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
+       refParams.lodMode               = LODMODE_EXACT; // Use ideal lod.
+
+       // Bias values.
+       static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
+
+       // Projection values.
+       static const Vec4 s_projections[] =
+       {
+               Vec4(1.2f, 1.0f, 0.7f, 1.0f),
+               Vec4(1.3f, 0.8f, 0.6f, 2.0f),
+               Vec4(0.8f, 1.0f, 1.7f, 0.6f),
+               Vec4(1.2f, 1.0f, 1.7f, 1.5f)
+       };
+
+       // Render cells.
+       for (int gridY = 0; gridY < gridHeight; gridY++)
+       {
+               for (int gridX = 0; gridX < gridWidth; gridX++)
+               {
+                       const int       curX            = cellWidth*gridX;
+                       const int       curY            = cellHeight*gridY;
+                       const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                       const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                       const int       cellNdx         = gridY*gridWidth + gridX;
+
+                       // Compute texcoord.
+                       switch (m_testParameters.coordType)
+                       {
+                               case COORDTYPE_BASIC_BIAS:      // Fall-through.
+                               case COORDTYPE_PROJECTED:
+                               case COORDTYPE_BASIC:           getBasicTexCoord2D      (texCoord, cellNdx);    break;
+                               case COORDTYPE_AFFINE:          getAffineTexCoord2D     (texCoord, cellNdx);    break;
+                               default:                                        DE_ASSERT(DE_FALSE);
+                       }
+
+                       if (isProjected)
+                               refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
+
+                       if (useLodBias)
+                               refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
+
+                       m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
+                       m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
+               }
+       }
+
+       // Compare and log.
+       {
+               const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
+               const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
+               const bool                              isTrilinear             = m_testParameters.minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_testParameters.minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
+               tcu::Surface                    referenceFrame  (viewportWidth, viewportHeight);
+               tcu::Surface                    errorMask               (viewportWidth, viewportHeight);
+               tcu::LookupPrecision    lookupPrec;
+               tcu::LodPrecision               lodPrec;
+               int                                             numFailedPixels = 0;
+
+               lookupPrec.coordBits            = tcu::IVec3(20, 20, 0);
+               lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
+               lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
+               lookupPrec.colorMask            = getCompareMask(pixelFormat);
+               lodPrec.derivateBits            = 10;
+               lodPrec.lodBits                         = isProjected ? 6 : 8;
+
+               for (int gridY = 0; gridY < gridHeight; gridY++)
+               {
+                       for (int gridX = 0; gridX < gridWidth; gridX++)
+                       {
+                               const int       curX            = cellWidth*gridX;
+                               const int       curY            = cellHeight*gridY;
+                               const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                               const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                               const int       cellNdx         = gridY*gridWidth + gridX;
+
+                               // Compute texcoord.
+                               switch (m_testParameters.coordType)
+                               {
+                                       case COORDTYPE_BASIC_BIAS:      // Fall-through.
+                                       case COORDTYPE_PROJECTED:
+                                       case COORDTYPE_BASIC:           getBasicTexCoord2D      (texCoord, cellNdx);    break;
+                                       case COORDTYPE_AFFINE:          getAffineTexCoord2D     (texCoord, cellNdx);    break;
+                                       default:                                        DE_ASSERT(DE_FALSE);
+                               }
+
+                               if (isProjected)
+                                       refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
+
+                               if (useLodBias)
+                                       refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
+
+                               // Render ideal result
+                               sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
+                                                         m_texture->getTexture(), &texCoord[0], refParams);
+
+                               // Compare this cell
+                               numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
+                                                                                                                       m_texture->getTexture(), &texCoord[0], refParams,
+                                                                                                                       lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
+                       }
+               }
+
+               if (numFailedPixels > 0)
+                       m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
+
+               m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
+                                                                                       << TestLog::Image("Rendered", "Rendered image", renderedFrame);
+
+               if (numFailedPixels > 0)
+               {
+                       m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
+                                                                                               << TestLog::Image("ErrorMask", "Error mask", errorMask);
+               }
+
+               m_context.getTestContext().getLog() << TestLog::EndImageSet;
+
+               {
+                       const bool isOk = numFailedPixels == 0;
+                       return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
+               }
+       }
+}
+
+// TextureCubeMipmapTestInstance
+class TextureCubeMipmapTestInstance : public TestInstance
+{
+public:
+       typedef TextureCubeMipmapTestCaseParameters     ParameterType;
+
+                                                                       TextureCubeMipmapTestInstance   (Context& context, const ParameterType& testParameters);
+                                                                       ~TextureCubeMipmapTestInstance  (void);
+
+       virtual tcu::TestStatus                 iterate                                                 (void);
+
+private:
+                                                                       TextureCubeMipmapTestInstance   (const TextureCubeMipmapTestInstance& other);
+       TextureCubeMipmapTestInstance&  operator=                                               (const TextureCubeMipmapTestInstance& other);
+
+       const ParameterType                             m_testParameters;
+       TestTextureCubeSp                               m_texture;
+       TextureRenderer                                 m_renderer;
+};
+
+TextureCubeMipmapTestInstance::TextureCubeMipmapTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
+       : TestInstance          (context)
+       , m_testParameters      (testParameters)
+       , m_renderer            (context, m_testParameters.sampleCount, m_testParameters.size*2, m_testParameters.size*2)
+{
+       TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
+
+       m_texture = TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(m_testParameters.format), m_testParameters.size));
+
+       const int numLevels = deLog2Floor32(m_testParameters.size)+1;
+
+       // Fill texture with colored grid.
+       for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
+       {
+               for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+               {
+                       const deUint32  step    = 0xff / (numLevels-1);
+                       const deUint32  inc             = deClamp32(step*levelNdx, 0x00, 0xff);
+                       const deUint32  dec             = 0xff - inc;
+                       deUint32                rgb             = 0;
+
+                       switch (faceNdx)
+                       {
+                               case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
+                               case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
+                               case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
+                               case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
+                               case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
+                               case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
+                       }
+
+                       const deUint32  color   = 0xff000000 | rgb;
+                       tcu::clear(m_texture->getLevel(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
+               }
+       }
+
+       m_renderer.addCubeTexture(m_texture);
+}
+
+TextureCubeMipmapTestInstance::~TextureCubeMipmapTestInstance (void)
+{
+}
+
+static void randomPartition (vector<IVec4>& dst, de::Random& rnd, int x, int y, int width, int height)
+{
+       const int       minWidth        = 8;
+       const int       minHeight       = 8;
+
+       const bool      partition       = rnd.getFloat() > 0.4f;
+       const bool      partitionX      = partition && width > minWidth && rnd.getBool();
+       const bool      partitionY      = partition && height > minHeight && !partitionX;
+
+       if (partitionX)
+       {
+               const int split = width/2 + rnd.getInt(-width/4, +width/4);
+               randomPartition(dst, rnd, x, y, split, height);
+               randomPartition(dst, rnd, x+split, y, width-split, height);
+       }
+       else if (partitionY)
+       {
+               const int split = height/2 + rnd.getInt(-height/4, +height/4);
+               randomPartition(dst, rnd, x, y, width, split);
+               randomPartition(dst, rnd, x, y+split, width, height-split);
+       }
+       else
+               dst.push_back(IVec4(x, y, width, height));
+}
+
+static void computeGridLayout (vector<IVec4>& dst, int width, int height)
+{
+       de::Random rnd(7);
+       randomPartition(dst, rnd, 0, 0, width, height);
+}
+
+tcu::TestStatus TextureCubeMipmapTestInstance::iterate (void)
+{
+       const int                       viewportWidth   = m_renderer.getRenderWidth();
+       const int                       viewportHeight  = m_renderer.getRenderHeight();
+
+       const bool                      isProjected             = m_testParameters.coordType == COORDTYPE_PROJECTED;
+       const bool                      useLodBias              = m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
+
+       ReferenceParams         refParams               (TEXTURETYPE_CUBE);
+       vector<float>           texCoord;
+       tcu::Surface            renderedFrame   (viewportWidth, viewportHeight);
+
+       refParams.sampler               = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
+       refParams.samplerType   = getSamplerType(vk::mapVkFormat(m_testParameters.format));
+       refParams.flags                 = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
+       refParams.lodMode               = LODMODE_EXACT; // Use ideal lod.
+
+       // Compute grid.
+       vector<IVec4> gridLayout;
+       computeGridLayout(gridLayout, viewportWidth, viewportHeight);
+
+       // Bias values.
+       static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
+
+       // Projection values \note Less agressive than in 2D case due to smaller quads.
+       static const Vec4 s_projections[] =
+       {
+               Vec4(1.2f, 1.0f, 0.7f, 1.0f),
+               Vec4(1.3f, 0.8f, 0.6f, 1.1f),
+               Vec4(0.8f, 1.0f, 1.2f, 0.8f),
+               Vec4(1.2f, 1.0f, 1.3f, 0.9f)
+       };
+
+       // Render with GL
+       for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
+       {
+               const float                     curX            = (float)gridLayout[cellNdx].x();
+               const float                     curY            = (float)gridLayout[cellNdx].y();
+               const float                     curW            = (float)gridLayout[cellNdx].z();
+               const float                     curH            = (float)gridLayout[cellNdx].w();
+               const tcu::CubeFace     cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
+
+               DE_ASSERT(m_testParameters.coordType != COORDTYPE_AFFINE); // Not supported.
+               computeQuadTexCoordCube(texCoord, cubeFace);
+
+               if (isProjected)
+               {
+                       refParams.flags |= ReferenceParams::PROJECTED;
+                       refParams.w              = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
+               }
+
+               if (useLodBias)
+               {
+                       refParams.flags |= ReferenceParams::USE_BIAS;
+                       refParams.bias   = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
+               }
+
+               // Render
+               m_renderer.setViewport(curX, curY, curW, curH);
+               m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
+       }
+
+       // Render reference and compare
+       {
+               const tcu::IVec4                formatBitDepth          = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
+               const tcu::PixelFormat  pixelFormat                     (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
+               tcu::Surface                    referenceFrame          (viewportWidth, viewportHeight);
+               tcu::Surface                    errorMask                       (viewportWidth, viewportHeight);
+               int                                             numFailedPixels         = 0;
+               tcu::LookupPrecision    lookupPrec;
+               tcu::LodPrecision               lodPrec;
+
+               // Params for rendering reference
+               refParams.sampler                                       = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, m_testParameters.magFilter);
+               refParams.sampler.seamlessCubeMap       = true;
+               refParams.lodMode                                       = LODMODE_EXACT;
+
+               // Comparison parameters
+               lookupPrec.colorMask            = getCompareMask(pixelFormat);
+               lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat)-2, tcu::IVec4(0)));
+               lookupPrec.coordBits            = isProjected ? tcu::IVec3(8) : tcu::IVec3(10);
+               lookupPrec.uvwBits                      = tcu::IVec3(5,5,0);
+               lodPrec.derivateBits            = 10;
+               lodPrec.lodBits                         = isProjected ? 3 : 6;
+
+               for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
+               {
+                       const int                               curX            = gridLayout[cellNdx].x();
+                       const int                               curY            = gridLayout[cellNdx].y();
+                       const int                               curW            = gridLayout[cellNdx].z();
+                       const int                               curH            = gridLayout[cellNdx].w();
+                       const tcu::CubeFace             cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
+
+                       DE_ASSERT(m_testParameters.coordType != COORDTYPE_AFFINE); // Not supported.
+                       computeQuadTexCoordCube(texCoord, cubeFace);
+
+                       if (isProjected)
+                       {
+                               refParams.flags |= ReferenceParams::PROJECTED;
+                               refParams.w              = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
+                       }
+
+                       if (useLodBias)
+                       {
+                               refParams.flags |= ReferenceParams::USE_BIAS;
+                               refParams.bias   = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
+                       }
+
+                       // Render ideal reference.
+                       {
+                               tcu::SurfaceAccess idealDst(referenceFrame, pixelFormat, curX, curY, curW, curH);
+                               sampleTexture(idealDst, m_texture->getTexture(), &texCoord[0], refParams);
+                       }
+
+                       // Compare this cell
+                       numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                               tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                               tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
+                                                                                                               m_texture->getTexture(), &texCoord[0], refParams,
+                                                                                                               lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
+               }
+
+               if (numFailedPixels > 0)
+               {
+                       m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
+               }
+
+               m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
+                                                                                       << TestLog::Image("Rendered", "Rendered image", renderedFrame);
+
+               if (numFailedPixels > 0)
+               {
+                       m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
+                                                                                               << TestLog::Image("ErrorMask", "Error mask", errorMask);
+               }
+
+               m_context.getTestContext().getLog() << TestLog::EndImageSet;
+
+               {
+                       const bool isOk = numFailedPixels == 0;
+                       return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
+               }
+       }
+}
+
+// Texture3DMipmapTestInstance
+class Texture3DMipmapTestInstance : public TestInstance
+{
+public:
+       typedef Texture3DMipmapTestCaseParameters       ParameterType;
+
+                                                                       Texture3DMipmapTestInstance             (Context& context, const ParameterType& testParameters);
+                                                                       ~Texture3DMipmapTestInstance    (void);
+
+       virtual tcu::TestStatus                 iterate                                                 (void);
+
+private:
+                                                                       Texture3DMipmapTestInstance             (const Texture3DMipmapTestInstance& other);
+       Texture3DMipmapTestInstance&    operator=                                               (const Texture3DMipmapTestInstance& other);
+
+       const ParameterType                             m_testParameters;
+       TestTexture3DSp                                 m_texture;
+       TextureRenderer                                 m_renderer;
+};
+
+Texture3DMipmapTestInstance::Texture3DMipmapTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
+       : TestInstance          (context)
+       , m_testParameters      (testParameters)
+       , m_renderer            (context, testParameters.sampleCount, testParameters.width*4, testParameters.height*4)
+{
+       TCU_CHECK_INTERNAL(!(m_testParameters.coordType == COORDTYPE_PROJECTED && m_testParameters.sampleCount != VK_SAMPLE_COUNT_1_BIT));
+
+       const tcu::TextureFormat&       texFmt          = mapVkFormat(testParameters.format);
+       tcu::TextureFormatInfo          fmtInfo         = tcu::getTextureFormatInfo(texFmt);
+       const tcu::Vec4&                        cScale          = fmtInfo.lookupScale;
+       const tcu::Vec4&                        cBias           = fmtInfo.lookupBias;
+       const int                                       numLevels       = deLog2Floor32(de::max(de::max(testParameters.width, testParameters.height), testParameters.depth))+1;
+
+       m_texture = TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(m_testParameters.format), m_testParameters.width, m_testParameters.height, m_testParameters.depth));
+
+       // Fill texture with colored grid.
+       for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+       {
+               const deUint32  step    = 0xff / (numLevels-1);
+               const deUint32  inc             = deClamp32(step*levelNdx, 0x00, 0xff);
+               const deUint32  dec             = 0xff - inc;
+               const deUint32  rgb             = (0xff << 16) | (dec << 8) | inc;
+               const deUint32  color   = 0xff000000 | rgb;
+
+               tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec()*cScale + cBias);
+       }
+
+       m_renderer.add3DTexture(m_texture);
+}
+
+Texture3DMipmapTestInstance::~Texture3DMipmapTestInstance (void)
+{
+}
+
+static void getBasicTexCoord3D (std::vector<float>& dst, int cellNdx)
+{
+       static const struct
+       {
+               const float sScale;
+               const float sBias;
+               const float tScale;
+               const float tBias;
+               const float rScale;
+               const float rBias;
+       } s_params[] =
+       {
+       //              sScale  sBias   tScale  tBias   rScale  rBias
+               {        0.9f,  -0.1f,   0.7f,   0.3f,   0.8f,   0.9f   },
+               {        1.2f,  -0.1f,   1.1f,   0.3f,   1.0f,   0.9f   },
+               {        1.5f,   0.7f,   0.9f,  -0.3f,   1.1f,   0.1f   },
+               {        1.2f,   0.7f,  -2.3f,  -0.3f,   1.1f,   0.2f   },
+               {        1.1f,   0.8f,  -1.3f,  -0.3f,   2.9f,   0.9f   },
+               {        3.4f,   0.8f,   4.0f,   0.0f,  -3.3f,  -1.0f   },
+               {       -3.4f,  -0.1f,  -4.0f,   0.0f,  -5.1f,   1.0f   },
+               {       -4.0f,  -0.1f,   3.4f,   0.1f,   5.7f,   0.0f   },
+               {       -5.6f,   0.0f,   0.5f,   1.2f,   3.9f,   4.0f   },
+               {        5.0f,  -2.0f,   3.1f,   1.2f,   5.1f,   0.2f   },
+               {        2.5f,  -2.0f,   6.3f,   3.0f,   5.1f,   0.2f   },
+               {       -8.3f,   0.0f,   7.1f,   3.0f,   2.0f,   0.2f   },
+               {        3.8f,   0.0f,   9.7f,   1.0f,   7.0f,   0.7f   },
+               {       13.3f,   0.0f,   7.1f,   3.0f,   2.0f,   0.2f   },
+               {       16.0f,   8.0f,  12.7f,   1.0f,  17.1f,   0.7f   },
+               {       15.3f,   0.0f,  20.1f,   3.0f,  33.0f,   3.2f   }
+       };
+
+       const float sScale      = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sScale;
+       const float sBias       = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].sBias;
+       const float tScale      = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tScale;
+       const float tBias       = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].tBias;
+       const float rScale      = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rScale;
+       const float rBias       = s_params[cellNdx%DE_LENGTH_OF_ARRAY(s_params)].rBias;
+
+       dst.resize(3*4);
+
+       dst[0] = sBias;                 dst[ 1] = tBias;                        dst[ 2] = rBias;
+       dst[3] = sBias;                 dst[ 4] = tBias+tScale;         dst[ 5] = rBias+rScale*0.5f;
+       dst[6] = sBias+sScale;  dst[ 7] = tBias;                        dst[ 8] = rBias+rScale*0.5f;
+       dst[9] = sBias+sScale;  dst[10] = tBias+tScale;         dst[11] = rBias+rScale;
+}
+
+static void getAffineTexCoord3D (std::vector<float>& dst, int cellNdx)
+{
+       // Use basic coords as base.
+       getBasicTexCoord3D(dst, cellNdx);
+
+       // Rotate based on cell index.
+       const float             angleX          = 0.0f + 2.0f*DE_PI * ((float)cellNdx / 16.0f);
+       const float             angleY          = 1.0f + 2.0f*DE_PI * ((float)cellNdx / 32.0f);
+       const tcu::Mat3 rotMatrix       = tcu::rotationMatrixX(angleX) * tcu::rotationMatrixY(angleY);
+
+       const Vec3              p0                      = rotMatrix * Vec3(dst[0], dst[ 1], dst[ 2]);
+       const Vec3              p1                      = rotMatrix * Vec3(dst[3], dst[ 4], dst[ 5]);
+       const Vec3              p2                      = rotMatrix * Vec3(dst[6], dst[ 7], dst[ 8]);
+       const Vec3              p3                      = rotMatrix * Vec3(dst[9], dst[10], dst[11]);
+
+       dst[0] = p0.x();        dst[ 1] = p0.y();       dst[ 2] = p0.z();
+       dst[3] = p1.x();        dst[ 4] = p1.y();       dst[ 5] = p1.z();
+       dst[6] = p2.x();        dst[ 7] = p2.y();       dst[ 8] = p2.z();
+       dst[9] = p3.x();        dst[10] = p3.y();       dst[11] = p3.z();
+}
+
+tcu::TestStatus Texture3DMipmapTestInstance::iterate (void)
+{
+       const tcu::TextureFormat&               texFmt                  = m_texture->getTextureFormat();
+       const tcu::TextureFormatInfo    fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
+       const Sampler::FilterMode               magFilter               = Sampler::NEAREST;
+       const int                                               viewportWidth   = m_renderer.getRenderWidth();
+       const int                                               viewportHeight  = m_renderer.getRenderHeight();
+
+       const bool                                              isProjected             = m_testParameters.coordType == COORDTYPE_PROJECTED;
+       const bool                                              useLodBias              = m_testParameters.coordType == COORDTYPE_BASIC_BIAS;
+
+       // Viewport is divided into 4x4 grid.
+       const int                                               gridWidth               = 4;
+       const int                                               gridHeight              = 4;
+       const int                                               cellWidth               = viewportWidth / gridWidth;
+       const int                                               cellHeight              = viewportHeight / gridHeight;
+
+       ReferenceParams                                 refParams               (TEXTURETYPE_3D);
+
+       tcu::Surface                                    renderedFrame   (viewportWidth, viewportHeight);
+       vector<float>                                   texCoord;
+
+       // Sampling parameters.
+       refParams.sampler               = util::createSampler(m_testParameters.wrapS, m_testParameters.wrapT, m_testParameters.minFilter, magFilter);
+       refParams.samplerType   = getSamplerType(texFmt);
+
+       refParams.colorBias             = fmtInfo.lookupBias;
+       refParams.colorScale    = fmtInfo.lookupScale;
+       refParams.flags                 = (isProjected ? ReferenceParams::PROJECTED : 0) | (useLodBias ? ReferenceParams::USE_BIAS : 0);
+
+       // Bias values.
+       static const float s_bias[] = { 1.0f, -2.0f, 0.8f, -0.5f, 1.5f, 0.9f, 2.0f, 4.0f };
+
+       // Projection values.
+       static const Vec4 s_projections[] =
+       {
+               Vec4(1.2f, 1.0f, 0.7f, 1.0f),
+               Vec4(1.3f, 0.8f, 0.6f, 2.0f),
+               Vec4(0.8f, 1.0f, 1.7f, 0.6f),
+               Vec4(1.2f, 1.0f, 1.7f, 1.5f)
+       };
+
+       // Render cells.
+       for (int gridY = 0; gridY < gridHeight; gridY++)
+       {
+               for (int gridX = 0; gridX < gridWidth; gridX++)
+               {
+                       const int       curX            = cellWidth*gridX;
+                       const int       curY            = cellHeight*gridY;
+                       const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                       const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                       const int       cellNdx         = gridY*gridWidth + gridX;
+
+                       // Compute texcoord.
+                       switch (m_testParameters.coordType)
+                       {
+                               case COORDTYPE_BASIC_BIAS:      // Fall-through.
+                               case COORDTYPE_PROJECTED:
+                               case COORDTYPE_BASIC:           getBasicTexCoord3D      (texCoord, cellNdx);    break;
+                               case COORDTYPE_AFFINE:          getAffineTexCoord3D     (texCoord, cellNdx);    break;
+                               default:                                        DE_ASSERT(DE_FALSE);
+                       }
+
+                       // Set projection.
+                       if (isProjected)
+                               refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
+
+                       // Set LOD bias.
+                       if (useLodBias)
+                               refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
+
+                       m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
+                       m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
+               }
+       }
+
+       // Compare and log
+       {
+               const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
+               const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
+               const bool                              isTrilinear             = m_testParameters.minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_testParameters.minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
+               tcu::Surface                    referenceFrame  (viewportWidth, viewportHeight);
+               tcu::Surface                    errorMask               (viewportWidth, viewportHeight);
+               tcu::LookupPrecision    lookupPrec;
+               tcu::LodPrecision               lodPrec;
+               int                                             numFailedPixels = 0;
+
+               lookupPrec.coordBits            = tcu::IVec3(20, 20, 20);
+               lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
+               lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
+               lookupPrec.colorMask            = getCompareMask(pixelFormat);
+               lodPrec.derivateBits            = 10;
+               lodPrec.lodBits                         = isProjected ? 6 : 8;
+
+               for (int gridY = 0; gridY < gridHeight; gridY++)
+               {
+                       for (int gridX = 0; gridX < gridWidth; gridX++)
+                       {
+                               const int       curX            = cellWidth*gridX;
+                               const int       curY            = cellHeight*gridY;
+                               const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                               const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                               const int       cellNdx         = gridY*gridWidth + gridX;
+
+                               switch (m_testParameters.coordType)
+                               {
+                                       case COORDTYPE_BASIC_BIAS:      // Fall-through.
+                                       case COORDTYPE_PROJECTED:
+                                       case COORDTYPE_BASIC:           getBasicTexCoord3D      (texCoord, cellNdx);    break;
+                                       case COORDTYPE_AFFINE:          getAffineTexCoord3D     (texCoord, cellNdx);    break;
+                                       default:                                        DE_ASSERT(DE_FALSE);
+                               }
+
+                               if (isProjected)
+                                       refParams.w = s_projections[cellNdx % DE_LENGTH_OF_ARRAY(s_projections)];
+
+                               if (useLodBias)
+                                       refParams.bias = s_bias[cellNdx % DE_LENGTH_OF_ARRAY(s_bias)];
+
+                               // Render ideal result
+                               sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
+                                                         m_texture->getTexture(), &texCoord[0], refParams);
+
+                               // Compare this cell
+                               numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
+                                                                                                                       m_texture->getTexture(), &texCoord[0], refParams,
+                                                                                                                       lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
+                       }
+               }
+
+               if (numFailedPixels > 0)
+                       m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
+
+               m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
+                                                                                       << TestLog::Image("Rendered", "Rendered image", renderedFrame);
+
+               if (numFailedPixels > 0)
+               {
+                       m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
+                                                                                               << TestLog::Image("ErrorMask", "Error mask", errorMask);
+               }
+
+               m_context.getTestContext().getLog() << TestLog::EndImageSet;
+
+               {
+                       const bool isOk = numFailedPixels == 0;
+                       return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
+               }
+       }
+}
+
+// Texture2DLodControlTestInstance
+class Texture2DLodControlTestInstance : public TestInstance
+{
+public:
+       typedef Texture2DMipmapTestCaseParameters       ParameterType;
+
+                                                                               Texture2DLodControlTestInstance         (Context& context, const ParameterType& testParameters);
+                                                                               ~Texture2DLodControlTestInstance        (void);
+
+       virtual tcu::TestStatus                         iterate                                                         (void);
+
+protected:
+       virtual void                                            getReferenceParams                                      (ReferenceParams& params, int cellNdx) = 0;
+
+       const int                                                       m_texWidth;
+       const int                                                       m_texHeight;
+
+private:
+                                                                               Texture2DLodControlTestInstance         (const Texture2DLodControlTestInstance& other);
+       Texture2DLodControlTestInstance&        operator=                                                       (const Texture2DLodControlTestInstance& other);
+
+       const ParameterType                                     m_testParameters;
+       tcu::Sampler::FilterMode                        m_minFilter;
+       TestTexture2DSp                                         m_texture;
+       TextureRenderer                                         m_renderer;
+};
+
+Texture2DLodControlTestInstance::Texture2DLodControlTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
+       : TestInstance          (context)
+       , m_texWidth            (64) //64
+       , m_texHeight           (64)//64
+       , m_testParameters      (testParameters)
+       , m_minFilter           (testParameters.minFilter)
+       , m_texture                     (DE_NULL)
+       , m_renderer            (context, testParameters.sampleCount, m_texWidth*4, m_texHeight*4)
+{
+       const VkFormat  format          = VK_FORMAT_R8G8B8A8_UNORM;
+       const int               numLevels       = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
+
+       m_texture = TestTexture2DSp(new pipeline::TestTexture2D(vk::mapVkFormat(format), m_texWidth, m_texHeight));
+
+       // Fill texture with colored grid.
+       for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+       {
+               const deUint32  step    = 0xff / (numLevels-1);
+               const deUint32  inc             = deClamp32(step*levelNdx, 0x00, 0xff);
+               const deUint32  dec             = 0xff - inc;
+               const deUint32  rgb             = (inc << 16) | (dec << 8) | 0xff;
+               const deUint32  color   = 0xff000000 | rgb;
+
+               tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec());
+       }
+
+       m_renderer.add2DTexture(m_texture);
+}
+
+Texture2DLodControlTestInstance::~Texture2DLodControlTestInstance (void)
+{
+}
+
+tcu::TestStatus Texture2DLodControlTestInstance::iterate (void)
+{
+       const tcu::Sampler::WrapMode    wrapS                   = Sampler::REPEAT_GL;
+       const tcu::Sampler::WrapMode    wrapT                   = Sampler::REPEAT_GL;
+       const tcu::Sampler::FilterMode  magFilter               = Sampler::NEAREST;
+
+       const tcu::Texture2D&                   refTexture              = m_texture->getTexture();
+
+       const int                                               viewportWidth   = m_renderer.getRenderWidth();
+       const int                                               viewportHeight  = m_renderer.getRenderHeight();
+
+       tcu::Sampler                                    sampler                 = util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
+
+       ReferenceParams                                 refParams               (TEXTURETYPE_2D, sampler);
+       vector<float>                                   texCoord;
+       tcu::Surface                                    renderedFrame   (viewportWidth, viewportHeight);
+
+       // Viewport is divided into 4x4 grid.
+       const int                                               gridWidth               = 4;
+       const int                                               gridHeight              = 4;
+       const int                                               cellWidth               = viewportWidth / gridWidth;
+       const int                                               cellHeight              = viewportHeight / gridHeight;
+
+       refParams.maxLevel = deLog2Floor32(de::max(m_texWidth, m_texHeight));
+
+       // Render cells.
+       for (int gridY = 0; gridY < gridHeight; gridY++)
+       {
+               for (int gridX = 0; gridX < gridWidth; gridX++)
+               {
+                       const int       curX            = cellWidth*gridX;
+                       const int       curY            = cellHeight*gridY;
+                       const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                       const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                       const int       cellNdx         = gridY*gridWidth + gridX;
+
+                       // Compute texcoord.
+                       getBasicTexCoord2D(texCoord, cellNdx);
+                       // Render
+                       getReferenceParams(refParams,cellNdx);
+                       m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
+                       m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel);
+                       m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
+               }
+       }
+
+       // Compare and log.
+       {
+               const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(vk::mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
+               const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
+               const bool                              isTrilinear             = m_minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
+               tcu::Surface                    referenceFrame  (viewportWidth, viewportHeight);
+               tcu::Surface                    errorMask               (viewportWidth, viewportHeight);
+               tcu::LookupPrecision    lookupPrec;
+               tcu::LodPrecision               lodPrec;
+               int                                             numFailedPixels = 0;
+
+               lookupPrec.coordBits            = tcu::IVec3(20, 20, 0);
+               lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 0); // Doesn't really matter since pixels are unicolored.
+               lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
+               lookupPrec.colorMask            = getCompareMask(pixelFormat);
+               lodPrec.derivateBits            = 10;
+               lodPrec.lodBits                         = 8;
+
+               for (int gridY = 0; gridY < gridHeight; gridY++)
+               {
+                       for (int gridX = 0; gridX < gridWidth; gridX++)
+                       {
+                               const int       curX            = cellWidth*gridX;
+                               const int       curY            = cellHeight*gridY;
+                               const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                               const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                               const int       cellNdx         = gridY*gridWidth + gridX;
+
+                               getBasicTexCoord2D(texCoord, cellNdx);
+                               getReferenceParams(refParams, cellNdx);
+
+                               // Render ideal result
+                               sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
+                                                         refTexture, &texCoord[0], refParams);
+
+                               // Compare this cell
+                               numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
+                                                                                                                       m_texture->getTexture(), &texCoord[0], refParams,
+                                                                                                                       lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
+                       }
+               }
+
+               if (numFailedPixels > 0)
+                       m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
+
+               m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
+                                                                                       << TestLog::Image("Rendered", "Rendered image", renderedFrame);
+
+               if (numFailedPixels > 0)
+               {
+                       m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
+                                                                                               << TestLog::Image("ErrorMask", "Error mask", errorMask);
+               }
+
+               m_context.getTestContext().getLog() << TestLog::EndImageSet;
+
+               {
+                       const bool isOk = numFailedPixels == 0;
+                       return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
+               }
+       }
+}
+
+class Texture2DMinLodTestInstance : public Texture2DLodControlTestInstance
+{
+public:
+       Texture2DMinLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
+               : Texture2DLodControlTestInstance(context, testParameters)
+       {
+       }
+
+protected:
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.minLod = getMinLodForCell(cellNdx);
+       }
+};
+
+class Texture2DMaxLodTestInstance : public Texture2DLodControlTestInstance
+{
+public:
+       Texture2DMaxLodTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
+               : Texture2DLodControlTestInstance(context, testParameters)
+       {
+       }
+
+protected:
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.maxLod = getMaxLodForCell(cellNdx);
+       }
+};
+
+class Texture2DBaseLevelTestInstance : public Texture2DLodControlTestInstance
+{
+public:
+       Texture2DBaseLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
+               : Texture2DLodControlTestInstance(context, testParameters)
+               , m_testParam (testParameters)
+       {
+       }
+
+protected:
+       const Texture2DMipmapTestCaseParameters m_testParam;
+
+       int getBaseLevel (int cellNdx) const
+       {
+               const int       numLevels       = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
+               const int       baseLevel       = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0xac2f274a) % numLevels;
+
+               return baseLevel;
+       }
+
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.baseLevel = getBaseLevel(cellNdx);
+       }
+};
+
+class Texture2DMaxLevelTestInstance : public Texture2DLodControlTestInstance
+{
+public:
+       Texture2DMaxLevelTestInstance (Context& context, const Texture2DMipmapTestCaseParameters& testParameters)
+               : Texture2DLodControlTestInstance(context, testParameters)
+               , m_testParam (testParameters)
+       {
+       }
+
+protected:
+       const Texture2DMipmapTestCaseParameters m_testParam;
+
+       int getMaxLevel (int cellNdx) const
+       {
+               const int       numLevels       = deLog2Floor32(de::max(m_texWidth, m_texHeight))+1;
+               const int       maxLevel        = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x82cfa4e) % numLevels;
+
+               return maxLevel;
+       }
+
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.maxLevel = getMaxLevel(cellNdx);
+       }
+};
+
+// TextureCubeLodControlTestInstance
+class TextureCubeLodControlTestInstance : public TestInstance
+{
+public:
+       typedef TextureCubeMipmapTestCaseParameters     ParameterType;
+
+                                                                               TextureCubeLodControlTestInstance       (Context& context, const ParameterType& testParameters);
+                                                                               ~TextureCubeLodControlTestInstance      (void);
+
+       virtual tcu::TestStatus                         iterate                                                         (void);
+
+protected:
+       virtual void                                            getReferenceParams                                      (ReferenceParams& params, int cellNdx)  = DE_NULL;
+
+       const int                                                       m_texSize;
+
+private:
+                                                                               TextureCubeLodControlTestInstance       (const TextureCubeLodControlTestInstance& other);
+       TextureCubeLodControlTestInstance&      operator=                                                       (const TextureCubeLodControlTestInstance& other);
+
+       const ParameterType                                     m_testParameters;
+       tcu::Sampler::FilterMode                        m_minFilter;
+       TestTextureCubeSp                                       m_texture;
+       TextureRenderer                                         m_renderer;
+};
+
+TextureCubeLodControlTestInstance::TextureCubeLodControlTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
+       : TestInstance          (context)
+       , m_texSize                     (64)
+       , m_testParameters      (testParameters)
+       , m_minFilter           (testParameters.minFilter)
+       , m_texture                     (DE_NULL)
+       , m_renderer            (context, testParameters.sampleCount, m_texSize*2, m_texSize*2)
+{
+       const VkFormat  format          = VK_FORMAT_R8G8B8A8_UNORM;
+       const int               numLevels       = deLog2Floor32(m_texSize)+1;
+
+       m_texture = TestTextureCubeSp(new pipeline::TestTextureCube(vk::mapVkFormat(format), m_texSize));
+
+       // Fill texture with colored grid.
+       for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
+       {
+               for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+               {
+                       const deUint32  step    = 0xff / (numLevels-1);
+                       const deUint32  inc             = deClamp32(step*levelNdx, 0x00, 0xff);
+                       const deUint32  dec             = 0xff - inc;
+                       deUint32                rgb             = 0;
+
+                       switch (faceNdx)
+                       {
+                               case 0: rgb = (inc << 16) | (dec << 8) | 255; break;
+                               case 1: rgb = (255 << 16) | (inc << 8) | dec; break;
+                               case 2: rgb = (dec << 16) | (255 << 8) | inc; break;
+                               case 3: rgb = (dec << 16) | (inc << 8) | 255; break;
+                               case 4: rgb = (255 << 16) | (dec << 8) | inc; break;
+                               case 5: rgb = (inc << 16) | (255 << 8) | dec; break;
+                       }
+
+                       const deUint32  color   = 0xff000000 | rgb;
+
+                       tcu::clear(m_texture->getLevel(levelNdx, (tcu::CubeFace)faceNdx), tcu::RGBA(color).toVec());
+               }
+       }
+
+       m_renderer.addCubeTexture(m_texture);
+}
+
+TextureCubeLodControlTestInstance::~TextureCubeLodControlTestInstance (void)
+{
+}
+
+tcu::TestStatus TextureCubeLodControlTestInstance::iterate (void)
+{
+       const tcu::Sampler::WrapMode    wrapS                   = Sampler::CLAMP_TO_EDGE;
+       const tcu::Sampler::WrapMode    wrapT                   = Sampler::CLAMP_TO_EDGE;
+       const tcu::Sampler::FilterMode  magFilter               = Sampler::NEAREST;
+
+       const tcu::TextureCube&                 refTexture              = m_texture->getTexture();
+       const int                                               viewportWidth   = m_renderer.getRenderWidth();
+       const int                                               viewportHeight  = m_renderer.getRenderHeight();
+
+       tcu::Sampler                                    sampler                 = util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
+       ReferenceParams                                 refParams               (TEXTURETYPE_CUBE, sampler);
+       vector<float>                                   texCoord;
+       tcu::Surface                                    renderedFrame   (viewportWidth, viewportHeight);
+
+       refParams.maxLevel = deLog2Floor32(m_texSize);
+
+       // Compute grid.
+       vector<tcu::IVec4> gridLayout;
+       computeGridLayout(gridLayout, viewportWidth, viewportHeight);
+
+       for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
+       {
+               const int                       curX            = gridLayout[cellNdx].x();
+               const int                       curY            = gridLayout[cellNdx].y();
+               const int                       curW            = gridLayout[cellNdx].z();
+               const int                       curH            = gridLayout[cellNdx].w();
+               const tcu::CubeFace     cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
+
+               computeQuadTexCoordCube(texCoord, cubeFace);
+               getReferenceParams(refParams, cellNdx);
+
+               // Render with GL.
+               m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
+               m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel);
+               m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
+       }
+
+       // Render reference and compare
+       {
+               const tcu::IVec4                formatBitDepth          = getTextureFormatBitDepth(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
+               const tcu::PixelFormat  pixelFormat                     (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
+               tcu::Surface                    referenceFrame          (viewportWidth, viewportHeight);
+               tcu::Surface                    errorMask                       (viewportWidth, viewportHeight);
+               int                                             numFailedPixels         = 0;
+               tcu::LookupPrecision    lookupPrec;
+               tcu::LodPrecision               lodPrec;
+
+               // Params for rendering reference
+               refParams.sampler                                       = util::createSampler(wrapS, wrapT, m_testParameters.minFilter, magFilter);
+               refParams.sampler.seamlessCubeMap       = true;
+               refParams.lodMode                                       = LODMODE_EXACT;
+
+               // Comparison parameters
+               lookupPrec.colorMask                            = getCompareMask(pixelFormat);
+               lookupPrec.colorThreshold                       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat)-2, IVec4(0)));
+               lookupPrec.coordBits                            = tcu::IVec3(10);
+               lookupPrec.uvwBits                                      = tcu::IVec3(5,5,0);
+               lodPrec.derivateBits                            = 10;
+               lodPrec.lodBits                                         = 6;
+
+               for (int cellNdx = 0; cellNdx < (int)gridLayout.size(); cellNdx++)
+               {
+                       const int                               curX            = gridLayout[cellNdx].x();
+                       const int                               curY            = gridLayout[cellNdx].y();
+                       const int                               curW            = gridLayout[cellNdx].z();
+                       const int                               curH            = gridLayout[cellNdx].w();
+                       const tcu::CubeFace             cubeFace        = (tcu::CubeFace)(cellNdx % tcu::CUBEFACE_LAST);
+
+                       computeQuadTexCoordCube(texCoord, cubeFace);
+                       getReferenceParams(refParams, cellNdx);
+
+                       // Render ideal reference.
+                       {
+                               tcu::SurfaceAccess idealDst(referenceFrame, pixelFormat, curX, curY, curW, curH);
+                               sampleTexture(idealDst, refTexture, &texCoord[0], refParams);
+                       }
+
+                       // Compare this cell
+                       numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                               tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                               tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
+                                                                                                               m_texture->getTexture(), &texCoord[0], refParams,
+                                                                                                               lookupPrec, lodPrec,  m_context.getTestContext().getWatchDog());
+               }
+
+               if (numFailedPixels > 0)
+                        m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
+
+                m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
+                                                                                        << TestLog::Image("Rendered", "Rendered image", renderedFrame);
+
+               if (numFailedPixels > 0)
+               {
+                        m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
+                                                                                                << TestLog::Image("ErrorMask", "Error mask", errorMask);
+               }
+
+                m_context.getTestContext().getLog() << TestLog::EndImageSet;
+
+               {
+                       const bool isOk = numFailedPixels == 0;
+                       return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
+               }
+       }
+}
+
+class TextureCubeMinLodTestInstance : public TextureCubeLodControlTestInstance
+{
+public:
+       TextureCubeMinLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
+               : TextureCubeLodControlTestInstance(context, testParameters)
+       {
+       }
+
+protected:
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.minLod = getMinLodForCell(cellNdx);
+       }
+};
+
+class TextureCubeMaxLodTestInstance : public TextureCubeLodControlTestInstance
+{
+public:
+       TextureCubeMaxLodTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
+               : TextureCubeLodControlTestInstance(context, testParameters)
+       {
+       }
+
+protected:
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.maxLod = getMaxLodForCell(cellNdx);
+       }
+};
+
+class TextureCubeBaseLevelTestInstance : public TextureCubeLodControlTestInstance
+{
+public:
+       TextureCubeBaseLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
+               : TextureCubeLodControlTestInstance(context, testParameters)
+               , m_testParam (testParameters)
+       {
+       }
+
+protected:
+       const TextureCubeMipmapTestCaseParameters m_testParam;
+
+       int getBaseLevel (int cellNdx) const
+       {
+               const int       numLevels       = deLog2Floor32(m_texSize)+1;
+               const int       baseLevel       = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x23fae13) % numLevels;
+
+               return baseLevel;
+       }
+
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.baseLevel = getBaseLevel(cellNdx);
+       }
+};
+
+class TextureCubeMaxLevelTestInstance : public TextureCubeLodControlTestInstance
+{
+public:
+       TextureCubeMaxLevelTestInstance (Context& context, const TextureCubeMipmapTestCaseParameters& testParameters)
+               : TextureCubeLodControlTestInstance(context, testParameters)
+               , m_testParam (testParameters)
+       {
+       }
+
+protected:
+       const TextureCubeMipmapTestCaseParameters m_testParam;
+       int getMaxLevel (int cellNdx) const
+       {
+               const int       numLevels       = deLog2Floor32(m_texSize)+1;
+               const int       maxLevel        = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x974e21) % numLevels;
+
+               return maxLevel;
+       }
+
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.maxLevel = getMaxLevel(cellNdx);
+       }
+};
+
+// Texture3DLodControlTestInstance
+class Texture3DLodControlTestInstance : public TestInstance
+{
+public:
+       typedef Texture3DMipmapTestCaseParameters       ParameterType;
+
+                                                                               Texture3DLodControlTestInstance         (Context& context, const ParameterType& testParameters);
+                                                                               ~Texture3DLodControlTestInstance        (void);
+
+       virtual tcu::TestStatus                         iterate                                                         (void);
+
+protected:
+       virtual void                                            getReferenceParams                                      (ReferenceParams& params, int cellNdx)  = DE_NULL;
+
+       const int                                                       m_texWidth;
+       const int                                                       m_texHeight;
+       const int                                                       m_texDepth;
+
+private:
+                                                                               Texture3DLodControlTestInstance         (const Texture3DLodControlTestInstance& other);
+       Texture3DLodControlTestInstance&        operator=                                                       (const Texture3DLodControlTestInstance& other);
+
+       const ParameterType                                     m_testParameters;
+       tcu::Sampler::FilterMode                        m_minFilter;
+       TestTexture3DSp                                         m_texture;
+       TextureRenderer                                         m_renderer;
+};
+
+Texture3DLodControlTestInstance::Texture3DLodControlTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
+       : TestInstance          (context)
+       , m_texWidth            (32)
+       , m_texHeight           (32)
+       , m_texDepth            (32)
+       , m_testParameters      (testParameters)
+       , m_minFilter           (testParameters.minFilter)
+       , m_texture                     (DE_NULL)
+       , m_renderer            (context, testParameters.sampleCount, m_texWidth*4, m_texHeight*4)
+{
+       const VkFormat                  format          = VK_FORMAT_R8G8B8A8_UNORM;
+       tcu::TextureFormatInfo  fmtInfo         = tcu::getTextureFormatInfo(mapVkFormat(format));
+       const tcu::Vec4&                cScale          = fmtInfo.lookupScale;
+       const tcu::Vec4&                cBias           = fmtInfo.lookupBias;
+       const int                               numLevels       = deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth))+1;
+
+       m_texture = TestTexture3DSp(new pipeline::TestTexture3D(vk::mapVkFormat(format), m_texWidth, m_texHeight, m_texDepth));
+
+       // Fill texture with colored grid.
+       for (int levelNdx = 0; levelNdx < numLevels; levelNdx++)
+       {
+               const deUint32  step    = 0xff / (numLevels-1);
+               const deUint32  inc             = deClamp32(step*levelNdx, 0x00, 0xff);
+               const deUint32  dec             = 0xff - inc;
+               const deUint32  rgb             = (inc << 16) | (dec << 8) | 0xff;
+               const deUint32  color   = 0xff000000 | rgb;
+
+               tcu::clear(m_texture->getLevel(levelNdx, 0), tcu::RGBA(color).toVec()*cScale + cBias);
+       }
+
+       m_renderer.add3DTexture(m_texture);
+}
+
+Texture3DLodControlTestInstance::~Texture3DLodControlTestInstance (void)
+{
+}
+
+tcu::TestStatus Texture3DLodControlTestInstance::iterate (void)
+{
+       const tcu::Sampler::WrapMode    wrapS                   = Sampler::CLAMP_TO_EDGE;
+       const tcu::Sampler::WrapMode    wrapT                   = Sampler::CLAMP_TO_EDGE;
+       const tcu::Sampler::WrapMode    wrapR                   = Sampler::CLAMP_TO_EDGE;
+       const tcu::Sampler::FilterMode  magFilter               = Sampler::NEAREST;
+
+       const tcu::Texture3D&                   refTexture              = m_texture->getTexture();
+       const tcu::TextureFormat&               texFmt                  = refTexture.getFormat();
+       const tcu::TextureFormatInfo    fmtInfo                 = tcu::getTextureFormatInfo(texFmt);
+       const int                                               viewportWidth   = m_renderer.getRenderWidth();
+       const int                                               viewportHeight  = m_renderer.getRenderHeight();
+
+       tcu::Sampler                                    sampler                 = util::createSampler(wrapS, wrapT, m_minFilter, magFilter);
+       ReferenceParams                                 refParams               (TEXTURETYPE_3D, sampler);
+       vector<float>                                   texCoord;
+       tcu::Surface                                    renderedFrame   (viewportWidth, viewportHeight);
+
+       // Viewport is divided into 4x4 grid.
+       const int                                               gridWidth               = 4;
+       const int                                               gridHeight              = 4;
+       const int                                               cellWidth               = viewportWidth / gridWidth;
+       const int                                               cellHeight              = viewportHeight / gridHeight;
+
+       // Sampling parameters.
+       refParams.sampler               = util::createSampler(wrapS, wrapT, wrapR, m_testParameters.minFilter, magFilter);
+       refParams.samplerType   = getSamplerType(texFmt);
+       refParams.colorBias             = fmtInfo.lookupBias;
+       refParams.colorScale    = fmtInfo.lookupScale;
+       refParams.maxLevel              = deLog2Floor32(de::max(de::max(m_texWidth, m_texHeight), m_texDepth));
+
+       // Render cells.
+       for (int gridY = 0; gridY < gridHeight; gridY++)
+       {
+               for (int gridX = 0; gridX < gridWidth; gridX++)
+               {
+                       const int       curX            = cellWidth*gridX;
+                       const int       curY            = cellHeight*gridY;
+                       const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                       const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                       const int       cellNdx         = gridY*gridWidth + gridX;
+
+                       // Compute texcoord.
+                       getBasicTexCoord3D(texCoord, cellNdx);
+
+                       getReferenceParams(refParams,cellNdx);
+                       //Render
+                       m_renderer.setViewport((float)curX, (float)curY, (float)curW, (float)curH);
+                       m_renderer.getTextureBinding(0)->updateTextureViewMipLevels(refParams.baseLevel, refParams.maxLevel);
+                       m_renderer.renderQuad(renderedFrame, 0, &texCoord[0], refParams);
+               }
+       }
+
+       // Compare and log
+       {
+               const tcu::IVec4                formatBitDepth  = getTextureFormatBitDepth(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM));
+               const tcu::PixelFormat  pixelFormat             (formatBitDepth[0], formatBitDepth[1], formatBitDepth[2], formatBitDepth[3]);
+               const bool                              isTrilinear             = m_minFilter == Sampler::NEAREST_MIPMAP_LINEAR || m_minFilter == Sampler::LINEAR_MIPMAP_LINEAR;
+               tcu::Surface                    referenceFrame  (viewportWidth, viewportHeight);
+               tcu::Surface                    errorMask               (viewportWidth, viewportHeight);
+               tcu::LookupPrecision    lookupPrec;
+               tcu::LodPrecision               lodPrec;
+               int                                             numFailedPixels = 0;
+
+               lookupPrec.coordBits            = tcu::IVec3(20, 20, 20);
+               lookupPrec.uvwBits                      = tcu::IVec3(16, 16, 16); // Doesn't really matter since pixels are unicolored.
+               lookupPrec.colorThreshold       = tcu::computeFixedPointThreshold(max(getBitsVec(pixelFormat) - (isTrilinear ? 2 : 1), tcu::IVec4(0)));
+               lookupPrec.colorMask            = getCompareMask(pixelFormat);
+               lodPrec.derivateBits            = 10;
+               lodPrec.lodBits                         = 8;
+
+               for (int gridY = 0; gridY < gridHeight; gridY++)
+               {
+                       for (int gridX = 0; gridX < gridWidth; gridX++)
+                       {
+                               const int       curX            = cellWidth*gridX;
+                               const int       curY            = cellHeight*gridY;
+                               const int       curW            = gridX+1 == gridWidth ? (viewportWidth-curX) : cellWidth;
+                               const int       curH            = gridY+1 == gridHeight ? (viewportHeight-curY) : cellHeight;
+                               const int       cellNdx         = gridY*gridWidth + gridX;
+
+                               getBasicTexCoord3D(texCoord, cellNdx);
+                               getReferenceParams(refParams, cellNdx);
+
+                               // Render ideal result
+                               sampleTexture(tcu::SurfaceAccess(referenceFrame, pixelFormat, curX, curY, curW, curH),
+                                                         refTexture, &texCoord[0], refParams);
+
+                               // Compare this cell
+                               numFailedPixels += computeTextureLookupDiff(tcu::getSubregion(renderedFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(referenceFrame.getAccess(), curX, curY, curW, curH),
+                                                                                                                       tcu::getSubregion(errorMask.getAccess(), curX, curY, curW, curH),
+                                                                                                                       m_texture->getTexture(), &texCoord[0], refParams,
+                                                                                                                       lookupPrec, lodPrec, m_context.getTestContext().getWatchDog());
+                       }
+               }
+
+               if (numFailedPixels > 0)
+               {
+                       m_context.getTestContext().getLog() << TestLog::Message << "ERROR: Image verification failed, found " << numFailedPixels << " invalid pixels!" << TestLog::EndMessage;
+               }
+
+               m_context.getTestContext().getLog() << TestLog::ImageSet("Result", "Verification result")
+                                                                                       << TestLog::Image("Rendered", "Rendered image", renderedFrame);
+
+               if (numFailedPixels > 0)
+               {
+                       m_context.getTestContext().getLog() << TestLog::Image("Reference", "Ideal reference", referenceFrame)
+                                                                                               << TestLog::Image("ErrorMask", "Error mask", errorMask);
+               }
+
+               m_context.getTestContext().getLog() << TestLog::EndImageSet;
+
+               {
+                       const bool isOk = numFailedPixels == 0;
+                       return isOk ? tcu::TestStatus::pass("pass") : tcu::TestStatus::fail("fail");
+               }
+       }
+}
+
+class Texture3DMinLodTestInstance : public Texture3DLodControlTestInstance
+{
+public:
+       Texture3DMinLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
+               : Texture3DLodControlTestInstance(context, testParameters)
+       {
+       }
+
+protected:
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.minLod = getMinLodForCell(cellNdx);
+       }
+};
+
+class Texture3DMaxLodTestInstance : public Texture3DLodControlTestInstance
+{
+public:
+       Texture3DMaxLodTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
+               : Texture3DLodControlTestInstance(context, testParameters)
+       {
+       }
+
+protected:
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.maxLod = getMaxLodForCell(cellNdx);
+       }
+};
+
+class Texture3DBaseLevelTestInstance : public Texture3DLodControlTestInstance
+{
+public:
+       Texture3DBaseLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
+               : Texture3DLodControlTestInstance(context, testParameters)
+               ,m_testParam (testParameters)
+       {
+       }
+
+protected:
+       const Texture3DMipmapTestCaseParameters m_testParam;
+
+       int getBaseLevel (int cellNdx) const
+       {
+               const int       numLevels       = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
+               const int       baseLevel       = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x7347e9) % numLevels;
+
+               return baseLevel;
+       }
+
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.baseLevel = getBaseLevel(cellNdx);
+       }
+};
+
+class Texture3DMaxLevelTestInstance : public Texture3DLodControlTestInstance
+{
+public:
+       Texture3DMaxLevelTestInstance (Context& context, const Texture3DMipmapTestCaseParameters& testParameters)
+               : Texture3DLodControlTestInstance(context, testParameters)
+               ,m_testParam (testParameters)
+       {
+       }
+
+protected:
+       const Texture3DMipmapTestCaseParameters m_testParam;
+
+       int getMaxLevel (int cellNdx) const
+       {
+               const int       numLevels       = deLog2Floor32(de::max(m_texWidth, de::max(m_texHeight, m_texDepth)))+1;
+               const int       maxLevel        = (deInt32Hash(cellNdx) ^ deStringHash(m_testParam.minFilterName) ^ 0x9111e7) % numLevels;
+
+               return maxLevel;
+       }
+
+       void getReferenceParams (ReferenceParams& params, int cellNdx)
+       {
+               params.maxLevel = getMaxLevel(cellNdx);
+       }
+};
+
+} // anonymous
+
+void createTextureMipmappingTests (tcu::TestCaseGroup* textureTests)
+{
+       tcu::TestContext&                               testCtx                                 = textureTests->getTestContext();
+       de::MovePtr<tcu::TestCaseGroup> textureMipmappingTests  (new tcu::TestCaseGroup(testCtx, "mipmap", "Texture mipmapping tests."));
+
+       static const struct
+       {
+               const char*                             name;
+               const Sampler::WrapMode mode;
+       } wrapModes[] =
+       {
+               { "clamp",              Sampler::CLAMP_TO_EDGE          },
+               { "repeat",             Sampler::REPEAT_GL                      },
+               { "mirror",             Sampler::MIRRORED_REPEAT_GL     }
+       };
+
+       static const struct
+       {
+               const char*                                     name;
+               const Sampler::FilterMode       mode;
+       } minFilterModes[] =
+       {
+               { "nearest_nearest",    Sampler::NEAREST_MIPMAP_NEAREST },
+               { "linear_nearest",             Sampler::LINEAR_MIPMAP_NEAREST  },
+               { "nearest_linear",             Sampler::NEAREST_MIPMAP_LINEAR  },
+               { "linear_linear",              Sampler::LINEAR_MIPMAP_LINEAR   }
+       };
+
+       static const struct
+       {
+               const char*                                     name;
+               const Sampler::FilterMode       mode;
+       } magFilterModes[] =
+       {
+               { "nearest",    Sampler::NEAREST},
+               { "linear",             Sampler::LINEAR}
+       };
+
+
+       static const struct
+       {
+               const CoordType         type;
+               const char*                     name;
+               const char*                     desc;
+       } coordTypes[] =
+       {
+               { COORDTYPE_BASIC,              "basic",                "Mipmapping with translated and scaled coordinates" },
+               { COORDTYPE_AFFINE,             "affine",               "Mipmapping with affine coordinate transform"           },
+               { COORDTYPE_PROJECTED,  "projected",    "Mipmapping with perspective projection"                        }
+       };
+
+       static const struct
+       {
+               const char*             name;
+               const int               width;
+               const int               height;
+       } tex2DSizes[] =
+       {
+               { DE_NULL,              64, 64 }, // Default.
+               { "npot",               63, 57 },
+               { "non_square", 32, 64 }
+       };
+
+       static const struct
+       {
+               const char*             name;
+               const int               width;
+               const int               height;
+               const int               depth;
+       } tex3DSizes[] =
+       {
+               { DE_NULL,              32, 32, 32 }, // Default.
+               { "npot",               33, 29, 27 }
+       };
+
+       const int cubeMapSize = 64;
+
+       static const struct
+       {
+               const CoordType         type;
+               const char*                     name;
+               const char*                     desc;
+       } cubeCoordTypes[] =
+       {
+               { COORDTYPE_BASIC,              "basic",                "Mipmapping with translated and scaled coordinates" },
+               { COORDTYPE_PROJECTED,  "projected",    "Mipmapping with perspective projection"                        },
+               { COORDTYPE_BASIC_BIAS, "bias",                 "User-supplied bias value"                                                      }
+       };
+
+       // 2D cases.
+       {
+               de::MovePtr<tcu::TestCaseGroup> group2D                         (new tcu::TestCaseGroup(testCtx, "2d", "2D Mipmap Filtering"));
+
+               de::MovePtr<tcu::TestCaseGroup> biasGroup2D                     (new tcu::TestCaseGroup(testCtx, "bias", "User-supplied bias value"));
+               de::MovePtr<tcu::TestCaseGroup> minLodGroup2D           (new tcu::TestCaseGroup(testCtx, "min_lod", "Lod control: min lod"));
+               de::MovePtr<tcu::TestCaseGroup> maxLodGroup2D           (new tcu::TestCaseGroup(testCtx, "max_lod", "Lod control: max lod"));
+               de::MovePtr<tcu::TestCaseGroup> baseLevelGroup2D        (new tcu::TestCaseGroup(testCtx, "base_level", "Base level"));
+               de::MovePtr<tcu::TestCaseGroup> maxLevelGroup2D         (new tcu::TestCaseGroup(testCtx, "max_level", "Max level"));
+
+               for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
+               {
+                       de::MovePtr<tcu::TestCaseGroup> coordTypeGroup          (new tcu::TestCaseGroup(testCtx, coordTypes[coordType].name, coordTypes[coordType].desc));
+
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
+                               {
+                                       // Add non_square variants to basic cases only.
+                                       int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex2DSizes) : 1;
+
+                                       for (int size = 0; size < sizeEnd; size++)
+                                       {
+                                               Texture2DMipmapTestCaseParameters       testParameters;
+
+                                               testParameters.coordType        = coordTypes[coordType].type;
+                                               testParameters.minFilter        = minFilterModes[minFilter].mode;
+                                               testParameters.wrapS            = wrapModes[wrapMode].mode;
+                                               testParameters.wrapT            = wrapModes[wrapMode].mode;
+                                               testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM; //not sure (GL_RGBA)
+                                               testParameters.width            = tex2DSizes[size].width;
+                                               testParameters.height           = tex2DSizes[size].height;
+                                               testParameters.programs.push_back(PROGRAM_2D_FLOAT);
+
+                                               std::ostringstream name;
+                                               name << minFilterModes[minFilter].name
+                                                        << "_" << wrapModes[wrapMode].name;
+
+                                               if (tex2DSizes[size].name)
+                                                       name << "_" << tex2DSizes[size].name;
+
+                                               coordTypeGroup->addChild(new TextureTestCase<Texture2DMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
+                                       }
+                               }
+                       }
+
+                       group2D->addChild(coordTypeGroup.release());
+               }
+
+               // 2D bias variants.
+               {
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture2DMipmapTestCaseParameters       testParameters;
+
+                               testParameters.coordType        = COORDTYPE_BASIC_BIAS;
+                               testParameters.minFilter        = minFilterModes[minFilter].mode;
+                               testParameters.magFilter        = minFilterModes[minFilter].mode;
+                               testParameters.wrapS            = Sampler::REPEAT_GL;
+                               testParameters.wrapT            = Sampler::REPEAT_GL;
+                               testParameters.format           = VK_FORMAT_R8G8B8A8_UNORM; //not sure (GL_RGBA)
+                               testParameters.width            = tex2DSizes[0].width;
+                               testParameters.height           = tex2DSizes[0].height;
+                               testParameters.programs.push_back(PROGRAM_2D_FLOAT_BIAS);
+
+                               std::ostringstream name;
+                               name << minFilterModes[minFilter].name;
+
+                               biasGroup2D->addChild(new TextureTestCase<Texture2DMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
+                       }
+               }
+
+               // 2D LOD controls.
+               {
+                       // MIN_LOD
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture2DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter        = minFilterModes[minFilter].mode;
+                               testParameters.programs.push_back(PROGRAM_2D_FLOAT);
+
+                               minLodGroup2D->addChild(new TextureTestCase<Texture2DMinLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+
+                       // MAX_LOD
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture2DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter = minFilterModes[minFilter].mode;
+                               testParameters.programs.push_back(PROGRAM_2D_FLOAT);
+
+                               maxLodGroup2D->addChild(new TextureTestCase<Texture2DMaxLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+               }
+
+               {
+                       // BASE_LEVEL
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture2DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter = minFilterModes[minFilter].mode;
+                               testParameters.minFilterName = minFilterModes[minFilter].name;
+                               testParameters.programs.push_back(PROGRAM_2D_FLOAT);
+
+                               baseLevelGroup2D->addChild(new TextureTestCase<Texture2DBaseLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+
+                       // MAX_LEVEL
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture2DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter = minFilterModes[minFilter].mode;
+                               testParameters.minFilterName = minFilterModes[minFilter].name;
+                               testParameters.programs.push_back(PROGRAM_2D_FLOAT);
+
+                               maxLevelGroup2D->addChild(new TextureTestCase<Texture2DMaxLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+               }
+
+               group2D->addChild(biasGroup2D.release());
+               group2D->addChild(minLodGroup2D.release());
+               group2D->addChild(maxLodGroup2D.release());
+               group2D->addChild(baseLevelGroup2D.release());
+               group2D->addChild(maxLevelGroup2D.release());
+
+               textureMipmappingTests->addChild(group2D.release());
+       }
+
+       // Cubemap cases.
+       {
+               de::MovePtr<tcu::TestCaseGroup> groupCube                       (new tcu::TestCaseGroup(testCtx, "cubemap", "Cube Mipmap Filtering"));
+
+               de::MovePtr<tcu::TestCaseGroup> minLodGroupCube         (new tcu::TestCaseGroup(testCtx, "min_lod", "Lod control: min lod"));
+               de::MovePtr<tcu::TestCaseGroup> maxLodGroupCube         (new tcu::TestCaseGroup(testCtx, "max_lod", "Lod control: max lod"));
+               de::MovePtr<tcu::TestCaseGroup> baseLevelGroupCube      (new tcu::TestCaseGroup(testCtx, "base_level", "Base level"));
+               de::MovePtr<tcu::TestCaseGroup> maxLevelGroupCube       (new tcu::TestCaseGroup(testCtx, "max_level", "Max level"));
+
+               for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(cubeCoordTypes); coordType++)
+               {
+                       de::MovePtr<tcu::TestCaseGroup> coordTypeGroup  (new tcu::TestCaseGroup(testCtx, cubeCoordTypes[coordType].name, cubeCoordTypes[coordType].desc));
+
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               for (int magFilter = 0; magFilter < DE_LENGTH_OF_ARRAY(magFilterModes); magFilter++)
+                               {
+                                       for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
+                                       {
+                                               TextureCubeMipmapTestCaseParameters     testParameters;
+
+                                               testParameters.coordType                = cubeCoordTypes[coordType].type;
+                                               testParameters.minFilter                = minFilterModes[minFilter].mode;
+                                               testParameters.magFilter                = magFilterModes[magFilter].mode;
+                                               testParameters.minFilterName    = minFilterModes[minFilter].name;
+                                               testParameters.wrapS                    = wrapModes[wrapMode].mode;
+                                               testParameters.wrapT                    = wrapModes[wrapMode].mode;
+                                               testParameters.format                   = VK_FORMAT_R8G8B8A8_UNORM;
+                                               testParameters.size                             = cubeMapSize;
+                                               testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
+                                               testParameters.programs.push_back(PROGRAM_CUBE_FLOAT_BIAS);
+
+                                               std::ostringstream name;
+                                               name << minFilterModes[minFilter].name
+                                                        << "_" << magFilterModes[magFilter].name
+                                                        << "_" << wrapModes[wrapMode].name;
+
+                                               coordTypeGroup->addChild(new TextureTestCase<TextureCubeMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
+                                       }
+                               }
+                       }
+
+                       groupCube->addChild(coordTypeGroup.release());
+               }
+
+               // Cubemap LOD controls.
+               {
+                       // MIN_LOD
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               TextureCubeMipmapTestCaseParameters     testParameters;
+                               testParameters.minFilter        = minFilterModes[minFilter].mode;
+                               testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
+
+                               minLodGroupCube->addChild(new TextureTestCase<TextureCubeMinLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+
+                       // MAX_LOD
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               TextureCubeMipmapTestCaseParameters     testParameters;
+                               testParameters.minFilter        = minFilterModes[minFilter].mode;
+                               testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
+
+                               maxLodGroupCube->addChild(new TextureTestCase<TextureCubeMaxLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+               }
+
+               {
+                       // BASE_LEVEL
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               TextureCubeMipmapTestCaseParameters     testParameters;
+                               testParameters.minFilter = minFilterModes[minFilter].mode;
+                               testParameters.minFilterName = minFilterModes[minFilter].name;
+                               testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
+
+                               baseLevelGroupCube->addChild(new TextureTestCase<TextureCubeBaseLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+
+                       // MAX_LEVEL
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               TextureCubeMipmapTestCaseParameters     testParameters;
+                               testParameters.minFilter = minFilterModes[minFilter].mode;
+                               testParameters.minFilterName = minFilterModes[minFilter].name;
+                               testParameters.programs.push_back(PROGRAM_CUBE_FLOAT);
+
+                               maxLevelGroupCube->addChild(new TextureTestCase<TextureCubeMaxLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+               }
+
+               groupCube->addChild(minLodGroupCube.release());
+               groupCube->addChild(maxLodGroupCube.release());
+               groupCube->addChild(baseLevelGroupCube.release());
+               groupCube->addChild(maxLevelGroupCube.release());
+
+               textureMipmappingTests->addChild(groupCube.release());
+       }
+
+       // 3D cases.
+       {
+               de::MovePtr<tcu::TestCaseGroup> group3D                         (new tcu::TestCaseGroup(testCtx, "3d", "3D Mipmap Filtering"));
+
+               de::MovePtr<tcu::TestCaseGroup> biasGroup3D                     (new tcu::TestCaseGroup(testCtx, "bias", "User-supplied bias value"));
+               de::MovePtr<tcu::TestCaseGroup> minLodGroup3D           (new tcu::TestCaseGroup(testCtx, "min_lod", "Lod control: min lod"));
+               de::MovePtr<tcu::TestCaseGroup> maxLodGroup3D           (new tcu::TestCaseGroup(testCtx, "max_lod", "Lod control: max lod"));
+               de::MovePtr<tcu::TestCaseGroup> baseLevelGroup3D        (new tcu::TestCaseGroup(testCtx, "base_level", "Base level"));
+               de::MovePtr<tcu::TestCaseGroup> maxLevelGroup3D         (new tcu::TestCaseGroup(testCtx, "max_level", "Max level"));
+
+               for (int coordType = 0; coordType < DE_LENGTH_OF_ARRAY(coordTypes); coordType++)
+               {
+                       de::MovePtr<tcu::TestCaseGroup> coordTypeGroup  (new tcu::TestCaseGroup(testCtx, coordTypes[coordType].name, coordTypes[coordType].desc));
+
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               for (int wrapMode = 0; wrapMode < DE_LENGTH_OF_ARRAY(wrapModes); wrapMode++)
+                               {
+                                       // Add other size variants to basic cases only.
+                                       int sizeEnd = coordTypes[coordType].type == COORDTYPE_BASIC ? DE_LENGTH_OF_ARRAY(tex3DSizes) : 1;
+
+                                       Texture3DMipmapTestCaseParameters       testParameters;
+
+                                       testParameters.coordType                = coordTypes[coordType].type;
+                                       testParameters.minFilter                = minFilterModes[minFilter].mode;
+                                       testParameters.minFilterName    = minFilterModes[minFilter].name;
+                                       testParameters.wrapR                    = wrapModes[wrapMode].mode;
+                                       testParameters.wrapS                    = wrapModes[wrapMode].mode;
+                                       testParameters.wrapT                    = wrapModes[wrapMode].mode;
+                                       testParameters.format                   = VK_FORMAT_R8G8B8A8_UNORM;
+                                       testParameters.programs.push_back(PROGRAM_3D_FLOAT);
+
+                                       for (int size = 0; size < sizeEnd; size++)
+                                       {
+                                               testParameters.width                    = tex3DSizes[size].width;
+                                               testParameters.height                   = tex3DSizes[size].height;
+                                               testParameters.depth                    = tex3DSizes[size].depth;
+
+                                               std::ostringstream name;
+                                               name << minFilterModes[minFilter].name
+                                                        << "_" << wrapModes[wrapMode].name;
+
+                                               if (tex3DSizes[size].name)
+                                                       name << "_" << tex3DSizes[size].name;
+
+                                               coordTypeGroup->addChild(new TextureTestCase<Texture3DMipmapTestInstance>(testCtx, name.str().c_str(), "", testParameters));
+                                       }
+                               }
+                       }
+
+                       group3D->addChild(coordTypeGroup.release());
+               }
+
+               // 3D bias variants.
+               {
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture3DMipmapTestCaseParameters       testParameters;
+                               testParameters.coordType                        = COORDTYPE_BASIC_BIAS;
+                               testParameters.minFilter                        = minFilterModes[minFilter].mode;
+                               testParameters.wrapR                            = Sampler::REPEAT_GL;
+                               testParameters.wrapS                            = Sampler::REPEAT_GL;
+                               testParameters.wrapT                            = Sampler::REPEAT_GL;
+                               testParameters.format                           = VK_FORMAT_R8G8B8A8_UNORM;
+                               testParameters.width                            = tex3DSizes[0].width;
+                               testParameters.height                           = tex3DSizes[0].height;
+                               testParameters.depth                            = tex3DSizes[0].depth;
+
+                               testParameters.programs.push_back(PROGRAM_3D_FLOAT);
+                               testParameters.programs.push_back(PROGRAM_3D_FLOAT_BIAS);
+
+                               biasGroup3D->addChild(new TextureTestCase<Texture3DMipmapTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+               }
+
+               // 3D LOD controls.
+               {
+                       // MIN_LOD
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture3DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter                        = minFilterModes[minFilter].mode;
+                               testParameters.programs.push_back(PROGRAM_3D_FLOAT);
+
+                               minLodGroup3D->addChild(new TextureTestCase<Texture3DMinLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+
+                       // MAX_LOD
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture3DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter                        = minFilterModes[minFilter].mode;
+                               testParameters.programs.push_back(PROGRAM_3D_FLOAT);
+
+                               maxLodGroup3D->addChild(new TextureTestCase<Texture3DMaxLodTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+               }
+
+               {
+                       // BASE_LEVEL
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture3DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter                        = minFilterModes[minFilter].mode;
+                               testParameters.minFilterName            = minFilterModes[minFilter].name;
+                               testParameters.programs.push_back(PROGRAM_3D_FLOAT);
+
+                               baseLevelGroup3D->addChild(new TextureTestCase<Texture3DBaseLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+
+                       // MAX_LEVEL
+                       for (int minFilter = 0; minFilter < DE_LENGTH_OF_ARRAY(minFilterModes); minFilter++)
+                       {
+                               Texture3DMipmapTestCaseParameters       testParameters;
+                               testParameters.minFilter                        = minFilterModes[minFilter].mode;
+                               testParameters.minFilterName            = minFilterModes[minFilter].name;
+                               testParameters.programs.push_back(PROGRAM_3D_FLOAT);
+
+                               maxLevelGroup3D->addChild(new TextureTestCase<Texture3DMaxLevelTestInstance>(testCtx, minFilterModes[minFilter].name, "", testParameters));
+                       }
+               }
+
+               group3D->addChild(biasGroup3D.release());
+               group3D->addChild(minLodGroup3D.release());
+               group3D->addChild(maxLodGroup3D.release());
+               group3D->addChild(baseLevelGroup3D.release());
+               group3D->addChild(maxLevelGroup3D.release());
+
+               textureMipmappingTests->addChild(group3D.release());
+       }
+
+       textureTests->addChild(textureMipmappingTests.release());
+}
+
+} // texture
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.hpp b/external/vulkancts/modules/vulkan/texture/vktTextureMipmapTests.hpp
new file mode 100644 (file)
index 0000000..fbd11b4
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _VKTTEXTUREMIPMAPTESTS_HPP
+#define _VKTTEXTUREMIPMAPTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2016 The Khronos Group Inc.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Mipmapping tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace texture
+{
+
+void createTextureMipmappingTests (tcu::TestCaseGroup* textureTests);
+
+} // texture
+} // vkt
+
+#endif // _VKTTEXTUREMIPMAPTESTS_HPP
index 8d7ca80..a3bc44e 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "vktTestGroupUtil.hpp"
 #include "vktTextureFilteringTests.hpp"
+#include "vktTextureMipmapTests.hpp"
 #include "vktTextureTests.hpp"
 
 namespace vkt
@@ -37,6 +38,7 @@ namespace
 void createTextureTests (tcu::TestCaseGroup* imageTests)
 {
        createTextureFilteringTests(imageTests);
+       createTextureMipmappingTests(imageTests);
 }
 
 } // anonymous
index 064efed..035bfb6 100644 (file)
@@ -332,3 +332,6 @@ dEQP-VK.spirv_assembly.instruction.compute.opfunord.*
 
 # New tests from AOSP
 dEQP-VK.texture_filtering.*
+
+# Exclude tests which are not on the Android CTS mustpass list
+dEQP-VK.texture.mipmap.2d.projected.*
index 40638c2..f5bf7fd 100644 (file)
@@ -112397,3 +112397,227 @@ dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_cla
 dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_clamp_to_edge_mirror_clamp_to_edge_clamp_to_edge
 dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_clamp_to_edge_mirror_clamp_to_edge_clamp_to_border
 dEQP-VK.texture.filtering.3d.combinations.linear_mipmap_linear_linear_mirror_clamp_to_edge_mirror_clamp_to_edge_mirror_clamp_to_edge
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_nearest_mirror_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_clamp
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_repeat
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_mirror
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_nearest_mirror_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_clamp
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_repeat
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_mirror
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.nearest_linear_mirror_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_clamp
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_clamp_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_clamp_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_repeat
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_repeat_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_repeat_non_square
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_mirror
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_mirror_npot
+dEQP-VK.texture.mipmap.2d.basic.linear_linear_mirror_non_square
+dEQP-VK.texture.mipmap.2d.affine.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.2d.affine.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.2d.affine.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.2d.affine.linear_nearest_clamp
+dEQP-VK.texture.mipmap.2d.affine.linear_nearest_repeat
+dEQP-VK.texture.mipmap.2d.affine.linear_nearest_mirror
+dEQP-VK.texture.mipmap.2d.affine.nearest_linear_clamp
+dEQP-VK.texture.mipmap.2d.affine.nearest_linear_repeat
+dEQP-VK.texture.mipmap.2d.affine.nearest_linear_mirror
+dEQP-VK.texture.mipmap.2d.affine.linear_linear_clamp
+dEQP-VK.texture.mipmap.2d.affine.linear_linear_repeat
+dEQP-VK.texture.mipmap.2d.affine.linear_linear_mirror
+dEQP-VK.texture.mipmap.2d.bias.nearest_nearest
+dEQP-VK.texture.mipmap.2d.bias.linear_nearest
+dEQP-VK.texture.mipmap.2d.bias.nearest_linear
+dEQP-VK.texture.mipmap.2d.bias.linear_linear
+dEQP-VK.texture.mipmap.2d.min_lod.nearest_nearest
+dEQP-VK.texture.mipmap.2d.min_lod.linear_nearest
+dEQP-VK.texture.mipmap.2d.min_lod.nearest_linear
+dEQP-VK.texture.mipmap.2d.min_lod.linear_linear
+dEQP-VK.texture.mipmap.2d.max_lod.nearest_nearest
+dEQP-VK.texture.mipmap.2d.max_lod.linear_nearest
+dEQP-VK.texture.mipmap.2d.max_lod.nearest_linear
+dEQP-VK.texture.mipmap.2d.max_lod.linear_linear
+dEQP-VK.texture.mipmap.2d.base_level.nearest_nearest
+dEQP-VK.texture.mipmap.2d.base_level.linear_nearest
+dEQP-VK.texture.mipmap.2d.base_level.nearest_linear
+dEQP-VK.texture.mipmap.2d.base_level.linear_linear
+dEQP-VK.texture.mipmap.2d.max_level.nearest_nearest
+dEQP-VK.texture.mipmap.2d.max_level.linear_nearest
+dEQP-VK.texture.mipmap.2d.max_level.nearest_linear
+dEQP-VK.texture.mipmap.2d.max_level.linear_linear
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.nearest_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.basic.linear_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.nearest_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.projected.linear_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_nearest_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.nearest_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_nearest_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_nearest_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_nearest_mirror
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_linear_clamp
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_linear_repeat
+dEQP-VK.texture.mipmap.cubemap.bias.linear_linear_linear_mirror
+dEQP-VK.texture.mipmap.cubemap.min_lod.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.min_lod.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.min_lod.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.min_lod.linear_linear
+dEQP-VK.texture.mipmap.cubemap.max_lod.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.max_lod.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.max_lod.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.max_lod.linear_linear
+dEQP-VK.texture.mipmap.cubemap.base_level.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.base_level.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.base_level.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.base_level.linear_linear
+dEQP-VK.texture.mipmap.cubemap.max_level.nearest_nearest
+dEQP-VK.texture.mipmap.cubemap.max_level.linear_nearest
+dEQP-VK.texture.mipmap.cubemap.max_level.nearest_linear
+dEQP-VK.texture.mipmap.cubemap.max_level.linear_linear
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.3d.basic.nearest_nearest_mirror_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_clamp
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_repeat
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_mirror
+dEQP-VK.texture.mipmap.3d.basic.linear_nearest_mirror_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_clamp
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_repeat
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_mirror
+dEQP-VK.texture.mipmap.3d.basic.nearest_linear_mirror_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_clamp
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_clamp_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_repeat
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_repeat_npot
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_mirror
+dEQP-VK.texture.mipmap.3d.basic.linear_linear_mirror_npot
+dEQP-VK.texture.mipmap.3d.affine.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.3d.affine.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.3d.affine.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.3d.affine.linear_nearest_clamp
+dEQP-VK.texture.mipmap.3d.affine.linear_nearest_repeat
+dEQP-VK.texture.mipmap.3d.affine.linear_nearest_mirror
+dEQP-VK.texture.mipmap.3d.affine.nearest_linear_clamp
+dEQP-VK.texture.mipmap.3d.affine.nearest_linear_repeat
+dEQP-VK.texture.mipmap.3d.affine.nearest_linear_mirror
+dEQP-VK.texture.mipmap.3d.affine.linear_linear_clamp
+dEQP-VK.texture.mipmap.3d.affine.linear_linear_repeat
+dEQP-VK.texture.mipmap.3d.affine.linear_linear_mirror
+dEQP-VK.texture.mipmap.3d.projected.nearest_nearest_clamp
+dEQP-VK.texture.mipmap.3d.projected.nearest_nearest_repeat
+dEQP-VK.texture.mipmap.3d.projected.nearest_nearest_mirror
+dEQP-VK.texture.mipmap.3d.projected.linear_nearest_clamp
+dEQP-VK.texture.mipmap.3d.projected.linear_nearest_repeat
+dEQP-VK.texture.mipmap.3d.projected.linear_nearest_mirror
+dEQP-VK.texture.mipmap.3d.projected.nearest_linear_clamp
+dEQP-VK.texture.mipmap.3d.projected.nearest_linear_repeat
+dEQP-VK.texture.mipmap.3d.projected.nearest_linear_mirror
+dEQP-VK.texture.mipmap.3d.projected.linear_linear_clamp
+dEQP-VK.texture.mipmap.3d.projected.linear_linear_repeat
+dEQP-VK.texture.mipmap.3d.projected.linear_linear_mirror
+dEQP-VK.texture.mipmap.3d.bias.nearest_nearest
+dEQP-VK.texture.mipmap.3d.bias.linear_nearest
+dEQP-VK.texture.mipmap.3d.bias.nearest_linear
+dEQP-VK.texture.mipmap.3d.bias.linear_linear
+dEQP-VK.texture.mipmap.3d.min_lod.nearest_nearest
+dEQP-VK.texture.mipmap.3d.min_lod.linear_nearest
+dEQP-VK.texture.mipmap.3d.min_lod.nearest_linear
+dEQP-VK.texture.mipmap.3d.min_lod.linear_linear
+dEQP-VK.texture.mipmap.3d.max_lod.nearest_nearest
+dEQP-VK.texture.mipmap.3d.max_lod.linear_nearest
+dEQP-VK.texture.mipmap.3d.max_lod.nearest_linear
+dEQP-VK.texture.mipmap.3d.max_lod.linear_linear
+dEQP-VK.texture.mipmap.3d.base_level.nearest_nearest
+dEQP-VK.texture.mipmap.3d.base_level.linear_nearest
+dEQP-VK.texture.mipmap.3d.base_level.nearest_linear
+dEQP-VK.texture.mipmap.3d.base_level.linear_linear
+dEQP-VK.texture.mipmap.3d.max_level.nearest_nearest
+dEQP-VK.texture.mipmap.3d.max_level.linear_nearest
+dEQP-VK.texture.mipmap.3d.max_level.nearest_linear
+dEQP-VK.texture.mipmap.3d.max_level.linear_linear