Add GLSL to SPIR-V compilation support using glslang
authorPyry Haulos <phaulos@google.com>
Fri, 19 Jun 2015 22:25:34 +0000 (15:25 -0700)
committerPyry Haulos <phaulos@google.com>
Wed, 24 Jun 2015 22:15:28 +0000 (15:15 -0700)
Change-Id: Ie28c68f482355ebab5e4e913cab075fe7188e7ce

CMakeLists.txt
external/glslang/CMakeLists.txt [new file with mode: 0644]
external/glslang/osinclude.cpp [new file with mode: 0644]
external/glslang/osinclude.h [new file with mode: 0644]
framework/vulkan/CMakeLists.txt
framework/vulkan/vkGlslToSpirV.cpp [new file with mode: 0644]
framework/vulkan/vkGlslToSpirV.hpp [new file with mode: 0644]
framework/vulkan/vkPrograms.cpp
framework/vulkan/vkPrograms.hpp
modules/vulkan/vktTestPackage.cpp

index e91b79f..a3811b5 100644 (file)
@@ -75,6 +75,9 @@ if (NOT PNG_INCLUDE_PATH OR NOT PNG_LIBRARY)
        # \note PNG_LIBRARY and PNG_INCLUDE_PATH are promoted from external/libpng/CMakeLists.txt
 endif ()
 
+# glslang
+add_subdirectory(external/glslang)
+
 include_directories(${PNG_INCLUDE_PATH})
 
 message(STATUS "DEQP_TARGET_NAME        = ${DEQP_TARGET_NAME}")
