Added spirv-tools to the vulkan test suite.
authorAndrew Woloszyn <awoloszyn@google.com>
Fri, 4 Sep 2015 19:50:45 +0000 (15:50 -0400)
committerAndrew Woloszyn <awoloszyn@google.com>
Wed, 9 Sep 2015 19:44:35 +0000 (15:44 -0400)
This allows hand-written assembly tests.

It follows the same philosophy as glslang, and allows spirv to be
assembled prior to running the tests or at test time.

Change-Id: I1110fcd4f5713b50274502e73703bd1ba2fd372f

17 files changed:
CMakeLists.txt
external/spirv-tools/CMakeLists.txt [new file with mode: 0644]
external/vulkancts/README.md
external/vulkancts/framework/vulkan/CMakeLists.txt
external/vulkancts/framework/vulkan/vkPrograms.cpp
external/vulkancts/framework/vulkan/vkPrograms.hpp
external/vulkancts/framework/vulkan/vkSpirVAsm.cpp [new file with mode: 0644]
external/vulkancts/framework/vulkan/vkSpirVAsm.hpp [new file with mode: 0644]
external/vulkancts/framework/vulkan/vkSpirVProgram.cpp [new file with mode: 0644]
external/vulkancts/framework/vulkan/vkSpirVProgram.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/api/vktApiSmokeTests.cpp
external/vulkancts/modules/vulkan/vktBuildPrograms.cpp
external/vulkancts/modules/vulkan/vktTestCase.cpp
external/vulkancts/modules/vulkan/vktTestCase.hpp
external/vulkancts/modules/vulkan/vktTestCaseUtil.hpp
external/vulkancts/modules/vulkan/vktTestPackage.cpp
framework/platform/CMakeLists.txt

index d80389b..fdd9d17 100644 (file)
@@ -78,6 +78,9 @@ endif ()
 # glslang
 add_subdirectory(external/glslang)
 
+# spirv-tools
+add_subdirectory(external/spirv-tools)
+
 include_directories(${PNG_INCLUDE_PATH})
 
 message(STATUS "DEQP_TARGET_NAME        = ${DEQP_TARGET_NAME}")
diff --git a/external/spirv-tools/CMakeLists.txt b/external/spirv-tools/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e6df4d4
--- /dev/null
@@ -0,0 +1,28 @@
+#cmake file for spirv-tools
+
+if (NOT DE_DEFS)
+       message(FATAL_ERROR "Include Defs.cmake")
+endif ()
+
+# Assume build inside Android source tree
+set(DEFAULT_SPIRV_TOOLS_SRC_PATH "../spirv-tools")
+
+set(SPIRV_TOOLS_SRC_PATH ${DEFAULT_SPIRV_TOOLS_SRC_PATH} CACHE STRING "Path to spirv-tools source tree")
+if (IS_ABSOLUTE ${SPIRV_TOOLS_SRC_PATH})
+       set(SPIRV_TOOLS_ABS_PATH ${SPIRV_TOOLS_SRC_PATH})
+else ()
+       set(SPIRV_TOOLS_ABS_PATH "${CMAKE_SOURCE_DIR}/${SPIRV_TOOLS_SRC_PATH}")
+endif ()
+
+if (EXISTS ${SPIRV_TOOLS_ABS_PATH}/source/opcode.cpp)
+       message(STATUS "spirv-tools found; building with DEQP_HAVE_SPIRV_TOOLS")
+       set(CMAKE_C_FLAGS ${DE_3RD_PARTY_C_FLAGS})
+       set(CMAKE_CXX_FLAGS ${DE_3RD_PARTY_CXX_FLAGS})
+
+       set(DEQP_HAVE_SPIRV_TOOLS               ON                                      PARENT_SCOPE)
+       set(SPIRV_SKIP_EXECUTABLES              ON)
+       add_subdirectory(${SPIRV_TOOLS_ABS_PATH} spirv-tools)
+else()
+       message(STATUS "spirv-tools not found; SPIR-V assembly not available")
+       set(DEQP_HAVE_SPIRV_TOOLS               OFF                                     PARENT_SCOPE)
+endif()
index 09889c5..18f0bc8 100644 (file)
@@ -37,11 +37,18 @@ from the official repository to directory next to 'deqp':
 $ cd .. # assuming you were in 'deqp' source directory
 $ git clone https://github.com/KhronosGroup/glslang.git glslang
 
+spirv-tools is optional, but enables SPIRV assembly. Check out spirv-tools
+from the google branch of the gitlab repository next to 'deqp':
+
+$ cd .. # assuming you were in 'deqp' source directory
+$ git clone -b google https://gitlab.khronos.org/spirv/spirv-tools.git
+
 I.e the final directory structure should look like this:
 
 src/
     deqp/
     glslang/