diff --git a/external/glslang/CMakeLists.txt b/external/glslang/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ca53d4f
--- /dev/null
@@ -0,0 +1,109 @@
+# cmake file for glslang
+
+if (NOT DE_DEFS)
+       message(FATAL_ERROR "Include Defs.cmake")
+endif ()
+
+# Assume build inside Android source tree
+set(DEFAULT_GLSLANG_SRC_PATH "../glslang")
+
+set(GLSLANG_SRC_PATH ${DEFAULT_GLSLANG_SRC_PATH} CACHE STRING "Path to glslang source tree")
+
+if (IS_ABSOLUTE ${GLSLANG_SRC_PATH})
+       set(GLSLANG_ABS_PATH ${GLSLANG_SRC_PATH})
+else ()
+       set(GLSLANG_ABS_PATH "${CMAKE_SOURCE_DIR}/${GLSLANG_SRC_PATH}")
+endif ()
+
+find_package(BISON)
+
+# \todo [2015-06-24 pyry] Full C++11 support on Android requires using CLang + libc++
+if (NOT BISON_FOUND AND DE_OS_IS_WIN32 AND EXISTS ${GLSLANG_ABS_PATH}/tools/bison.exe)
+       message(STATUS "Using pre-built bison executable")
+       set(BISON_EXECUTABLE ${GLSLANG_ABS_PATH}/tools/bison.exe)
+       set(BISON_FOUND ON)
+endif ()
+
+if (BISON_FOUND AND EXISTS ${GLSLANG_ABS_PATH}/glslang/GenericCodeGen/CodeGen.cpp AND NOT DE_OS_IS_ANDROID)
+       message(STATUS "glslang found; building with DEQP_SUPPORT_GLSLANG")
+
+       include_directories(
+               .
+               ${GLSLANG_ABS_PATH}
+               ${GLSLANG_ABS_PATH}/glslang
+               ${GLSLANG_ABS_PATH}/glslang/Include
+               ${GLSLANG_ABS_PATH}/glslang/Public
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent
+               ${GLSLANG_ABS_PATH}/glslang/GenericCodeGen
+               ${GLSLANG_ABS_PATH}/OGLCompilersDLL
+               ${GLSLANG_ABS_PATH}/SPIRV
+               ${CMAKE_CURRENT_BINARY_DIR}
+               )
+
+       set(GLSLANG_SRCS
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Constant.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/InfoSink.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Initialize.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/IntermTraverse.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Intermediate.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/ParseHelper.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/PoolAlloc.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/RemoveTree.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Scan.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/ShaderLang.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/SymbolTable.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/Versions.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/intermOut.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/limits.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/linkValidate.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/parseConst.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/reflection.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/Pp.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpAtom.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpContext.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpMemory.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpScanner.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpSymbols.cpp
+               ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/preprocessor/PpTokens.cpp
+               ${GLSLANG_ABS_PATH}/glslang/GenericCodeGen/CodeGen.cpp
+               ${GLSLANG_ABS_PATH}/glslang/GenericCodeGen/Link.cpp
+               ${GLSLANG_ABS_PATH}/OGLCompilersDLL/InitializeDll.cpp
+
+               ${GLSLANG_ABS_PATH}/SPIRV/GlslangToSpv.cpp
+               ${GLSLANG_ABS_PATH}/SPIRV/SpvBuilder.cpp
+               ${GLSLANG_ABS_PATH}/SPIRV/SPVRemapper.cpp
+               ${GLSLANG_ABS_PATH}/SPIRV/doc.cpp
+               ${GLSLANG_ABS_PATH}/SPIRV/disassemble.cpp
+
+               ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp
+               ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp.h
+
+               osinclude.h
+               osinclude.cpp
+               )
+
+       set(CMAKE_C_FLAGS       ${DE_3RD_PARTY_C_FLAGS})
+       set(CMAKE_CXX_FLAGS     ${DE_3RD_PARTY_CXX_FLAGS})
+
+       if (DE_COMPILER_IS_GCC OR DE_COMPILER_IS_CLANG)
+               set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+       endif ()
+
+       add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp.h
+                                          COMMAND ${BISON_EXECUTABLE} --defines=${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp.h -t MachineIndependent/glslang.y -o ${CMAKE_CURRENT_BINARY_DIR}/glslang_tab.cpp
+                                          MAIN_DEPENDENCY ${GLSLANG_ABS_PATH}/glslang/MachineIndependent/glslang.y
+                                          WORKING_DIRECTORY ${GLSLANG_ABS_PATH}/glslang)
+
+       add_library(glslang STATIC ${GLSLANG_SRCS})
+       target_link_libraries(glslang dethread ${ZLIB_LIBRARY})
+
+       set(GLSLANG_INCLUDE_PATH        ${GLSLANG_ABS_PATH}     PARENT_SCOPE)
+       set(GLSLANG_LIBRARY                     glslang                         PARENT_SCOPE)
+       set(DEQP_HAVE_GLSLANG           ON                                      PARENT_SCOPE)
+
+else ()
+       message(STATUS "glslang not found; GLSL to SPIR-V compilation not available")
+
+       set(DEQP_HAVE_GLSLANG           OFF                                     PARENT_SCOPE)
+
+endif ()
diff --git a/external/glslang/osinclude.cpp b/external/glslang/osinclude.cpp
new file mode 100644 (file)
index 0000000..9341ec7
--- /dev/null
@@ -0,0 +1,96 @@
+/*-------------------------------------------------------------------------
+ * dEQP glslang integration
+ * ------------------------
+ *
+ * Copyright 2015 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 glslang OS interface.
+ *//*--------------------------------------------------------------------*/
+
+#include "osinclude.h"
+
+namespace glslang
+{
+
+// Thread-local
+
+OS_TLSIndex OS_AllocTLSIndex (void)
+{
+       return deThreadLocal_create();
+}
+
+bool OS_SetTLSValue (OS_TLSIndex nIndex, void* lpvValue)
+{
+       deThreadLocal_set(nIndex, lpvValue);
+       return true;
+}
+
+bool OS_FreeTLSIndex (OS_TLSIndex nIndex)
+{
+       deThreadLocal_destroy(nIndex);
+       return true;
+}
+
+void* OS_GetTLSValue (OS_TLSIndex nIndex)
+{
+       return deThreadLocal_get(nIndex);
+}
+
+// Global lock - not used
+
+void InitGlobalLock (void)
+{
+}
+
+void GetGlobalLock (void)
+{
+}
+
+void ReleaseGlobalLock (void)
+{
+}
+
+// Threading
+
+DE_STATIC_ASSERT(sizeof(void*) >= sizeof(deThread));
+
+void* OS_CreateThread (TThreadEntrypoint entry)
+{
+       return (void*)(deUintptr)deThread_create(entry, DE_NULL, DE_NULL);
+}
+
+void OS_WaitForAllThreads (void* threads, int numThreads)
+{
+       for (int ndx = 0; ndx < numThreads; ndx++)
+       {
+               const deThread thread = (deThread)(deUintptr)((void**)threads)[ndx];
+               deThread_join(thread);
+               deThread_destroy(thread);
+       }
+}
+
+void OS_Sleep (int milliseconds)
+{
+       deSleep(milliseconds);
+}
+
+void OS_DumpMemoryCounters (void)
+{
+       // Not used
+}
+
+} // glslang
diff --git a/external/glslang/osinclude.h b/external/glslang/osinclude.h
new file mode 100644 (file)
index 0000000..7174579
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _OSINCLUDE_H
+#define _OSINCLUDE_H
+/*-------------------------------------------------------------------------
+ * dEQP glslang integration
+ * ------------------------
+ *
+ * Copyright 2015 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 glslang OS interface.
+ *//*--------------------------------------------------------------------*/
+
+#include "deDefs.hpp"
+#include "deThreadLocal.h"
+#include "deThread.h"
+
+namespace glslang
+{
+
+// Thread-local
+
+typedef deThreadLocal OS_TLSIndex;
+
+#define OS_INVALID_TLS_INDEX   DE_NULL
+
+OS_TLSIndex    OS_AllocTLSIndex                (void);
+bool           OS_SetTLSValue                  (OS_TLSIndex nIndex, void* lpvValue);
+bool           OS_FreeTLSIndex                 (OS_TLSIndex nIndex);
+
+void*          OS_GetTLSValue                  (OS_TLSIndex nIndex);
+
+// Global lock?
+
+void           InitGlobalLock                  (void);
+void           GetGlobalLock                   (void);
+void           ReleaseGlobalLock               (void);
+
+// Threading
+
+typedef deThreadFunc TThreadEntrypoint;
+
+void*          OS_CreateThread                 (TThreadEntrypoint);
+void           OS_WaitForAllThreads    (void* threads, int numThreads);
+
+void           OS_Sleep                                (int milliseconds);
+
+void           OS_DumpMemoryCounters   (void);
+
+} // glslang
+
+#endif /* _OSINCLUDE_H */
index 369e82e..b3380b5 100644 (file)
@@ -17,11 +17,25 @@ set(VKUTIL_SRCS
        vkMemUtil.hpp
        vkDeviceUtil.cpp
        vkDeviceUtil.hpp
+       vkGlslToSpirV.cpp
+       vkGlslToSpirV.hpp
        )
 
+# \note Code interfacing with glslang needs to include third-party headers
+#       that cause all sorts of warnings to appear.
+set_source_files_properties(
+       FILES vkGlslToSpirV.cpp
+       PROPERTIES COMPILE_FLAGS ${DE_3RD_PARTY_CXX_FLAGS})
+
 set(VKUTIL_LIBS
        tcutil
        )
 
+if (DEQP_HAVE_GLSLANG)
+       include_directories(${GLSLANG_INCLUDE_PATH})
+       add_definitions(-DDEQP_HAVE_GLSLANG=1)
+       set(VKUTIL_LIBS ${VKUTIL_LIBS} ${GLSLANG_LIBRARY})
+endif ()
+
 add_library(vkutil STATIC ${VKUTIL_SRCS})
 target_link_libraries(vkutil ${VKUTIL_LIBS})
diff --git a/framework/vulkan/vkGlslToSpirV.cpp b/framework/vulkan/vkGlslToSpirV.cpp
new file mode 100644 (file)
index 0000000..193132b
--- /dev/null
@@ -0,0 +1,261 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program Vulkan Utilities
+ * -----------------------------------------------
+ *
+ * Copyright 2015 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 GLSL to SPIR-V.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkGlslToSpirV.hpp"
+#include "deArrayUtil.hpp"
+#include "deMemory.h"
+#include "qpDebugOut.h"
+
+#if defined(DEQP_HAVE_GLSLANG)
+#      include "deSingleton.h"
+#      include "deMutex.hpp"
+
+#      include "SPIRV/GlslangToSpv.h"
+#      include "glslang/Include/InfoSink.h"
+#      include "glslang/Include/ShHandle.h"
+#      include "glslang/MachineIndependent/localintermediate.h"
+#      include "glslang/Public/ShaderLang.h"
+#endif
+
+namespace vk
+{
+
+using std::string;
+using std::vector;
+
+#if defined(DEQP_HAVE_GLSLANG)
+
+namespace
+{
+
+EShLanguage getGlslangStage (glu::ShaderType type)
+{
+       static const EShLanguage stageMap[] =
+       {
+               EShLangVertex,
+               EShLangFragment,
+               EShLangGeometry,
+               EShLangTessControl,
+               EShLangTessEvaluation,
+               EShLangCompute,
+       };
+       return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
+}
+
+static volatile deSingletonState       s_glslangInitState      = DE_SINGLETON_STATE_NOT_INITIALIZED;
+static de::Mutex                                       s_glslangLock;
+
+void initGlslang (void*)
+{
+       ShInitialize();
+}
+
+void prepareGlslang (void)
+{
+       deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
+}
+
+class SpvGenerator : public TCompiler
+{
+public:
+       SpvGenerator (EShLanguage language, std::vector<deUint32>& dst, TInfoSink& infoSink)
+               : TCompiler     (language, infoSink)
+               , m_dst         (dst)
+       {
+       }
+
+       bool compile (TIntermNode* root, int version = 0, EProfile profile = ENoProfile)
+       {
+               glslang::TIntermediate intermediate(getLanguage(), version, profile);
+               intermediate.setTreeRoot(root);
+               glslang::GlslangToSpv(intermediate, m_dst);
+               return true;
+       }
+
+private:
+       std::vector<deUint32>&  m_dst;
+};
+
+// \todo [2015-06-19 pyry] Specialize these per GLSL version
+
+// Fail compilation if more members are added to TLimits or TBuiltInResource
+struct LimitsSizeHelper_s                      { bool m0, m1, m2, m3, m4, m5, m6, m7, m8; };
+struct BuiltInResourceSizeHelper_s     { int m[83]; LimitsSizeHelper_s l; };
+
+DE_STATIC_ASSERT(sizeof(TLimits)                       == sizeof(LimitsSizeHelper_s));
+DE_STATIC_ASSERT(sizeof(TBuiltInResource)      == sizeof(BuiltInResourceSizeHelper_s));
+
+void getDefaultLimits (TLimits* limits)
+{
+       limits->nonInductiveForLoops                                    = true;
+       limits->whileLoops                                                              = true;
+       limits->doWhileLoops                                                    = true;
+       limits->generalUniformIndexing                                  = true;
+       limits->generalAttributeMatrixVectorIndexing    = true;
+       limits->generalVaryingIndexing                                  = true;
+       limits->generalSamplerIndexing                                  = true;
+       limits->generalVariableIndexing                                 = true;
+       limits->generalConstantMatrixVectorIndexing             = true;
+}
+
+void getDefaultBuiltInResources (TBuiltInResource* builtin)
+{
+       getDefaultLimits(&builtin->limits);
+
+       builtin->maxLights                                                                      = 32;
+       builtin->maxClipPlanes                                                          = 6;
+       builtin->maxTextureUnits                                                        = 32;
+       builtin->maxTextureCoords                                                       = 32;
+       builtin->maxVertexAttribs                                                       = 64;
+       builtin->maxVertexUniformComponents                                     = 4096;
+       builtin->maxVaryingFloats                                                       = 64;
+       builtin->maxVertexTextureImageUnits                                     = 32;
+       builtin->maxCombinedTextureImageUnits                           = 80;
+       builtin->maxTextureImageUnits                                           = 32;
+       builtin->maxFragmentUniformComponents                           = 4096;
+       builtin->maxDrawBuffers                                                         = 32;
+       builtin->maxVertexUniformVectors                                        = 128;
+       builtin->maxVaryingVectors                                                      = 8;
+       builtin->maxFragmentUniformVectors                                      = 16;
+       builtin->maxVertexOutputVectors                                         = 16;
+       builtin->maxFragmentInputVectors                                        = 15;
+       builtin->minProgramTexelOffset                                          = -8;
+       builtin->maxProgramTexelOffset                                          = 7;
+       builtin->maxClipDistances                                                       = 8;
+       builtin->maxComputeWorkGroupCountX                                      = 65535;
+       builtin->maxComputeWorkGroupCountY                                      = 65535;
+       builtin->maxComputeWorkGroupCountZ                                      = 65535;
+       builtin->maxComputeWorkGroupSizeX                                       = 1024;
+       builtin->maxComputeWorkGroupSizeX                                       = 1024;
+       builtin->maxComputeWorkGroupSizeZ                                       = 64;
+       builtin->maxComputeUniformComponents                            = 1024;
+       builtin->maxComputeTextureImageUnits                            = 16;
+       builtin->maxComputeImageUniforms                                        = 8;
+       builtin->maxComputeAtomicCounters                                       = 8;
+       builtin->maxComputeAtomicCounterBuffers                         = 1;
+       builtin->maxVaryingComponents                                           = 60;
+       builtin->maxVertexOutputComponents                                      = 64;
+       builtin->maxGeometryInputComponents                                     = 64;
+       builtin->maxGeometryOutputComponents                            = 128;
+       builtin->maxFragmentInputComponents                                     = 128;
+       builtin->maxImageUnits                                                          = 8;
+       builtin->maxCombinedImageUnitsAndFragmentOutputs        = 8;
+       builtin->maxCombinedShaderOutputResources                       = 8;
+       builtin->maxImageSamples                                                        = 0;
+       builtin->maxVertexImageUniforms                                         = 0;
+       builtin->maxTessControlImageUniforms                            = 0;
+       builtin->maxTessEvaluationImageUniforms                         = 0;
+       builtin->maxGeometryImageUniforms                                       = 0;
+       builtin->maxFragmentImageUniforms                                       = 8;
+       builtin->maxCombinedImageUniforms                                       = 8;
+       builtin->maxGeometryTextureImageUnits                           = 16;
+       builtin->maxGeometryOutputVertices                                      = 256;
+       builtin->maxGeometryTotalOutputComponents                       = 1024;
+       builtin->maxGeometryUniformComponents                           = 1024;
+       builtin->maxGeometryVaryingComponents                           = 64;
+       builtin->maxTessControlInputComponents                          = 128;
+       builtin->maxTessControlOutputComponents                         = 128;
+       builtin->maxTessControlTextureImageUnits                        = 16;
+       builtin->maxTessControlUniformComponents                        = 1024;
+       builtin->maxTessControlTotalOutputComponents            = 4096;
+       builtin->maxTessEvaluationInputComponents                       = 128;
+       builtin->maxTessEvaluationOutputComponents                      = 128;
+       builtin->maxTessEvaluationTextureImageUnits                     = 16;
+       builtin->maxTessEvaluationUniformComponents                     = 1024;
+       builtin->maxTessPatchComponents                                         = 120;
+       builtin->maxPatchVertices                                                       = 32;
+       builtin->maxTessGenLevel                                                        = 64;
+       builtin->maxViewports                                                           = 16;
+       builtin->maxVertexAtomicCounters                                        = 0;
+       builtin->maxTessControlAtomicCounters                           = 0;
+       builtin->maxTessEvaluationAtomicCounters                        = 0;
+       builtin->maxGeometryAtomicCounters                                      = 0;
+       builtin->maxFragmentAtomicCounters                                      = 8;
+       builtin->maxCombinedAtomicCounters                                      = 8;
+       builtin->maxAtomicCounterBindings                                       = 1;
+       builtin->maxVertexAtomicCounterBuffers                          = 0;
+       builtin->maxTessControlAtomicCounterBuffers                     = 0;
+       builtin->maxTessEvaluationAtomicCounterBuffers          = 0;
+       builtin->maxGeometryAtomicCounterBuffers                        = 0;
+       builtin->maxFragmentAtomicCounterBuffers                        = 1;
+       builtin->maxCombinedAtomicCounterBuffers                        = 1;
+       builtin->maxAtomicCounterBufferSize                                     = 16384;
+       builtin->maxTransformFeedbackBuffers                            = 4;
+       builtin->maxTransformFeedbackInterleavedComponents      = 64;
+       builtin->maxCullDistances                                                       = 8;
+       builtin->maxCombinedClipAndCullDistances                        = 8;
+       builtin->maxSamples                                                                     = 4;
+};
+
+} // anonymous
+
+void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>& dst)
+{
+       TBuiltInResource        builtinRes;
+
+       prepareGlslang();
+       getDefaultBuiltInResources(&builtinRes);
+
+       // \note Compiles only first found shader
+       for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+       {
+               if (!program.sources[shaderType].empty())
+               {
+                       de::ScopedLock          compileLock     (s_glslangLock);
+                       const char* const       srcText         = program.sources[shaderType][0].c_str();
+                       const int                       srcLen          = (int)program.sources[shaderType][0].size();
+                       vector<deUint32>        spvBlob;
+                       TInfoSink                       infoSink;
+                       SpvGenerator            compiler        (getGlslangStage(glu::ShaderType(shaderType)), spvBlob, infoSink);
+                       const int                       compileOk       = ShCompile(static_cast<ShHandle>(&compiler), &srcText, 1, &srcLen, EShOptNone, &builtinRes, 0);
+
+                       if (compileOk == 0)
+                       {
+                               // \todo [2015-06-19 pyry] Create special CompileException and pass error messages through that
+                               qpPrint(infoSink.info.c_str());
+                               TCU_FAIL("Failed to compile shader");
+                       }
+
+                       dst.resize(spvBlob.size() * sizeof(deUint32));
+#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
+                       deMemcpy(&dst[0], &spvBlob[0], dst.size());
+#else
+#      error "Big-endian not supported"
+#endif
+                       return;
+               }
+       }
+
+       TCU_THROW(InternalError, "Can't compile empty program");
+}
+
+#else // defined(DEQP_HAVE_GLSLANG)
+
+void glslToSpirV (const glu::ProgramSources&, std::vector<deUint8>&)
+{
+       TCU_THROW(NotSupportedError, "GLSL to SPIR-V compilation not supported (DEQP_HAVE_GLSLANG not defined)");
+}
+
+#endif
+
+} // vk
diff --git a/framework/vulkan/vkGlslToSpirV.hpp b/framework/vulkan/vkGlslToSpirV.hpp
new file mode 100644 (file)
index 0000000..2081cc1
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _VKGLSLTOSPIRV_HPP
+#define _VKGLSLTOSPIRV_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program Vulkan Utilities
+ * -----------------------------------------------
+ *
+ * Copyright 2015 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 GLSL to SPIR-V.
+ *//*--------------------------------------------------------------------*/
+
+#include "vkDefs.hpp"
+#include "gluShaderProgram.hpp"
+
+namespace vk
+{
+
+//! Compile GLSL program to SPIR-V. Will fail with NotSupportedError if compiler is not available.
+void   glslToSpirV             (const glu::ProgramSources& src, std::vector<deUint8>& dst);
+
+} // vk
+
+#endif // _VKGLSLTOSPIRV_HPP
index 8f78c1f..69f00c0 100644 (file)
@@ -22,6 +22,7 @@
  *//*--------------------------------------------------------------------*/
 
 #include "vkPrograms.hpp"