+    spirv-tools/
 
 After downloading all dependencies, please follow instructions at
 http://source.android.com/devices/graphics/build-tests.html
index b4e27ea..5ab0112 100644 (file)
@@ -25,6 +25,10 @@ set(VKUTIL_SRCS
        vkDeviceUtil.hpp
        vkGlslToSpirV.cpp
        vkGlslToSpirV.hpp
+       vkSpirVAsm.hpp
+       vkSpirVAsm.cpp
+       vkSpirVProgram.hpp
+       vkSpirVProgram.cpp
        vkBinaryRegistry.cpp
        vkBinaryRegistry.hpp
        vkNullDriver.cpp
@@ -53,5 +57,13 @@ if (DEQP_HAVE_GLSLANG)
        set(VKUTIL_LIBS ${VKUTIL_LIBS} ${GLSLANG_LIBRARY})
 endif ()
 
+if(DEQP_HAVE_SPIRV_TOOLS)
+       include_directories(${spirv-tools_SOURCE_DIR}/include)
+       include_directories(${spirv-tools_SOURCE_DIR}/external/include)
+
+       add_definitions(-DDEQP_HAVE_SPIRV_TOOLS=1)
+       set(VKUTIL_LIBS ${VKUTIL_LIBS} SPIRV-TOOLS)
+endif()
+
 add_library(vkutil STATIC ${VKUTIL_SRCS})
 target_link_libraries(vkutil ${VKUTIL_LIBS})
index baac221..a73d7f8 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "vkPrograms.hpp"
 #include "vkGlslToSpirV.hpp"
+#include "vkSpirVAsm.hpp"
 #include "vkRefUtil.hpp"
 
 #include "tcuTestLog.hpp"
@@ -70,6 +71,13 @@ ProgramBinary* buildProgram (const glu::ProgramSources& program, ProgramFormat b
                TCU_THROW(NotSupportedError, "Unsupported program format");
 }
 
+ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo)
+{
+       vector<deUint8> binary;
+       assembleSpirV(&program, &binary, buildInfo);
+       return new ProgramBinary(PROGRAM_FORMAT_SPIRV, binary.size(), &binary[0]);
+}
+
 Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags)
 {
        if (binary.getFormat() == PROGRAM_FORMAT_SPIRV)
index 3e111a1..dfc30d9 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "vkDefs.hpp"
 #include "vkRef.hpp"
+#include "vkSpirVProgram.hpp"
 #include "gluShaderProgram.hpp"
 #include "deUniquePtr.hpp"
 #include "deSTLUtil.hpp"
@@ -168,11 +169,20 @@ const Program& ProgramCollection<Program>::get (const std::string& name) const
        return *m_programs.find(name)->second;
 }
 
-typedef ProgramCollection<glu::ProgramSources> SourceCollection;
+typedef vk::ProgramCollection<glu::ProgramSources>     GlslSourceCollection;
+typedef vk::ProgramCollection<vk::SpirVAsmSource>      SpirVAsmCollection;
+
+struct SourceCollections
+{
+       GlslSourceCollection    glslSources;
+       SpirVAsmCollection              spirvAsmSources;
+};
+
 typedef ProgramCollection<ProgramBinary>               BinaryCollection;
 
 // \todo [2015-03-13 pyry] Likely need BinaryBuilder abstraction for this
 ProgramBinary*                 buildProgram            (const glu::ProgramSources& program, ProgramFormat binaryFormat, glu::ShaderProgramInfo* buildInfo);
+ProgramBinary*                 assembleProgram         (const vk::SpirVAsmSource& program, SpirVProgramInfo* buildInfo);
 Move<VkShaderModule>   createShaderModule      (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags);
 
 } // vk
diff --git a/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp b/external/vulkancts/framework/vulkan/vkSpirVAsm.cpp
new file mode 100644 (file)
index 0000000..9ff7944
--- /dev/null
@@ -0,0 +1,122 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V assembly to binary.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkSpirVAsm.hpp"
+#include "vkSpirVProgram.hpp"
+#include "deArrayUtil.hpp"
+#include "deMemory.h"
+#include "deClock.h"
+#include "qpDebugOut.h"
+
+#if defined(DEQP_HAVE_SPIRV_TOOLS)
+#      include "deSingleton.h"
+
+#      include "libspirv/libspirv.h"
+#endif
+
+namespace vk
+{
+
+using std::string;
+using std::vector;
+
+#if defined(DEQP_HAVE_SPIRV_TOOLS)
+
+namespace
+{
+static volatile deSingletonState       s_spirvInitState        = DE_SINGLETON_STATE_NOT_INITIALIZED;
+static                 spv_opcode_table        s_spirvOpcodeTable;
+static                 spv_operand_table       s_spirvOperandTable;
+static                 spv_ext_inst_table      s_spirvExtInstTable;
+
+void initSpirVTools (void*)
+{
+       spvCheck(spvOpcodeTableGet(&s_spirvOpcodeTable) != SPV_SUCCESS,
+                        TCU_THROW(InternalError, "Cannot get opcode table for assembly"));
+
+       spvCheck(spvOperandTableGet(&s_spirvOperandTable) != SPV_SUCCESS,
+                        TCU_THROW(InternalError, "Cannot get operand table for assembly"));
+
+       spvCheck(spvExtInstTableGet(&s_spirvExtInstTable) != SPV_SUCCESS,
+                        TCU_THROW(InternalError, "Cannot get external instruction table for assembly"));
+}
+
+void prepareSpirvTools (void)
+{
+       deInitSingleton(&s_spirvInitState, initSpirVTools, DE_NULL);
+}
+
+} // anonymous
+
+void assembleSpirV (const SpirVAsmSource* program, std::vector<deUint8>* dst, SpirVProgramInfo* buildInfo)
+{
+       prepareSpirvTools();
+
+       const std::string&      spvSource                       = program->program.str();
+       spv_binary                      binary                          = DE_NULL;
+       spv_diagnostic          diagnostic                      = DE_NULL;
+       const deUint64          compileStartTime        = deGetMicroseconds();
+       const spv_result_t      compileOk                       = spvTextToBinary(spvSource.c_str(), spvSource.size(), s_spirvOpcodeTable, s_spirvOperandTable, s_spirvExtInstTable, &binary, &diagnostic);
+
+       {
+               buildInfo->source                       = program;
+               buildInfo->infoLog                      = diagnostic? diagnostic->error : ""; // \todo [2015-07-13 pyry] Include debug log?
+               buildInfo->compileTimeUs        = deGetMicroseconds() - compileStartTime;
+               buildInfo->compileOk            = (compileOk == SPV_SUCCESS);
+       }
+
+       if (compileOk != SPV_SUCCESS)
+               TCU_FAIL("Failed to compile shader");
+
+       dst->resize((int)binary->wordCount * sizeof(deUint32));
+#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
+       deMemcpy(&(*dst)[0], &binary->code[0], dst->size());
+#else
+#      error "Big-endian not supported"
+#endif
+       spvBinaryDestroy(binary);
+       spvDiagnosticDestroy(diagnostic);
+       return;
+}
+
+#else // defined(DEQP_HAVE_SPIRV_TOOLS)
+
+void assembleSpirV (const SpirvProgram* program, std::vector<deUint8>* dst, SpirvProgramInfo* buildInfo)
+{
+       TCU_THROW(NotSupportedError, "SPIR-V assembly not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
+}
+
+#endif
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkSpirVAsm.hpp b/external/vulkancts/framework/vulkan/vkSpirVAsm.hpp
new file mode 100644 (file)
index 0000000..2897ecd
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _VKSPIRVASM_HPP
+#define _VKSPIRVASM_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V assembly to binary.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "vkPrograms.hpp"
+
+namespace vk
+{
+
+//! Assemble SPIR-V program. Will fail with NotSupportedError if compiler is not available.
+void assembleSpirV (const SpirVAsmSource* program, std::vector<deUint8>* dst, SpirVProgramInfo* buildInfo);
+
+} // vk
+
+#endif // _VKSPIRVASM_HPP
diff --git a/external/vulkancts/framework/vulkan/vkSpirVProgram.cpp b/external/vulkancts/framework/vulkan/vkSpirVProgram.cpp
new file mode 100644 (file)
index 0000000..cd73668
--- /dev/null
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Spirv program and binary info.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkSpirVProgram.hpp"
+
+#include "tcuTestLog.hpp"
+
+namespace vk
+{
+
+tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVProgramInfo& shaderInfo)
+{
+       log << tcu::TestLog::ShaderProgram(shaderInfo.compileOk , shaderInfo.infoLog) << tcu::TestLog::EndShaderProgram;
+
+       // Write statistics
+       log << tcu::TestLog::Float(     "SpirVAssemblyTime",
+                                                               "SpirV assembly time",
+                                                               "ms", QP_KEY_TAG_TIME, (float)shaderInfo.compileTimeUs / 1000.0f);
+       return log;
+}
+
+tcu::TestLog& operator<< (tcu::TestLog& log, const SpirVAsmSource& source)
+{
+       log << tcu::TestLog::KernelSource(source.program.str());
+
+       return log;
+}
+
+} // vk
diff --git a/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp b/external/vulkancts/framework/vulkan/vkSpirVProgram.hpp
new file mode 100644 (file)
index 0000000..b09e5fd
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef _VKSPIPVROGRAM_HPP
+#define _VKSPIPVROGRAM_HPP
+/*-------------------------------------------------------------------------
+ * Vulkan CTS Framework
+ * --------------------
+ *
+ * Copyright (c) 2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be
+ * included in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by
+ * Khronos, at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief SPIR-V program and binary info.
+ *//*--------------------------------------------------------------------*/
+
+#include <sstream>
+
+#include "vkDefs.hpp"
+#include "tcuTestLog.hpp"
+
+namespace vk
+{
+
+struct SpirVAsmSource
+{
+       SpirVAsmSource& operator<<(const char* val)
+       {
+               program << val;
+               return *this;
+       }
+       std::ostringstream program;
+};
+
+struct SpirVProgramInfo
+{
+       SpirVProgramInfo()
+               : source                (DE_NULL)
+               , compileTimeUs (0)
+               , compileOk             (false)
+       {
+       }
+
+       const SpirVAsmSource*   source;
+       std::string                             infoLog;
+       deUint64                                compileTimeUs;
+       bool                                    compileOk;
+};
+
+tcu::TestLog&  operator<<                      (tcu::TestLog& log, const SpirVProgramInfo& shaderInfo);
+tcu::TestLog&  operator<<                      (tcu::TestLog& log, const SpirVAsmSource& program);
+
+}
+
+#endif // _VKSPIVPROGRAM_HPP
index 8fd1710..555828b 100644 (file)
@@ -100,9 +100,9 @@ tcu::TestStatus createSamplerTest (Context& context)
        return tcu::TestStatus::pass("Creating sampler succeeded");
 }
 