+#include "vkGlslToSpirV.hpp"
 #include "deArrayUtil.hpp"
 #include "deMemory.h"
 
@@ -56,10 +57,6 @@ struct BinaryHeader
 
 DE_STATIC_ASSERT(sizeof(BinaryHeader) == sizeof(deUint32)*7);
 
-#if (DE_ENDIANNESS != DE_LITTLE_ENDIAN)
-#      error Big-endian not supported
-#endif
-
 size_t computeSrcArrayTotalLength (const vector<string>& sources)
 {
        size_t total = 0;
@@ -154,38 +151,65 @@ VkShaderStage getShaderStage (glu::ShaderType type)
 
 ProgramBinary* buildProgram (const glu::ProgramSources& program, ProgramFormat binaryFormat)
 {
-       if (binaryFormat == PROGRAM_FORMAT_GLSL)
+       if (binaryFormat == PROGRAM_FORMAT_GLSL_SOURCE)
        {
                vector<deUint8> binary;
                encodeGLSLBinary(program, binary);
                return new ProgramBinary(binaryFormat, binary.size(), &binary[0]);
        }
+       else if (binaryFormat == PROGRAM_FORMAT_SPIRV)
+       {
+               vector<deUint8> binary;
+               glslToSpirV(program, binary);
+               return new ProgramBinary(binaryFormat, binary.size(), &binary[0]);
+       }
        else
                TCU_THROW(NotSupportedError, "Unsupported program format");
 }
 
-void setShaderBinary (const DeviceInterface& vk, VkShader shader, const ProgramBinary& binary)
+Move<VkShaderT> createShader (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderCreateFlags flags)
 {
-       DE_UNREF(vk);
-       DE_UNREF(shader);
-       DE_UNREF(binary);
-#if 0
-       if (binary.getFormat() == PROGRAM_FORMAT_GLSL)
+       if (binary.getFormat() == PROGRAM_FORMAT_GLSL_SOURCE)
        {
+               // HACK: just concatenate everything
                glu::ProgramSources     sources;
+               std::string                     concatenated;
 
                decodeGLSLBinary(binary.getSize(), binary.getBinary(), sources);
 
                for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
                {
-                       DE_ASSERT(sources.sources[shaderType].size() <= 1);
+                       for (size_t ndx = 0; ndx < sources.sources[shaderType].size(); ++ndx)
+                               concatenated += sources.sources[shaderType][ndx];
+               }
 
-                       if (!sources.sources[shaderType].empty())
-                               vk.programSetSource(program, getShaderStage(static_cast<glu::ShaderType>(shaderType)), sources.sources[shaderType][0].c_str());
+               {
+                       const struct VkShaderCreateInfo         shaderInfo      =
+                       {
+                               VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,   //      VkStructureType         sType;
+                               DE_NULL,                                                                //      const void*                     pNext;
+                               (deUintptr)concatenated.size(),                 //      deUintptr                       codeSize;
+                               concatenated.c_str(),                                   //      const void*                     pCode;
+                               flags,                                                                  //      VkShaderCreateFlags     flags;
+                       };
+
+                       return createShader(deviceInterface, device, &shaderInfo);
                }
        }
+       else if (binary.getFormat() == PROGRAM_FORMAT_SPIRV)
+       {
+               const struct VkShaderCreateInfo         shaderInfo      =
+               {
+                       VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,   //      VkStructureType         sType;
+                       DE_NULL,                                                                //      const void*                     pNext;
+                       (deUintptr)binary.getSize(),                    //      deUintptr                       codeSize;
+                       binary.getBinary(),                                             //      const void*                     pCode;
+                       flags,                                                                  //      VkShaderCreateFlags     flags;
+               };
+
+               return createShader(deviceInterface, device, &shaderInfo);
+       }
        else
-#endif
                TCU_THROW(NotSupportedError, "Unsupported program format");
 }
 
index c860880..81aebcb 100644 (file)
@@ -24,6 +24,7 @@
  *//*--------------------------------------------------------------------*/
 
 #include "vkDefs.hpp"
+#include "vkRef.hpp"
 #include "gluShaderProgram.hpp"
 #include "deUniquePtr.hpp"
 #include "deSTLUtil.hpp"
@@ -35,7 +36,10 @@ namespace vk
 
 enum ProgramFormat
 {
-       PROGRAM_FORMAT_GLSL = 0
+       PROGRAM_FORMAT_GLSL_SOURCE = 0,
+       PROGRAM_FORMAT_SPIRV,
+
+       PROGRAM_FORMAT_LAST
 };
 
 class ProgramBinary
@@ -152,8 +156,8 @@ typedef ProgramCollection<glu::ProgramSources>      SourceCollection;
 typedef ProgramCollection<ProgramBinary>               BinaryCollection;
 
 // \todo [2015-03-13 pyry] Likely need BinaryBuilder abstraction for this
-ProgramBinary* buildProgram            (const glu::ProgramSources& program, ProgramFormat binaryFormat);
-void                   setShaderBinary         (const DeviceInterface& deviceInterface, VkShader shader, const ProgramBinary& binary);
+ProgramBinary*         buildProgram    (const glu::ProgramSources& program, ProgramFormat binaryFormat);
+Move<VkShaderT>                createShader    (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderCreateFlags flags);
 
 } // vk
 
index f12a5c9..a06687b 100644 (file)
@@ -96,7 +96,7 @@ void TestCaseExecutor::init (tcu::TestCase* testCase, const std::string& casePat
        {
                const std::string&                              name            = progIter.getName();
                const glu::ProgramSources&              srcProg         = progIter.getProgram();
-               de::MovePtr<vk::ProgramBinary>  binProg         = de::MovePtr<vk::ProgramBinary>(vk::buildProgram(srcProg, vk::PROGRAM_FORMAT_GLSL));
+               de::MovePtr<vk::ProgramBinary>  binProg         = de::MovePtr<vk::ProgramBinary>(vk::buildProgram(srcProg, vk::PROGRAM_FORMAT_SPIRV));
 
                m_progCollection.add(name, binProg);
        }