-void createShaderProgs (SourceCollection& dst)
+void createShaderProgs (SourceCollections& dst)
 {
-       dst.add("test") << glu::VertexSource(
+       dst.glslSources.add("test") << glu::VertexSource(
                "#version 300 es\n"
                "in highp vec4 a_position;\n"
                "void main (void) { gl_Position = a_position; }\n");
@@ -117,13 +117,81 @@ tcu::TestStatus createShaderModuleTest (Context& context)
        return tcu::TestStatus::pass("Creating shader module succeeded");
 }
 
-void createTriangleProgs (SourceCollection& dst)
+void createTriangleAsmProgs (SourceCollections& dst)
 {
-       dst.add("vert") << glu::VertexSource(
+       dst.spirvAsmSources.add("vert") <<
+               "                OpSource ESSL 300\n"
+               "                OpCapability Shader\n"
+               "%1 =    OpExtInstImport \"GLSL.std.450\"\n"
+               "                OpMemoryModel Logical GLSL450\n"
+               "                OpEntryPoint Vertex %4 \"main\"\n"
+               "                OpName %4 \"main\"\n"
+               "                OpName %10 \"gl_Position\"\n"
+               "                OpName %12 \"a_position\"\n"
+               "                OpName %16 \"gl_VertexID\"\n"
+               "                OpName %17 \"gl_InstanceID\"\n"
+               "                OpDecorate %10 BuiltIn Position\n"
+               "                OpDecorate %12 Location 0\n"
+               "                OpDecorate %16 BuiltIn VertexId\n"
+               "                OpDecorate %16 NoStaticUse\n"
+               "                OpDecorate %17 BuiltIn InstanceId\n"
+               "                OpDecorate %17 NoStaticUse\n"
+               "%2 =    OpTypeVoid\n"
+               "%3 =    OpTypeFunction %2\n"
+               "%7 =    OpTypeFloat 32\n"
+               "%8 =    OpTypeVector %7 4\n"
+               "%9 =    OpTypePointer Output %8\n"
+               "%10 =   OpVariable %9 Output\n"
+               "%11 =   OpTypePointer Input %8\n"
+               "%12 =   OpVariable %11 Input\n"
+               "%14 =   OpTypeInt 32 1\n"
+               "%15 =   OpTypePointer Input %14\n"
+               "%16 =   OpVariable %15 Input\n"
+               "%17 =   OpVariable %15 Input\n"
+               "%4 =    OpFunction %2 None %3\n"
+               "%5 =    OpLabel\n"
+               "%13 =   OpLoad %8 %12\n"
+               "                OpStore %10 %13\n"
+               "                OpBranch %6\n"
+               "%6 =    OpLabel\n"
+               "                OpReturn\n"
+               "                OpFunctionEnd\n";
+       dst.spirvAsmSources.add("frag") <<
+               "               OpSource ESSL 300\n"
+               "               OpCapability Shader\n"
+               "%1 =   OpExtInstImport \"GLSL.std.450\"\n"
+               "               OpMemoryModel Logical GLSL450\n"
+               "               OpEntryPoint Fragment %4 \"main\"\n"
+               "               OpExecutionMode %4 OriginLowerLeft\n"
+               "               OpName %4 \"main\"\n"
+               "               OpName %10 \"o_color\"\n"
+               "               OpDecorate %10 RelaxedPrecision\n"
+               "               OpDecorate %10 Location 0\n"
+               "%2 =   OpTypeVoid\n"
+               "%3 =   OpTypeFunction %2\n"
+               "%7 =   OpTypeFloat 32\n"
+               "%8 =   OpTypeVector %7 4\n"
+               "%9 =   OpTypePointer Output %8\n"
+               "%10 =  OpVariable %9 Output\n"
+               "%11 =  OpConstant %7 1065353216\n"
+               "%12 =  OpConstant %7 0\n"
+               "%13 =  OpConstantComposite %8 %11 %12 %11 %11\n"
+               "%4 =   OpFunction %2 None %3\n"
+               "%5 =   OpLabel\n"
+               "               OpStore %10 %13\n"
+               "               OpBranch %6\n"
+               "%6 =   OpLabel\n"
+               "               OpReturn\n"
+               "               OpFunctionEnd\n";
+}
+
+void createTriangleProgs (SourceCollections& dst)
+{
+       dst.glslSources.add("vert") << glu::VertexSource(
                "#version 300 es\n"
                "layout(location = 0) in highp vec4 a_position;\n"
                "void main (void) { gl_Position = a_position; }\n");
-       dst.add("frag") << glu::FragmentSource(
+       dst.glslSources.add("frag") << glu::FragmentSource(
                "#version 300 es\n"
                "layout(location = 0) out lowp vec4 o_color;\n"
                "void main (void) { o_color = vec4(1.0, 0.0, 1.0, 1.0); }\n");
@@ -721,6 +789,7 @@ tcu::TestCaseGroup* createSmokeTests (tcu::TestContext& testCtx)
        addFunctionCase                         (smokeTests.get(), "create_sampler",    "",     createSamplerTest);
        addFunctionCaseWithPrograms     (smokeTests.get(), "create_shader",             "", createShaderProgs,          createShaderModuleTest);
        addFunctionCaseWithPrograms     (smokeTests.get(), "triangle",                  "", createTriangleProgs,        renderTriangleTest);
+       addFunctionCaseWithPrograms     (smokeTests.get(), "asm_triangle",              "", createTriangleAsmProgs,     renderTriangleTest);
 
        return smokeTests.release();
 }
index b8e9d75..94319d5 100644 (file)
@@ -82,6 +82,82 @@ struct BuildStats
        }
 };
 
+namespace // anonymous
+{
+
+vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, glu::ShaderProgramInfo* buildInfo)
+{
+       return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, buildInfo);
+}
+
+vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo)
+{
+       return vk::assembleProgram(source, buildInfo);
+}
+
+void writeVerboseLogs (const glu::ShaderProgramInfo& buildInfo)
+{
+       for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
+       {
+               const glu::ShaderInfo&  shaderInfo      = buildInfo.shaders[shaderNdx];
+               const char* const               shaderName      = getShaderTypeName(shaderInfo.type);
+
+               tcu::print("%s source:\n---\n%s\n---\n", shaderName, shaderInfo.source.c_str());
+               tcu::print("%s compile log:\n---\n%s\n---\n", shaderName, shaderInfo.infoLog.c_str());
+       }
+}
+
+void writeVerboseLogs (const vk::SpirVProgramInfo& buildInfo)
+{
+       tcu::print("source:\n---\n%s\n---\n", buildInfo.source->program.str().c_str());
+       tcu::print("compile log:\n---\n%s\n---\n", buildInfo.infoLog.c_str());
+}
+
+template <typename InfoType, typename IteratorType>
+void buildProgram (const std::string&                  casePath,
+                                  bool                                                 printLogs,
+                                  IteratorType                                 iter,
+                                  BuildMode                                    mode,
+                                  BuildStats*                                  stats,
+                                  vk::BinaryRegistryReader*    reader,
+                                  vk::BinaryRegistryWriter*    writer)
+{
+       InfoType                                                        buildInfo;
+       try
+       {
+               const vk::ProgramIdentifier                     progId          (casePath, iter.getName());
+               const UniquePtr<vk::ProgramBinary>      binary          (compileProgram(iter.getProgram(), &buildInfo));
+
+               if (mode == BUILDMODE_BUILD)
+                       writer->storeProgram(progId, *binary);
+               else
+               {
+                       DE_ASSERT(mode == BUILDMODE_VERIFY);
+
+                       const UniquePtr<vk::ProgramBinary>      storedBinary    (reader->loadProgram(progId));
+
+                       if (binary->getSize() != storedBinary->getSize())
+                               throw tcu::Exception("Binary size doesn't match");
+
+                       if (deMemCmp(binary->getBinary(), storedBinary->getBinary(), binary->getSize()))
+                               throw tcu::Exception("Binary contents don't match");
+               }
+
+               tcu::print("  OK: %s\n", iter.getName().c_str());
+               stats->numSucceeded += 1;
+       }
+       catch (const std::exception& e)
+       {
+               tcu::print("  ERROR: %s: %s\n", iter.getName().c_str(), e.what());
+               if (printLogs)
+               {
+                       writeVerboseLogs(buildInfo);
+               }
+               stats->numFailed += 1;
+       }
+}
+
+} // anonymous
 BuildStats buildPrograms (tcu::TestContext& testCtx, const std::string& dstPath, BuildMode mode, bool verbose)
 {
        const UniquePtr<tcu::TestPackageRoot>   root            (createRoot(testCtx));
@@ -100,57 +176,20 @@ BuildStats buildPrograms (tcu::TestContext& testCtx, const std::string& dstPath,
                {
                        const TestCase* const           testCase        = dynamic_cast<TestCase*>(iterator.getNode());
                        const string                            casePath        = iterator.getNodePath();
-                       vk::SourceCollection            progs;
+                       vk::SourceCollections           progs;
 
                        tcu::print("%s\n", casePath.c_str());
 
                        testCase->initPrograms(progs);
 
-                       for (vk::SourceCollection::Iterator progIter = progs.begin(); progIter != progs.end(); ++progIter)
+                       for (vk::GlslSourceCollection::Iterator progIter = progs.glslSources.begin(); progIter != progs.glslSources.end(); ++progIter)
+                       {
+                               buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
+                       }
+
+                       for (vk::SpirVAsmCollection::Iterator progIter = progs.spirvAsmSources.begin(); progIter != progs.spirvAsmSources.end(); ++progIter)
                        {
-                               glu::ShaderProgramInfo  buildInfo;
-
-                               try
-                               {
-                                       const vk::ProgramIdentifier                     progId          (casePath, progIter.getName());
-                                       const UniquePtr<vk::ProgramBinary>      binary          (vk::buildProgram(progIter.getProgram(), vk::PROGRAM_FORMAT_SPIRV, &buildInfo));
-
-                                       if (mode == BUILDMODE_BUILD)
-                                               writer->storeProgram(progId, *binary);
-                                       else
-                                       {
-                                               DE_ASSERT(mode == BUILDMODE_VERIFY);
-
-                                               const UniquePtr<vk::ProgramBinary>      storedBinary    (reader->loadProgram(progId));
-
-                                               if (binary->getSize() != storedBinary->getSize())
-                                                       throw tcu::Exception("Binary size doesn't match");
-
-                                               if (deMemCmp(binary->getBinary(), storedBinary->getBinary(), binary->getSize()))
-                                                       throw tcu::Exception("Binary contents don't match");
-                                       }
-
-                                       tcu::print("  OK: %s\n", progIter.getName().c_str());
-                                       stats.numSucceeded += 1;
-                               }
-                               catch (const std::exception& e)
-                               {
-                                       tcu::print("  ERROR: %s: %s\n", progIter.getName().c_str(), e.what());
-
-                                       if (printLogs)
-                                       {
-                                               for (size_t shaderNdx = 0; shaderNdx < buildInfo.shaders.size(); shaderNdx++)
-                                               {
-                                                       const glu::ShaderInfo&  shaderInfo      = buildInfo.shaders[shaderNdx];
-                                                       const char* const               shaderName      = getShaderTypeName(shaderInfo.type);
-
-                                                       tcu::print("%s source:\n---\n%s\n---\n", shaderName, shaderInfo.source.c_str());
-                                                       tcu::print("%s compile log:\n---\n%s\n---\n", shaderName, shaderInfo.infoLog.c_str());
-                                               }
-                                       }
-
-                                       stats.numFailed += 1;
-                               }
+                               buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, printLogs, progIter, mode, &stats, reader.get(), writer.get());
                        }
                }
 
index e001e68..3f92ecc 100644 (file)
@@ -184,7 +184,7 @@ vk::Allocator&                                      Context::getDefaultAllocator                    (void) const { return *m_alloc
 
 // TestCase
 
-void TestCase::initPrograms (vk::ProgramCollection<glu::ProgramSources>&) const
+void TestCase::initPrograms (SourceCollections&) const
 {
 }
 
index c7d61b6..fbd9105 100644 (file)
@@ -50,6 +50,7 @@ class PlatformInterface;
 class ProgramBinary;
 template<typename Program> class ProgramCollection;
 class Allocator;
+struct SourceCollections;
 }
 
 namespace vkt
@@ -93,6 +94,7 @@ private:
        Context&                                                                        operator=                                               (const Context&); // Not allowed
 };
 
+
 class TestInstance;
 
 class TestCase : public tcu::TestCase
@@ -102,7 +104,7 @@ public:
                                                        TestCase                (tcu::TestContext& testCtx, tcu::TestNodeType type, const std::string& name, const std::string& description);
        virtual                                 ~TestCase               (void) {}
 
-       virtual void                    initPrograms    (vk::ProgramCollection<glu::ProgramSources>& programCollection) const;
+       virtual void                    initPrograms    (vk::SourceCollections& programCollection) const;
        virtual TestInstance*   createInstance  (Context& context) const = 0;
 
        IterateResult                   iterate                 (void) { DE_ASSERT(false); return STOP; } // Deprecated in this module
index 3fe936d..1fa09d3 100644 (file)
@@ -43,7 +43,7 @@ namespace vkt
 template<typename Arg0>
 struct NoPrograms1
 {
-       void    init    (vk::ProgramCollection<glu::ProgramSources>&, Arg0) const {}
+       void    init    (vk::SourceCollections&, Arg0) const {}
 };
 
 template<typename Instance, typename Arg0, typename Programs = NoPrograms1<Arg0> >
@@ -62,7 +62,7 @@ public:
                                                , m_arg0        (arg0)
                                        {}
 
-       void                    initPrograms            (vk::ProgramCollection<glu::ProgramSources>& dst) const { m_progs.init(dst, m_arg0); }
+       void                    initPrograms            (vk::SourceCollections& dst) const { m_progs.init(dst, m_arg0); }
        TestInstance*   createInstance          (Context& context) const { return new Instance(context, m_arg0); }
 
 private:
@@ -114,13 +114,13 @@ private:
 class FunctionPrograms0
 {
 public:
-       typedef void    (*Function)             (vk::ProgramCollection<glu::ProgramSources>& dst);
+       typedef void    (*Function)             (vk::SourceCollections& dst);
 
                                        FunctionPrograms0       (Function func)
                                                : m_func(func)
                                        {}
 
-       void                    init                    (vk::ProgramCollection<glu::ProgramSources>& dst, FunctionInstance0::Function) const { m_func(dst); }
+       void                    init                    (vk::SourceCollections& dst, FunctionInstance0::Function) const { m_func(dst); }
 
 private:
        const Function  m_func;
@@ -130,13 +130,13 @@ template<typename Arg0>
 class FunctionPrograms1
 {
 public:
-       typedef void    (*Function)             (vk::ProgramCollection<glu::ProgramSources>& dst, Arg0 arg0);
+       typedef void    (*Function)             (vk::SourceCollections& dst, Arg0 arg0);
 
                                        FunctionPrograms1       (Function func)
                                                : m_func(func)
                                        {}
 
-       void                    init                    (vk::ProgramCollection<glu::ProgramSources>& dst, const typename FunctionInstance1<Arg0>::Args& args) const { m_func(dst, args.arg0); }
+       void                    init                    (vk::SourceCollections& dst, const typename FunctionInstance1<Arg0>::Args& args) const { m_func(dst, args.arg0); }
 
 private:
        const Function  m_func;
index 4cd4435..4cdfc81 100644 (file)
@@ -42,6 +42,7 @@
 #include "vkPrograms.hpp"
 #include "vkBinaryRegistry.hpp"
 #include "vkGlslToSpirV.hpp"
+#include "vkSpirVAsm.hpp"
 
 #include "deUniquePtr.hpp"
 
 #include <vector>
 #include <sstream>
 
+namespace // compilation
+{
+
+vk::ProgramBinary* compileProgram (const glu::ProgramSources& source, glu::ShaderProgramInfo* buildInfo)
+{
+       return vk::buildProgram(source, vk::PROGRAM_FORMAT_SPIRV, buildInfo);
+}
+
+vk::ProgramBinary* compileProgram (const vk::SpirVAsmSource& source, vk::SpirVProgramInfo* buildInfo)
+{
+       return vk::assembleProgram(source, buildInfo);
+}
+
+template <typename InfoType, typename IteratorType>
+vk::ProgramBinary* buildProgram (const std::string& casePath, IteratorType iter, vkt::Context* context, vk::BinaryCollection* progCollection)
+{
+       tcu::TestLog&                                   log                     = context->getTestContext().getLog();
+       const vk::ProgramIdentifier             progId          (casePath, iter.getName());
+       const tcu::ScopedLogSection             progSection     (log, iter.getName(), "Program: " + iter.getName());
+       de::MovePtr<vk::ProgramBinary>  binProg;
+       InfoType                                                buildInfo;
+
+       try
+       {
+               binProg = de::MovePtr<vk::ProgramBinary>(compileProgram(iter.getProgram(), &buildInfo));
+               log << buildInfo;
+       }
+       catch (const tcu::NotSupportedError& err)
+       {
+               // Try to load from cache
+               const vk::BinaryRegistryReader  registry        (context->getTestContext().getArchive(), "vulkan/prebuilt");
+
+               log << err << tcu::TestLog::Message << "Building from source not supported, loading stored binary instead" << tcu::TestLog::EndMessage;
+
+               binProg = de::MovePtr<vk::ProgramBinary>(registry.loadProgram(progId));
+
+               log << iter.getProgram();
+       }
+       catch (const tcu::Exception&)
+       {
+               // Build failed for other reason
+               log << buildInfo;
+               throw;
+       }
+
+       TCU_CHECK_INTERNAL(binProg);
+
+       vk::ProgramBinary* returnBinary = binProg.get();
+
+       progCollection->add(progId.programName, binProg);
+
+       return returnBinary;
+}
+
+} // anonymous(compilation)
+
 namespace vkt
 {
 
@@ -101,7 +158,7 @@ void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePat
 {
        const TestCase*                 vktCase         = dynamic_cast<TestCase*>(testCase);
        tcu::TestLog&                   log                     = m_context.getTestContext().getLog();
-       vk::SourceCollection    sourceProgs;
+       vk::SourceCollections   sourceProgs;
 
        DE_UNREF(casePath); // \todo [2015-03-13 pyry] Use this to identify ProgramCollection storage path
 
@@ -111,39 +168,9 @@ void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePat
        m_progCollection.clear();
        vktCase->initPrograms(sourceProgs);
 
-       for (vk::SourceCollection::Iterator progIter = sourceProgs.begin(); progIter != sourceProgs.end(); ++progIter)
+       for (vk::GlslSourceCollection::Iterator progIter = sourceProgs.glslSources.begin(); progIter != sourceProgs.glslSources.end(); ++progIter)
        {
-               const vk::ProgramIdentifier             progId          (casePath, progIter.getName());
-               const tcu::ScopedLogSection             progSection     (log, progIter.getName(), "Program: " + progIter.getName());
-               de::MovePtr<vk::ProgramBinary>  binProg;
-               glu::ShaderProgramInfo                  buildInfo;
-
-               // \todo [2015-07-01 pyry] Command line parameter to control cache vs. build order?
-
-               try
-               {
-                       binProg = de::MovePtr<vk::ProgramBinary>(vk::buildProgram(progIter.getProgram(), vk::PROGRAM_FORMAT_SPIRV, &buildInfo));
-                       log << buildInfo;
-               }
-               catch (const tcu::NotSupportedError& err)
-               {
-                       // Try to load from cache
-                       const vk::BinaryRegistryReader  registry        (m_context.getTestContext().getArchive(), "vulkan/prebuilt");
-
-                       log << err << TestLog::Message << "Building from source not supported, loading stored binary instead" << TestLog::EndMessage;
-
-                       binProg = de::MovePtr<vk::ProgramBinary>(registry.loadProgram(progId));
-
-                       log << progIter.getProgram();
-               }
-               catch (const tcu::Exception&)
-               {
-                       // Build failed for other reason
-                       log << buildInfo;
-                       throw;
-               }
-
-               TCU_CHECK_INTERNAL(binProg);
+               vk::ProgramBinary* binProg = buildProgram<glu::ShaderProgramInfo, vk::GlslSourceCollection::Iterator>(casePath, progIter, &m_context, &m_progCollection);
 
                try
                {
@@ -157,8 +184,11 @@ void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePat
                {
                        log << err;
                }
+       }
 
-               m_progCollection.add(progId.programName, binProg);
+       for (vk::SpirVAsmCollection::Iterator asmIterator = sourceProgs.spirvAsmSources.begin(); asmIterator != sourceProgs.spirvAsmSources.end(); ++asmIterator)
+       {
+               buildProgram<vk::SpirVProgramInfo, vk::SpirVAsmCollection::Iterator>(casePath, asmIterator, &m_context, &m_progCollection);
        }
 
        DE_ASSERT(!m_instance);
index 55bbc90..0bbc1f6 100644 (file)
@@ -98,6 +98,10 @@ if (NOT DEFINED TCUTIL_PLATFORM_SRCS)
 endif ()
 
 add_library(tcutil-platform STATIC ${TCUTIL_PLATFORM_SRCS})
+
+# Add vkutil to the deps before tcutil so that it picks up the c++11 dependencies
+target_link_libraries(tcutil-platform vkutil)
+
 target_link_libraries(tcutil-platform tcutil ${TCUTIL_PLATFORM_LIBS})
 
 # Always link to glutil as some platforms such as Win32 always support GL
@@ -108,8 +112,6 @@ if (DEQP_SUPPORT_EGL)
        target_link_libraries(tcutil-platform eglutil eglwrapper)
 endif ()
 
-target_link_libraries(tcutil-platform vkutil)
-
 # X11 libraries
 if (DEQP_USE_X11)
        find_package(X11 REQUIRED)