Externals: Add glslang from Vulkan SDK v1.0.21.1
This commit is contained in:
parent
49e57df2b6
commit
951fc44d86
|
@ -635,6 +635,8 @@ endif()
|
|||
add_subdirectory(Externals/Bochs_disasm)
|
||||
include_directories(Externals/Bochs_disasm)
|
||||
|
||||
add_subdirectory(Externals/glslang)
|
||||
|
||||
if(USE_SHARED_ENET)
|
||||
check_lib(ENET libenet enet enet/enet.h QUIET)
|
||||
include(CheckSymbolExists)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# Windows Build Configuration for AppVeyor
|
||||
# http://www.appveyor.com/docs/appveyor-yml
|
||||
|
||||
# build version format
|
||||
version: "{build}"
|
||||
|
||||
os: Visual Studio 2013
|
||||
|
||||
platform:
|
||||
- Any CPU
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
clone_depth: 5
|
||||
|
||||
matrix:
|
||||
fast_finish: true # Show final status immediately if a test fails.
|
||||
|
||||
# scripts that run after cloning repository
|
||||
install:
|
||||
- git clone https://github.com/google/googletest.git External/googletest
|
||||
|
||||
build:
|
||||
parallel: true # enable MSBuild parallel builds
|
||||
verbosity: minimal
|
||||
|
||||
build_script:
|
||||
- mkdir build && cd build
|
||||
- cmake .. -DCMAKE_INSTALL_PREFIX=install
|
||||
- cmake --build . --config %CONFIGURATION% --target install
|
||||
|
||||
test_script:
|
||||
- ctest -C %CONFIGURATION% --output-on-failure
|
||||
- cd ../Test && bash runtests
|
|
@ -0,0 +1,12 @@
|
|||
Language: Cpp
|
||||
IndentWidth: 4
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping: { AfterFunction: true, AfterControlStatement: true }
|
||||
IndentCaseLabels: false
|
||||
ReflowComments: false
|
||||
ColumnLimit: 120
|
||||
AccessModifierOffset: -4
|
||||
AlignTrailingComments: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
|
@ -0,0 +1,60 @@
|
|||
# Linux and Mac Build Configuration for Travis
|
||||
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
# Use Ubuntu 14.04 LTS (Trusty) as the Linux testing environment.
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
- GLSLANG_BUILD_TYPE=Release
|
||||
- GLSLANG_BUILD_TYPE=Debug
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
matrix:
|
||||
fast_finish: true # Show final status immediately if a test fails.
|
||||
exclude:
|
||||
# Skip GCC builds on Mac OS X.
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.6
|
||||
- ninja-build
|
||||
|
||||
install:
|
||||
# Install ninja on Mac OS X.
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update && brew install ninja; fi
|
||||
# Make sure that clang-3.6 is selected.
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$CC" == "clang" ]]; then
|
||||
export CC=clang-3.6 CXX=clang++-3.6;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- git clone https://github.com/google/googletest.git External/googletest
|
||||
|
||||
script:
|
||||
- mkdir build && cd build
|
||||
# We need to install the compiled binaries so the paths in the runtests script can resolve correctly.
|
||||
- cmake -GNinja -DCMAKE_BUILD_TYPE=${GLSLANG_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=`pwd`/install ..
|
||||
- ninja install
|
||||
# Run Google-Test-based tests.
|
||||
- ctest --output-on-failure
|
||||
# Run runtests-based tests.
|
||||
- cd ../Test && ./runtests
|
|
@ -0,0 +1,58 @@
|
|||
set(SRCS
|
||||
glslang/GenericCodeGen/CodeGen.cpp
|
||||
glslang/GenericCodeGen/Link.cpp
|
||||
glslang/MachineIndependent/Constant.cpp
|
||||
glslang/MachineIndependent/glslang_tab.cpp
|
||||
glslang/MachineIndependent/InfoSink.cpp
|
||||
glslang/MachineIndependent/Initialize.cpp
|
||||
glslang/MachineIndependent/Intermediate.cpp
|
||||
glslang/MachineIndependent/intermOut.cpp
|
||||
glslang/MachineIndependent/IntermTraverse.cpp
|
||||
glslang/MachineIndependent/limits.cpp
|
||||
glslang/MachineIndependent/linkValidate.cpp
|
||||
glslang/MachineIndependent/parseConst.cpp
|
||||
glslang/MachineIndependent/ParseHelper.cpp
|
||||
glslang/MachineIndependent/PoolAlloc.cpp
|
||||
glslang/MachineIndependent/preprocessor/Pp.cpp
|
||||
glslang/MachineIndependent/preprocessor/PpAtom.cpp
|
||||
glslang/MachineIndependent/preprocessor/PpContext.cpp
|
||||
glslang/MachineIndependent/preprocessor/PpMemory.cpp
|
||||
glslang/MachineIndependent/preprocessor/PpScanner.cpp
|
||||
glslang/MachineIndependent/preprocessor/PpSymbols.cpp
|
||||
glslang/MachineIndependent/preprocessor/PpTokens.cpp
|
||||
glslang/MachineIndependent/propagateNoContraction.cpp
|
||||
glslang/MachineIndependent/reflection.cpp
|
||||
glslang/MachineIndependent/RemoveTree.cpp
|
||||
glslang/MachineIndependent/Scan.cpp
|
||||
glslang/MachineIndependent/ShaderLang.cpp
|
||||
glslang/MachineIndependent/SymbolTable.cpp
|
||||
glslang/MachineIndependent/Versions.cpp
|
||||
glslang/OSDependent/Unix/ossource.cpp
|
||||
hlsl/hlslGrammar.cpp
|
||||
hlsl/hlslOpMap.cpp
|
||||
hlsl/hlslParseables.cpp
|
||||
hlsl/hlslParseHelper.cpp
|
||||
hlsl/hlslScanContext.cpp
|
||||
hlsl/hlslTokenStream.cpp
|
||||
OGLCompilersDLL/InitializeDll.cpp
|
||||
SPIRV/disassemble.cpp
|
||||
SPIRV/doc.cpp
|
||||
SPIRV/GlslangToSpv.cpp
|
||||
SPIRV/InReadableOrder.cpp
|
||||
SPIRV/Logger.cpp
|
||||
SPIRV/SpvBuilder.cpp
|
||||
SPIRV/SPVRemapper.cpp
|
||||
)
|
||||
|
||||
# glslang requires C++11 at a minimum to compile.
|
||||
add_definitions(-std=c++11)
|
||||
|
||||
# Silence some warnings that occur frequently to reduce noise in build logs.
|
||||
add_definitions(-Wno-shadow)
|
||||
add_definitions(-Wno-reorder)
|
||||
add_definitions(-Wno-sign-compare)
|
||||
add_definitions(-Wno-parentheses)
|
||||
add_definitions(-Wno-unused-variable)
|
||||
|
||||
add_library(glslang STATIC ${SRCS})
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
enable_testing()
|
||||
|
||||
set(CMAKE_INSTALL_PREFIX "install" CACHE STRING "prefix")
|
||||
|
||||
project(glslang)
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_DEBUG_POSTFIX "d")
|
||||
include(ChooseMSVCCRT.cmake)
|
||||
add_definitions(-DGLSLANG_OSINCLUDE_WIN32)
|
||||
elseif(UNIX)
|
||||
add_definitions(-fPIC)
|
||||
add_definitions(-DGLSLANG_OSINCLUDE_UNIX)
|
||||
else(WIN32)
|
||||
message("unknown platform")
|
||||
endif(WIN32)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
add_definitions(-std=c++11)
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
add_definitions(-std=c++11)
|
||||
endif()
|
||||
|
||||
function(glslang_set_link_args TARGET)
|
||||
# For MinGW compiles, statically link against the GCC and C++ runtimes.
|
||||
# This avoids the need to ship those runtimes as DLLs.
|
||||
if(WIN32)
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
set_target_properties(${TARGET} PROPERTIES
|
||||
LINK_FLAGS "-static -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
endif(WIN32)
|
||||
endfunction(glslang_set_link_args)
|
||||
|
||||
# We depend on these for later projects, so they should come first.
|
||||
add_subdirectory(External)
|
||||
|
||||
add_subdirectory(glslang)
|
||||
add_subdirectory(OGLCompilersDLL)
|
||||
add_subdirectory(StandAlone)
|
||||
add_subdirectory(SPIRV)
|
||||
add_subdirectory(hlsl)
|
||||
add_subdirectory(gtests)
|
|
@ -0,0 +1,105 @@
|
|||
# The macro choose_msvc_crt() takes a list of possible
|
||||
# C runtimes to choose from, in the form of compiler flags,
|
||||
# to present to the user. (MTd for /MTd, etc)
|
||||
#
|
||||
# The macro is invoked at the end of the file.
|
||||
#
|
||||
# CMake already sets CRT flags in the CMAKE_CXX_FLAGS_* and
|
||||
# CMAKE_C_FLAGS_* variables by default. To let the user
|
||||
# override that for each build type:
|
||||
# 1. Detect which CRT is already selected, and reflect this in
|
||||
# LLVM_USE_CRT_* so the user can have a better idea of what
|
||||
# changes they're making.
|
||||
# 2. Replace the flags in both variables with the new flag via a regex.
|
||||
# 3. set() the variables back into the cache so the changes
|
||||
# are user-visible.
|
||||
|
||||
### Helper macros: ###
|
||||
macro(make_crt_regex regex crts)
|
||||
set(${regex} "")
|
||||
foreach(crt ${${crts}})
|
||||
# Trying to match the beginning or end of the string with stuff
|
||||
# like [ ^]+ didn't work, so use a bunch of parentheses instead.
|
||||
set(${regex} "${${regex}}|(^| +)/${crt}($| +)")
|
||||
endforeach(crt)
|
||||
string(REGEX REPLACE "^\\|" "" ${regex} "${${regex}}")
|
||||
endmacro(make_crt_regex)
|
||||
|
||||
macro(get_current_crt crt_current regex flagsvar)
|
||||
# Find the selected-by-CMake CRT for each build type, if any.
|
||||
# Strip off the leading slash and any whitespace.
|
||||
string(REGEX MATCH "${${regex}}" ${crt_current} "${${flagsvar}}")
|
||||
string(REPLACE "/" " " ${crt_current} "${${crt_current}}")
|
||||
string(STRIP "${${crt_current}}" ${crt_current})
|
||||
endmacro(get_current_crt)
|
||||
|
||||
# Replaces or adds a flag to a variable.
|
||||
# Expects 'flag' to be padded with spaces.
|
||||
macro(set_flag_in_var flagsvar regex flag)
|
||||
string(REGEX MATCH "${${regex}}" current_flag "${${flagsvar}}")
|
||||
if("${current_flag}" STREQUAL "")
|
||||
set(${flagsvar} "${${flagsvar}}${${flag}}")
|
||||
else()
|
||||
string(REGEX REPLACE "${${regex}}" "${${flag}}" ${flagsvar} "${${flagsvar}}")
|
||||
endif()
|
||||
string(STRIP "${${flagsvar}}" ${flagsvar})
|
||||
# Make sure this change gets reflected in the cache/gui.
|
||||
# CMake requires the docstring parameter whenever set() touches the cache,
|
||||
# so get the existing docstring and re-use that.
|
||||
get_property(flagsvar_docs CACHE ${flagsvar} PROPERTY HELPSTRING)
|
||||
set(${flagsvar} "${${flagsvar}}" CACHE STRING "${flagsvar_docs}" FORCE)
|
||||
endmacro(set_flag_in_var)
|
||||
|
||||
|
||||
macro(choose_msvc_crt MSVC_CRT)
|
||||
if(LLVM_USE_CRT)
|
||||
message(FATAL_ERROR
|
||||
"LLVM_USE_CRT is deprecated. Use the CMAKE_BUILD_TYPE-specific
|
||||
variables (LLVM_USE_CRT_DEBUG, etc) instead.")
|
||||
endif()
|
||||
|
||||
make_crt_regex(MSVC_CRT_REGEX ${MSVC_CRT})
|
||||
|
||||
foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
|
||||
string(TOUPPER "${build_type}" build)
|
||||
if (NOT LLVM_USE_CRT_${build})
|
||||
get_current_crt(LLVM_USE_CRT_${build}
|
||||
MSVC_CRT_REGEX
|
||||
CMAKE_CXX_FLAGS_${build})
|
||||
set(LLVM_USE_CRT_${build}
|
||||
"${LLVM_USE_CRT_${build}}"
|
||||
CACHE STRING "Specify VC++ CRT to use for ${build_type} configurations."
|
||||
FORCE)
|
||||
set_property(CACHE LLVM_USE_CRT_${build}
|
||||
PROPERTY STRINGS ;${${MSVC_CRT}})
|
||||
endif(NOT LLVM_USE_CRT_${build})
|
||||
endforeach(build_type)
|
||||
|
||||
foreach(build_type ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE})
|
||||
string(TOUPPER "${build_type}" build)
|
||||
if ("${LLVM_USE_CRT_${build}}" STREQUAL "")
|
||||
set(flag_string " ")
|
||||
else()
|
||||
set(flag_string " /${LLVM_USE_CRT_${build}} ")
|
||||
list(FIND ${MSVC_CRT} ${LLVM_USE_CRT_${build}} idx)
|
||||
if (idx LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Invalid value for LLVM_USE_CRT_${build}: ${LLVM_USE_CRT_${build}}. Valid options are one of: ${${MSVC_CRT}}")
|
||||
endif (idx LESS 0)
|
||||
message(STATUS "Using ${build_type} VC++ CRT: ${LLVM_USE_CRT_${build}}")
|
||||
endif()
|
||||
foreach(lang C CXX)
|
||||
set_flag_in_var(CMAKE_${lang}_FLAGS_${build} MSVC_CRT_REGEX flag_string)
|
||||
endforeach(lang)
|
||||
endforeach(build_type)
|
||||
endmacro(choose_msvc_crt MSVC_CRT)
|
||||
|
||||
|
||||
# List of valid CRTs for MSVC
|
||||
set(MSVC_CRT
|
||||
MD
|
||||
MDd
|
||||
MT
|
||||
MTd)
|
||||
|
||||
choose_msvc_crt(MSVC_CRT)
|
|
@ -0,0 +1,34 @@
|
|||
# Suppress all warnings from external projects.
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_OPTIONS -w)
|
||||
|
||||
if (TARGET gmock)
|
||||
message(STATUS "Google Mock already configured - use it")
|
||||
elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/googletest)
|
||||
# We need to make sure Google Test does not mess up with the
|
||||
# global CRT settings on Windows.
|
||||
if(WIN32)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
endif(WIN32)
|
||||
add_subdirectory(googletest)
|
||||
set(GTEST_TARGETS
|
||||
gtest
|
||||
gtest_main
|
||||
gmock
|
||||
gmock_main
|
||||
)
|
||||
foreach(target ${GTEST_TARGETS})
|
||||
set_property(TARGET ${target} PROPERTY FOLDER gtest)
|
||||
endforeach()
|
||||
mark_as_advanced(gmock_build_tests
|
||||
BUILD_GMOCK
|
||||
BUILD_GTEST
|
||||
BUILD_SHARED_LIBS
|
||||
gtest_build_samples
|
||||
gtest_build_tests
|
||||
gtest_disable_pthreads
|
||||
gtest_force_shared_crt
|
||||
gtest_hide_internal_symbols)
|
||||
else()
|
||||
message(STATUS
|
||||
"Google Mock was not found - tests based on that will not build")
|
||||
endif()
|
|
@ -0,0 +1,11 @@
|
|||
set(SOURCES InitializeDll.cpp InitializeDll.h)
|
||||
|
||||
add_library(OGLCompiler STATIC ${SOURCES})
|
||||
set_property(TARGET OGLCompiler PROPERTY FOLDER glslang)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES})
|
||||
endif(WIN32)
|
||||
|
||||
install(TARGETS OGLCompiler
|
||||
ARCHIVE DESTINATION lib)
|
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#define SH_EXPORTING
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "InitializeDll.h"
|
||||
#include "../glslang/Include/InitializeGlobals.h"
|
||||
|
||||
#include "../glslang/Public/ShaderLang.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
|
||||
|
||||
bool InitProcess()
|
||||
{
|
||||
glslang::GetGlobalLock();
|
||||
|
||||
if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) {
|
||||
//
|
||||
// Function is re-entrant.
|
||||
//
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
ThreadInitializeIndex = OS_AllocTLSIndex();
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "InitProcess(): Failed to allocate TLS area for init flag");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! InitializePoolIndex()) {
|
||||
assert(0 && "InitProcess(): Failed to initialize global pool");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! InitThread()) {
|
||||
assert(0 && "InitProcess(): Failed to initialize thread");
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return false;
|
||||
}
|
||||
|
||||
glslang::ReleaseGlobalLock();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool InitThread()
|
||||
{
|
||||
//
|
||||
// This function is re-entrant
|
||||
//
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "InitThread(): Process hasn't been initalised.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
|
||||
return true;
|
||||
|
||||
InitializeMemoryPools();
|
||||
|
||||
if (! OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
|
||||
assert(0 && "InitThread(): Unable to set init flag.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DetachThread()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
|
||||
return true;
|
||||
|
||||
//
|
||||
// Function is re-entrant and this thread may not have been initialized.
|
||||
//
|
||||
if (OS_GetTLSValue(ThreadInitializeIndex) != 0) {
|
||||
if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) {
|
||||
assert(0 && "DetachThread(): Unable to clear init flag.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
FreeGlobalPools();
|
||||
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool DetachProcess()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
|
||||
return true;
|
||||
|
||||
ShFinalize();
|
||||
|
||||
success = DetachThread();
|
||||
|
||||
FreePoolIndex();
|
||||
|
||||
OS_FreeTLSIndex(ThreadInitializeIndex);
|
||||
ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifndef __INITIALIZEDLL_H
|
||||
#define __INITIALIZEDLL_H
|
||||
|
||||
|
||||
#include "../glslang/OSDependent/osinclude.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
bool InitProcess();
|
||||
bool InitThread();
|
||||
bool DetachThread();
|
||||
bool DetachProcess();
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // __INITIALIZEDLL_H
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
|
||||
VERSION
|
||||
--------------------------------------------------------------------------------
|
||||
spirv-remap 0.97
|
||||
|
||||
INTRO:
|
||||
--------------------------------------------------------------------------------
|
||||
spirv-remap is a utility to improve compression of SPIR-V binary files via
|
||||
entropy reduction, plus optional stripping of debug information and
|
||||
load/store optimization. It transforms SPIR-V to SPIR-V, remapping IDs. The
|
||||
resulting modules have an increased ID range (IDs are not as tightly packed
|
||||
around zero), but will compress better when multiple modules are compressed
|
||||
together, since compressor's dictionary can find better cross module
|
||||
commonality.
|
||||
|
||||
Remapping is accomplished via canonicalization. Thus, modules can be
|
||||
compressed one at a time with no loss of quality relative to operating on
|
||||
many modules at once. The command line tool operates on multiple modules
|
||||
only in the trivial repetition sense, for ease of use. The remapper API
|
||||
only accepts a single module at a time.
|
||||
|
||||
There are two modes of use: command line, and a C++11 API. Both are
|
||||
described below.
|
||||
|
||||
spirv-remap is currently in an alpha state. Although there are no known
|
||||
remapping defects, it has only been exercised on one real world game shader
|
||||
workload.
|
||||
|
||||
|
||||
FEEDBACK
|
||||
--------------------------------------------------------------------------------
|
||||
Report defects, enhancements requests, code improvements, etc to:
|
||||
spvremapper@lunarg.com
|
||||
|
||||
|
||||
COMMAND LINE USAGE:
|
||||
--------------------------------------------------------------------------------
|
||||
Examples are given with a verbosity of one (-v), but more verbosity can be
|
||||
had via -vv, -vvv, etc, or an integer parameter to --verbose, such as
|
||||
"--verbose 4". With no verbosity, the command is silent and returns 0 on
|
||||
success, and a positive integer error on failure.
|
||||
|
||||
Pre-built binaries for several OSs are available. Examples presented are
|
||||
for Linux. Command line arguments can be provided in any order.
|
||||
|
||||
1. Basic ID remapping
|
||||
|
||||
Perform ID remapping on all shaders in "*.spv", writing new files with
|
||||
the same basenames to /tmp/out_dir.
|
||||
|
||||
spirv-remap -v --map all --input *.spv --output /tmp/out_dir
|
||||
|
||||
2. Perform all possible size reductions
|
||||
|
||||
spirv-remap-linux-64 -v --do-everything --input *.spv --output /tmp/out_dir
|
||||
|
||||
Note that --do-everything is a synonym for:
|
||||
|
||||
--map all --dce all --opt all --strip all
|
||||
|
||||
API USAGE:
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
The public interface to the remapper is defined in SPIRV/SPVRemapper.h as follows:
|
||||
|
||||
namespace spv {
|
||||
|
||||
class spirvbin_t
|
||||
{
|
||||
public:
|
||||
enum Options { ... };
|
||||
spirvbin_t(int verbose = 0); // construct
|
||||
|
||||
// remap an existing binary in memory
|
||||
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
|
||||
|
||||
// Type for error/log handler functions
|
||||
typedef std::function<void(const std::string&)> errorfn_t;
|
||||
typedef std::function<void(const std::string&)> logfn_t;
|
||||
|
||||
// Register error/log handling functions (can be c/c++ fn, lambda fn, or functor)
|
||||
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
|
||||
static void registerLogHandler(logfn_t handler) { logHandler = handler; }
|
||||
};
|
||||
|
||||
} // namespace spv
|
||||
|
||||
The class definition is in SPVRemapper.cpp.
|
||||
|
||||
remap() accepts an std::vector of SPIR-V words, modifies them per the
|
||||
request given in 'opts', and leaves the 'spv' container with the result.
|
||||
It is safe to instantiate one spirvbin_t per thread and process a different
|
||||
SPIR-V in each.
|
||||
|
||||
The "opts" parameter to remap() accepts a bit mask of desired remapping
|
||||
options. See REMAPPING AND OPTIMIZATION OPTIONS.
|
||||
|
||||
On error, the function supplied to registerErrorHandler() will be invoked.
|
||||
This can be a standard C/C++ function, a lambda function, or a functor.
|
||||
The default handler simply calls exit(5); The error handler is a static
|
||||
members, so need only be set up once, not once per spirvbin_t instance.
|
||||
|
||||
Log messages are supplied to registerLogHandler(). By default, log
|
||||
messages are eaten silently. The log handler is also a static member.
|
||||
|
||||
BUILD DEPENDENCIES:
|
||||
--------------------------------------------------------------------------------
|
||||
1. C++11 compatible compiler
|
||||
2. cmake
|
||||
3. glslang
|
||||
|
||||
|
||||
BUILDING
|
||||
--------------------------------------------------------------------------------
|
||||
The standalone remapper is built along side glslangValidator through its
|
||||
normal build process.
|
||||
|
||||
|
||||
REMAPPING AND OPTIMIZATION OPTIONS
|
||||
--------------------------------------------------------------------------------
|
||||
API:
|
||||
These are bits defined under spv::spirvbin_t::, and can be
|
||||
bitwise or-ed together as desired.
|
||||
|
||||
MAP_TYPES = canonicalize type IDs
|
||||
MAP_NAMES = canonicalize named data
|
||||
MAP_FUNCS = canonicalize function bodies
|
||||
DCE_FUNCS = remove dead functions
|
||||
DCE_VARS = remove dead variables
|
||||
DCE_TYPES = remove dead types
|
||||
OPT_LOADSTORE = optimize unneeded load/stores
|
||||
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS)
|
||||
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES)
|
||||
OPT_ALL = (OPT_LOADSTORE)
|
||||
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL)
|
||||
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
Also see the Khronos landing page for glslang as a reference front end:
|
||||
|
||||
https://www.khronos.org/opengles/sdk/tools/Reference-Compiler/
|
||||
|
||||
The above page includes where to get binaries, and is kept up to date
|
||||
regarding the feature level of glslang.
|
||||
|
||||
glslang
|
||||
=======
|
||||
|
||||
[![Build Status](https://travis-ci.org/KhronosGroup/glslang.svg?branch=master)](https://travis-ci.org/KhronosGroup/glslang)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/q6fi9cb0qnhkla68/branch/master?svg=true)](https://ci.appveyor.com/project/Khronoswebmaster/glslang/branch/master)
|
||||
|
||||
An OpenGL and OpenGL ES shader front end and validator.
|
||||
|
||||
There are two components:
|
||||
|
||||
1. A front-end library for programmatic parsing of GLSL/ESSL into an AST.
|
||||
|
||||
2. A standalone wrapper, `glslangValidator`, that can be used as a shader
|
||||
validation tool.
|
||||
|
||||
How to add a feature protected by a version/extension/stage/profile: See the
|
||||
comment in `glslang/MachineIndependent/Versions.cpp`.
|
||||
|
||||
Tasks waiting to be done are documented as GitHub issues.
|
||||
|
||||
Execution of Standalone Wrapper
|
||||
-------------------------------
|
||||
|
||||
To use the standalone binary form, execute `glslangValidator`, and it will print
|
||||
a usage statement. Basic operation is to give it a file containing a shader,
|
||||
and it will print out warnings/errors and optionally an AST.
|
||||
|
||||
The applied stage-specific rules are based on the file extension:
|
||||
* `.vert` for a vertex shader
|
||||
* `.tesc` for a tessellation control shader
|
||||
* `.tese` for a tessellation evaluation shader
|
||||
* `.geom` for a geometry shader
|
||||
* `.frag` for a fragment shader
|
||||
* `.comp` for a compute shader
|
||||
|
||||
There is also a non-shader extension
|
||||
* `.conf` for a configuration file of limits, see usage statement for example
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
### Dependencies
|
||||
|
||||
* [CMake][cmake]: for generating compilation targets.
|
||||
* [bison][bison]: _optional_, but needed when changing the grammar (glslang.y).
|
||||
* [googletest][googletest]: _optional_, but should use if making any changes to glslang.
|
||||
|
||||
### Build steps
|
||||
|
||||
#### 1) Check-Out External Projects
|
||||
|
||||
```bash
|
||||
cd <the directory glslang was cloned to, External will be a subdirectory>
|
||||
git clone https://github.com/google/googletest.git External/googletest
|
||||
```
|
||||
|
||||
#### 2) Configure
|
||||
|
||||
Assume the source directory is `$SOURCE_DIR` and
|
||||
the build directory is `$BUILD_DIR`:
|
||||
|
||||
For building on Linux (assuming using the Ninja generator):
|
||||
|
||||
```bash
|
||||
cd $BUILD_DIR
|
||||
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE={Debug|Release|RelWithDebInfo} \
|
||||
-DCMAKE_INSTALL_PREFIX=`pwd`/install $SOURCE_DIR
|
||||
```
|
||||
|
||||
For building on Windows:
|
||||
|
||||
```bash
|
||||
cmake $SOURCE_DIR -DCMAKE_INSTALL_PREFIX=`pwd`/install
|
||||
# The CMAKE_INSTALL_PREFIX part is for testing (explained later).
|
||||
```
|
||||
|
||||
The CMake GUI also works for Windows (version 3.4.1 tested).
|
||||
|
||||
#### 3) Build and Install
|
||||
|
||||
```bash
|
||||
# for Linux:
|
||||
ninja install
|
||||
|
||||
# for Windows:
|
||||
cmake --build . --config {Release|Debug|MinSizeRel|RelWithDebInfo} \
|
||||
--target install
|
||||
```
|
||||
|
||||
If using MSVC, after running CMake to configure, use the
|
||||
Configuration Manager to check the `INSTALL` project.
|
||||
|
||||
### If you need to change the GLSL grammar
|
||||
|
||||
The grammar in `glslang/MachineIndependent/glslang.y` has to be recompiled with
|
||||
bison if it changes, the output files are committed to the repo to avoid every
|
||||
developer needing to have bison configured to compile the project when grammar
|
||||
changes are quite infrequent. For windows you can get binaries from
|
||||
[GnuWin32][bison-gnu-win32].
|
||||
|
||||
The command to rebuild is:
|
||||
|
||||
```bash
|
||||
bison --defines=MachineIndependent/glslang_tab.cpp.h
|
||||
-t MachineIndependent/glslang.y
|
||||
-o MachineIndependent/glslang_tab.cpp
|
||||
```
|
||||
|
||||
The above command is also available in the bash script at
|
||||
`glslang/updateGrammar`.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
Right now, there are two test harnesses existing in glslang: one is [Google
|
||||
Test](gtests/), one is the [`runtests` script](Test/runtests). The former
|
||||
runs unit tests and single-shader single-threaded integration tests, while
|
||||
the latter runs multiple-shader linking tests and multi-threaded tests.
|
||||
|
||||
### Running tests
|
||||
|
||||
The [`runtests` script](Test/runtests) requires compiled binaries to be
|
||||
installed into `$BUILD_DIR/install`. Please make sure you have supplied the
|
||||
correct configuration to CMake (using `-DCMAKE_INSTALL_PREFIX`) when building;
|
||||
otherwise, you may want to modify the path in the `runtests` script.
|
||||
|
||||
Running Google Test-backed tests:
|
||||
|
||||
```bash
|
||||
cd $BUILD_DIR
|
||||
|
||||
# for Linux:
|
||||
ctest
|
||||
|
||||
# for Windows:
|
||||
ctest -C {Debug|Release|RelWithDebInfo|MinSizeRel}
|
||||
|
||||
# or, run the test binary directly
|
||||
# (which gives more fine-grained control like filtering):
|
||||
<dir-to-glslangtests-in-build-dir>/glslangtests
|
||||
```
|
||||
|
||||
Running `runtests` script-backed tests:
|
||||
|
||||
```bash
|
||||
cd $SOURCE_DIR/Test && ./runtests
|
||||
```
|
||||
|
||||
### Contributing tests
|
||||
|
||||
Test results should always be included with a pull request that modifies
|
||||
functionality.
|
||||
|
||||
If you are writing unit tests, please use the Google Test framework and
|
||||
place the tests under the `gtests/` directory.
|
||||
|
||||
Integration tests are placed in the `Test/` directory. It contains test input
|
||||
and a subdirectory `baseResults/` that contains the expected results of the
|
||||
tests. Both the tests and `baseResults/` are under source-code control.
|
||||
|
||||
Google Test runs those integration tests by reading the test input, compiling
|
||||
them, and then compare against the expected results in `baseResults/`. The
|
||||
integration tests to run via Google Test is registered in various
|
||||
`gtests/*.FromFile.cpp` source files. `glslangtests` provides a command-line
|
||||
option `--update-mode`, which, if supplied, will overwrite the golden files
|
||||
under the `baseResults/` directory with real output from that invocation.
|
||||
For more information, please check `gtests/` directory's
|
||||
[README](gtests/README.md).
|
||||
|
||||
For the `runtests` script, it will generate current results in the
|
||||
`localResults/` directory and `diff` them against the `baseResults/`.
|
||||
When you want to update the tracked test results, they need to be
|
||||
copied from `localResults/` to `baseResults/`. This can be done by
|
||||
the `bump` shell script.
|
||||
|
||||
You can add your own private list of tests, not tracked publicly, by using
|
||||
`localtestlist` to list non-tracked tests. This is automatically read
|
||||
by `runtests` and included in the `diff` and `bump` process.
|
||||
|
||||
Programmatic Interfaces
|
||||
-----------------------
|
||||
|
||||
Another piece of software can programmatically translate shaders to an AST
|
||||
using one of two different interfaces:
|
||||
* A new C++ class-oriented interface, or
|
||||
* The original C functional interface
|
||||
|
||||
The `main()` in `StandAlone/StandAlone.cpp` shows examples using both styles.
|
||||
|
||||
### C++ Class Interface (new, preferred)
|
||||
|
||||
This interface is in roughly the last 1/3 of `ShaderLang.h`. It is in the
|
||||
glslang namespace and contains the following.
|
||||
|
||||
```cxx
|
||||
const char* GetEsslVersionString();
|
||||
const char* GetGlslVersionString();
|
||||
bool InitializeProcess();
|
||||
void FinalizeProcess();
|
||||
|
||||
class TShader
|
||||
bool parse(...);
|
||||
void setStrings(...);
|
||||
const char* getInfoLog();
|
||||
|
||||
class TProgram
|
||||
void addShader(...);
|
||||
bool link(...);
|
||||
const char* getInfoLog();
|
||||
Reflection queries
|
||||
```
|
||||
|
||||
See `ShaderLang.h` and the usage of it in `StandAlone/StandAlone.cpp` for more
|
||||
details.
|
||||
|
||||
### C Functional Interface (orignal)
|
||||
|
||||
This interface is in roughly the first 2/3 of `ShaderLang.h`, and referred to
|
||||
as the `Sh*()` interface, as all the entry points start `Sh`.
|
||||
|
||||
The `Sh*()` interface takes a "compiler" call-back object, which it calls after
|
||||
building call back that is passed the AST and can then execute a backend on it.
|
||||
|
||||
The following is a simplified resulting run-time call stack:
|
||||
|
||||
```c
|
||||
ShCompile(shader, compiler) -> compiler(AST) -> <back end>
|
||||
```
|
||||
|
||||
In practice, `ShCompile()` takes shader strings, default version, and
|
||||
warning/error and other options for controlling compilation.
|
||||
|
||||
Basic Internal Operation
|
||||
------------------------
|
||||
|
||||
* Initial lexical analysis is done by the preprocessor in
|
||||
`MachineIndependent/Preprocessor`, and then refined by a GLSL scanner
|
||||
in `MachineIndependent/Scan.cpp`. There is currently no use of flex.
|
||||
|
||||
* Code is parsed using bison on `MachineIndependent/glslang.y` with the
|
||||
aid of a symbol table and an AST. The symbol table is not passed on to
|
||||
the back-end; the intermediate representation stands on its own.
|
||||
The tree is built by the grammar productions, many of which are
|
||||
offloaded into `ParseHelper.cpp`, and by `Intermediate.cpp`.
|
||||
|
||||
* The intermediate representation is very high-level, and represented
|
||||
as an in-memory tree. This serves to lose no information from the
|
||||
original program, and to have efficient transfer of the result from
|
||||
parsing to the back-end. In the AST, constants are propogated and
|
||||
folded, and a very small amount of dead code is eliminated.
|
||||
|
||||
To aid linking and reflection, the last top-level branch in the AST
|
||||
lists all global symbols.
|
||||
|
||||
* The primary algorithm of the back-end compiler is to traverse the
|
||||
tree (high-level intermediate representation), and create an internal
|
||||
object code representation. There is an example of how to do this
|
||||
in `MachineIndependent/intermOut.cpp`.
|
||||
|
||||
* Reduction of the tree to a linear byte-code style low-level intermediate
|
||||
representation is likely a good way to generate fully optimized code.
|
||||
|
||||
* There is currently some dead old-style linker-type code still lying around.
|
||||
|
||||
* Memory pool: parsing uses types derived from C++ `std` types, using a
|
||||
custom allocator that puts them in a memory pool. This makes allocation
|
||||
of individual container/contents just few cycles and deallocation free.
|
||||
This pool is popped after the AST is made and processed.
|
||||
|
||||
The use is simple: if you are going to call `new`, there are three cases:
|
||||
|
||||
- the object comes from the pool (its base class has the macro
|
||||
`POOL_ALLOCATOR_NEW_DELETE` in it) and you do not have to call `delete`
|
||||
|
||||
- it is a `TString`, in which case call `NewPoolTString()`, which gets
|
||||
it from the pool, and there is no corresponding `delete`
|
||||
|
||||
- the object does not come from the pool, and you have to do normal
|
||||
C++ memory management of what you `new`
|
||||
|
||||
|
||||
[cmake]: https://cmake.org/
|
||||
[bison]: https://www.gnu.org/software/bison/
|
||||
[googletest]: https://github.com/google/googletest
|
||||
[bison-gnu-win32]: http://gnuwin32.sourceforge.net/packages/bison.htm
|
|
@ -0,0 +1,29 @@
|
|||
set(SOURCES
|
||||
GlslangToSpv.cpp
|
||||
InReadableOrder.cpp
|
||||
Logger.cpp
|
||||
SpvBuilder.cpp
|
||||
SPVRemapper.cpp
|
||||
doc.cpp
|
||||
disassemble.cpp)
|
||||
|
||||
set(HEADERS
|
||||
spirv.hpp
|
||||
GLSL.std.450.h
|
||||
GlslangToSpv.h
|
||||
Logger.h
|
||||
SpvBuilder.h
|
||||
SPVRemapper.h
|
||||
spvIR.h
|
||||
doc.h
|
||||
disassemble.h)
|
||||
|
||||
add_library(SPIRV STATIC ${SOURCES} ${HEADERS})
|
||||
set_property(TARGET SPIRV PROPERTY FOLDER glslang)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES} ${HEADERS})
|
||||
endif(WIN32)
|
||||
|
||||
install(TARGETS SPIRV
|
||||
ARCHIVE DESTINATION lib)
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
** Copyright (c) 2014-2016 The Khronos Group 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 and this permission notice shall be included in
|
||||
** all copies or substantial portions of the Materials.
|
||||
**
|
||||
** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#ifndef GLSLstd450_H
|
||||
#define GLSLstd450_H
|
||||
|
||||
static const int GLSLstd450Version = 100;
|
||||
static const int GLSLstd450Revision = 1;
|
||||
|
||||
enum GLSLstd450 {
|
||||
GLSLstd450Bad = 0, // Don't use
|
||||
|
||||
GLSLstd450Round = 1,
|
||||
GLSLstd450RoundEven = 2,
|
||||
GLSLstd450Trunc = 3,
|
||||
GLSLstd450FAbs = 4,
|
||||
GLSLstd450SAbs = 5,
|
||||
GLSLstd450FSign = 6,
|
||||
GLSLstd450SSign = 7,
|
||||
GLSLstd450Floor = 8,
|
||||
GLSLstd450Ceil = 9,
|
||||
GLSLstd450Fract = 10,
|
||||
|
||||
GLSLstd450Radians = 11,
|
||||
GLSLstd450Degrees = 12,
|
||||
GLSLstd450Sin = 13,
|
||||
GLSLstd450Cos = 14,
|
||||
GLSLstd450Tan = 15,
|
||||
GLSLstd450Asin = 16,
|
||||
GLSLstd450Acos = 17,
|
||||
GLSLstd450Atan = 18,
|
||||
GLSLstd450Sinh = 19,
|
||||
GLSLstd450Cosh = 20,
|
||||
GLSLstd450Tanh = 21,
|
||||
GLSLstd450Asinh = 22,
|
||||
GLSLstd450Acosh = 23,
|
||||
GLSLstd450Atanh = 24,
|
||||
GLSLstd450Atan2 = 25,
|
||||
|
||||
GLSLstd450Pow = 26,
|
||||
GLSLstd450Exp = 27,
|
||||
GLSLstd450Log = 28,
|
||||
GLSLstd450Exp2 = 29,
|
||||
GLSLstd450Log2 = 30,
|
||||
GLSLstd450Sqrt = 31,
|
||||
GLSLstd450InverseSqrt = 32,
|
||||
|
||||
GLSLstd450Determinant = 33,
|
||||
GLSLstd450MatrixInverse = 34,
|
||||
|
||||
GLSLstd450Modf = 35, // second operand needs an OpVariable to write to
|
||||
GLSLstd450ModfStruct = 36, // no OpVariable operand
|
||||
GLSLstd450FMin = 37,
|
||||
GLSLstd450UMin = 38,
|
||||
GLSLstd450SMin = 39,
|
||||
GLSLstd450FMax = 40,
|
||||
GLSLstd450UMax = 41,
|
||||
GLSLstd450SMax = 42,
|
||||
GLSLstd450FClamp = 43,
|
||||
GLSLstd450UClamp = 44,
|
||||
GLSLstd450SClamp = 45,
|
||||
GLSLstd450FMix = 46,
|
||||
GLSLstd450IMix = 47, // Reserved
|
||||
GLSLstd450Step = 48,
|
||||
GLSLstd450SmoothStep = 49,
|
||||
|
||||
GLSLstd450Fma = 50,
|
||||
GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to
|
||||
GLSLstd450FrexpStruct = 52, // no OpVariable operand
|
||||
GLSLstd450Ldexp = 53,
|
||||
|
||||
GLSLstd450PackSnorm4x8 = 54,
|
||||
GLSLstd450PackUnorm4x8 = 55,
|
||||
GLSLstd450PackSnorm2x16 = 56,
|
||||
GLSLstd450PackUnorm2x16 = 57,
|
||||
GLSLstd450PackHalf2x16 = 58,
|
||||
GLSLstd450PackDouble2x32 = 59,
|
||||
GLSLstd450UnpackSnorm2x16 = 60,
|
||||
GLSLstd450UnpackUnorm2x16 = 61,
|
||||
GLSLstd450UnpackHalf2x16 = 62,
|
||||
GLSLstd450UnpackSnorm4x8 = 63,
|
||||
GLSLstd450UnpackUnorm4x8 = 64,
|
||||
GLSLstd450UnpackDouble2x32 = 65,
|
||||
|
||||
GLSLstd450Length = 66,
|
||||
GLSLstd450Distance = 67,
|
||||
GLSLstd450Cross = 68,
|
||||
GLSLstd450Normalize = 69,
|
||||
GLSLstd450FaceForward = 70,
|
||||
GLSLstd450Reflect = 71,
|
||||
GLSLstd450Refract = 72,
|
||||
|
||||
GLSLstd450FindILsb = 73,
|
||||
GLSLstd450FindSMsb = 74,
|
||||
GLSLstd450FindUMsb = 75,
|
||||
|
||||
GLSLstd450InterpolateAtCentroid = 76,
|
||||
GLSLstd450InterpolateAtSample = 77,
|
||||
GLSLstd450InterpolateAtOffset = 78,
|
||||
|
||||
GLSLstd450NMin = 79,
|
||||
GLSLstd450NMax = 80,
|
||||
GLSLstd450NClamp = 81,
|
||||
|
||||
GLSLstd450Count
|
||||
};
|
||||
|
||||
#endif // #ifndef GLSLstd450_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
//Copyright (C) 2014 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "../glslang/Include/intermediate.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
void GetSpirvVersion(std::string&);
|
||||
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv);
|
||||
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger);
|
||||
void OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName);
|
||||
void OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName);
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
//Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// The SPIR-V spec requires code blocks to appear in an order satisfying the
|
||||
// dominator-tree direction (ie, dominator before the dominated). This is,
|
||||
// actually, easy to achieve: any pre-order CFG traversal algorithm will do it.
|
||||
// Because such algorithms visit a block only after traversing some path to it
|
||||
// from the root, they necessarily visit the block's idom first.
|
||||
//
|
||||
// But not every graph-traversal algorithm outputs blocks in an order that
|
||||
// appears logical to human readers. The problem is that unrelated branches may
|
||||
// be interspersed with each other, and merge blocks may come before some of the
|
||||
// branches being merged.
|
||||
//
|
||||
// A good, human-readable order of blocks may be achieved by performing
|
||||
// depth-first search but delaying merge nodes until after all their branches
|
||||
// have been visited. This is implemented below by the inReadableOrder()
|
||||
// function.
|
||||
|
||||
#include "spvIR.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
|
||||
using spv::Block;
|
||||
using spv::Id;
|
||||
|
||||
namespace {
|
||||
// Traverses CFG in a readable order, invoking a pre-set callback on each block.
|
||||
// Use by calling visit() on the root block.
|
||||
class ReadableOrderTraverser {
|
||||
public:
|
||||
explicit ReadableOrderTraverser(std::function<void(Block*)> callback) : callback_(callback) {}
|
||||
// Visits the block if it hasn't been visited already and isn't currently
|
||||
// being delayed. Invokes callback(block), then descends into its
|
||||
// successors. Delays merge-block and continue-block processing until all
|
||||
// the branches have been completed.
|
||||
void visit(Block* block)
|
||||
{
|
||||
assert(block);
|
||||
if (visited_[block] || delayed_[block])
|
||||
return;
|
||||
callback_(block);
|
||||
visited_[block] = true;
|
||||
Block* mergeBlock = nullptr;
|
||||
Block* continueBlock = nullptr;
|
||||
auto mergeInst = block->getMergeInstruction();
|
||||
if (mergeInst) {
|
||||
Id mergeId = mergeInst->getIdOperand(0);
|
||||
mergeBlock = block->getParent().getParent().getInstruction(mergeId)->getBlock();
|
||||
delayed_[mergeBlock] = true;
|
||||
if (mergeInst->getOpCode() == spv::OpLoopMerge) {
|
||||
Id continueId = mergeInst->getIdOperand(1);
|
||||
continueBlock =
|
||||
block->getParent().getParent().getInstruction(continueId)->getBlock();
|
||||
delayed_[continueBlock] = true;
|
||||
}
|
||||
}
|
||||
const auto successors = block->getSuccessors();
|
||||
for (auto it = successors.cbegin(); it != successors.cend(); ++it)
|
||||
visit(*it);
|
||||
if (continueBlock) {
|
||||
delayed_[continueBlock] = false;
|
||||
visit(continueBlock);
|
||||
}
|
||||
if (mergeBlock) {
|
||||
delayed_[mergeBlock] = false;
|
||||
visit(mergeBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void(Block*)> callback_;
|
||||
// Whether a block has already been visited or is being delayed.
|
||||
std::unordered_map<Block *, bool> visited_, delayed_;
|
||||
};
|
||||
}
|
||||
|
||||
void spv::inReadableOrder(Block* root, std::function<void(Block*)> callback)
|
||||
{
|
||||
ReadableOrderTraverser(callback).visit(root);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
namespace spv {
|
||||
|
||||
void SpvBuildLogger::tbdFunctionality(const std::string& f)
|
||||
{
|
||||
if (std::find(std::begin(tbdFeatures), std::end(tbdFeatures), f) == std::end(tbdFeatures))
|
||||
tbdFeatures.push_back(f);
|
||||
}
|
||||
|
||||
void SpvBuildLogger::missingFunctionality(const std::string& f)
|
||||
{
|
||||
if (std::find(std::begin(missingFeatures), std::end(missingFeatures), f) == std::end(missingFeatures))
|
||||
missingFeatures.push_back(f);
|
||||
}
|
||||
|
||||
std::string SpvBuildLogger::getAllMessages() const {
|
||||
std::ostringstream messages;
|
||||
for (auto it = tbdFeatures.cbegin(); it != tbdFeatures.cend(); ++it)
|
||||
messages << "TBD functionality: " << *it << "\n";
|
||||
for (auto it = missingFeatures.cbegin(); it != missingFeatures.cend(); ++it)
|
||||
messages << "Missing functionality: " << *it << "\n";
|
||||
for (auto it = warnings.cbegin(); it != warnings.cend(); ++it)
|
||||
messages << "warning: " << *it << "\n";
|
||||
for (auto it = errors.cbegin(); it != errors.cend(); ++it)
|
||||
messages << "error: " << *it << "\n";
|
||||
return messages.str();
|
||||
}
|
||||
|
||||
} // end spv namespace
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GLSLANG_SPIRV_LOGGER_H
|
||||
#define GLSLANG_SPIRV_LOGGER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
// A class for holding all SPIR-V build status messages, including
|
||||
// missing/TBD functionalities, warnings, and errors.
|
||||
class SpvBuildLogger {
|
||||
public:
|
||||
SpvBuildLogger() {}
|
||||
|
||||
// Registers a TBD functionality.
|
||||
void tbdFunctionality(const std::string& f);
|
||||
// Registers a missing functionality.
|
||||
void missingFunctionality(const std::string& f);
|
||||
|
||||
// Logs a warning.
|
||||
void warning(const std::string& w) { warnings.push_back(w); }
|
||||
// Logs an error.
|
||||
void error(const std::string& e) { errors.push_back(e); }
|
||||
|
||||
// Returns all messages accumulated in the order of:
|
||||
// TBD functionalities, missing functionalities, warnings, errors.
|
||||
std::string getAllMessages() const;
|
||||
|
||||
private:
|
||||
SpvBuildLogger(const SpvBuildLogger&);
|
||||
|
||||
std::vector<std::string> tbdFeatures;
|
||||
std::vector<std::string> missingFeatures;
|
||||
std::vector<std::string> warnings;
|
||||
std::vector<std::string> errors;
|
||||
};
|
||||
|
||||
} // end spv namespace
|
||||
|
||||
#endif // GLSLANG_SPIRV_LOGGER_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,288 @@
|
|||
//
|
||||
//Copyright (C) 2015 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef SPIRVREMAPPER_H
|
||||
#define SPIRVREMAPPER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace spv {
|
||||
|
||||
// MSVC defines __cplusplus as an older value, even when it supports almost all of 11.
|
||||
// We handle that here by making our own symbol.
|
||||
#if __cplusplus >= 201103L || _MSC_VER >= 1700
|
||||
# define use_cpp11 1
|
||||
#endif
|
||||
|
||||
class spirvbin_base_t
|
||||
{
|
||||
public:
|
||||
enum Options {
|
||||
NONE = 0,
|
||||
STRIP = (1<<0),
|
||||
MAP_TYPES = (1<<1),
|
||||
MAP_NAMES = (1<<2),
|
||||
MAP_FUNCS = (1<<3),
|
||||
DCE_FUNCS = (1<<4),
|
||||
DCE_VARS = (1<<5),
|
||||
DCE_TYPES = (1<<6),
|
||||
OPT_LOADSTORE = (1<<7),
|
||||
OPT_FWD_LS = (1<<8), // EXPERIMENTAL: PRODUCES INVALID SCHEMA-0 SPIRV
|
||||
MAP_ALL = (MAP_TYPES | MAP_NAMES | MAP_FUNCS),
|
||||
DCE_ALL = (DCE_FUNCS | DCE_VARS | DCE_TYPES),
|
||||
OPT_ALL = (OPT_LOADSTORE),
|
||||
|
||||
ALL_BUT_STRIP = (MAP_ALL | DCE_ALL | OPT_ALL),
|
||||
DO_EVERYTHING = (STRIP | ALL_BUT_STRIP)
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace SPV
|
||||
|
||||
#if !defined (use_cpp11)
|
||||
#include <stdio.h>
|
||||
|
||||
namespace spv {
|
||||
class spirvbin_t : public spirvbin_base_t
|
||||
{
|
||||
public:
|
||||
spirvbin_t(int /*verbose = 0*/) { }
|
||||
|
||||
void remap(std::vector<unsigned int>& /*spv*/, unsigned int /*opts = 0*/)
|
||||
{
|
||||
printf("Tool not compiled for C++11, which is required for SPIR-V remapping.\n");
|
||||
exit(5);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SPV
|
||||
|
||||
#else // defined (use_cpp11)
|
||||
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
|
||||
#include "spirv.hpp"
|
||||
#include "spvIR.h"
|
||||
|
||||
namespace spv {
|
||||
|
||||
// class to hold SPIR-V binary data for remapping, DCE, and debug stripping
|
||||
class spirvbin_t : public spirvbin_base_t
|
||||
{
|
||||
public:
|
||||
spirvbin_t(int verbose = 0) : entryPoint(spv::NoResult), largestNewId(0), verbose(verbose) { }
|
||||
|
||||
// remap on an existing binary in memory
|
||||
void remap(std::vector<std::uint32_t>& spv, std::uint32_t opts = DO_EVERYTHING);
|
||||
|
||||
// Type for error/log handler functions
|
||||
typedef std::function<void(const std::string&)> errorfn_t;
|
||||
typedef std::function<void(const std::string&)> logfn_t;
|
||||
|
||||
// Register error/log handling functions (can be lambda fn / functor / etc)
|
||||
static void registerErrorHandler(errorfn_t handler) { errorHandler = handler; }
|
||||
static void registerLogHandler(logfn_t handler) { logHandler = handler; }
|
||||
|
||||
protected:
|
||||
// This can be overridden to provide other message behavior if needed
|
||||
virtual void msg(int minVerbosity, int indent, const std::string& txt) const;
|
||||
|
||||
private:
|
||||
// Local to global, or global to local ID map
|
||||
typedef std::unordered_map<spv::Id, spv::Id> idmap_t;
|
||||
typedef std::unordered_set<spv::Id> idset_t;
|
||||
typedef std::unordered_map<spv::Id, int> blockmap_t;
|
||||
|
||||
void remap(std::uint32_t opts = DO_EVERYTHING);
|
||||
|
||||
// Map of names to IDs
|
||||
typedef std::unordered_map<std::string, spv::Id> namemap_t;
|
||||
|
||||
typedef std::uint32_t spirword_t;
|
||||
|
||||
typedef std::pair<unsigned, unsigned> range_t;
|
||||
typedef std::function<void(spv::Id&)> idfn_t;
|
||||
typedef std::function<bool(spv::Op, unsigned start)> instfn_t;
|
||||
|
||||
// Special Values for ID map:
|
||||
static const spv::Id unmapped; // unchanged from default value
|
||||
static const spv::Id unused; // unused ID
|
||||
static const int header_size; // SPIR header = 5 words
|
||||
|
||||
class id_iterator_t;
|
||||
|
||||
// For mapping type entries between different shaders
|
||||
typedef std::vector<spirword_t> typeentry_t;
|
||||
typedef std::map<spv::Id, typeentry_t> globaltypes_t;
|
||||
|
||||
// A set that preserves position order, and a reverse map
|
||||
typedef std::set<int> posmap_t;
|
||||
typedef std::unordered_map<spv::Id, int> posmap_rev_t;
|
||||
|
||||
// handle error
|
||||
void error(const std::string& txt) const { errorHandler(txt); }
|
||||
|
||||
bool isConstOp(spv::Op opCode) const;
|
||||
bool isTypeOp(spv::Op opCode) const;
|
||||
bool isStripOp(spv::Op opCode) const;
|
||||
bool isFlowCtrl(spv::Op opCode) const;
|
||||
range_t literalRange(spv::Op opCode) const;
|
||||
range_t typeRange(spv::Op opCode) const;
|
||||
range_t constRange(spv::Op opCode) const;
|
||||
|
||||
spv::Id& asId(unsigned word) { return spv[word]; }
|
||||
const spv::Id& asId(unsigned word) const { return spv[word]; }
|
||||
spv::Op asOpCode(unsigned word) const { return opOpCode(spv[word]); }
|
||||
std::uint32_t asOpCodeHash(unsigned word);
|
||||
spv::Decoration asDecoration(unsigned word) const { return spv::Decoration(spv[word]); }
|
||||
unsigned asWordCount(unsigned word) const { return opWordCount(spv[word]); }
|
||||
spv::Id asTypeConstId(unsigned word) const { return asId(word + (isTypeOp(asOpCode(word)) ? 1 : 2)); }
|
||||
unsigned typePos(spv::Id id) const;
|
||||
|
||||
static unsigned opWordCount(spirword_t data) { return data >> spv::WordCountShift; }
|
||||
static spv::Op opOpCode(spirword_t data) { return spv::Op(data & spv::OpCodeMask); }
|
||||
|
||||
// Header access & set methods
|
||||
spirword_t magic() const { return spv[0]; } // return magic number
|
||||
spirword_t bound() const { return spv[3]; } // return Id bound from header
|
||||
spirword_t bound(spirword_t b) { return spv[3] = b; };
|
||||
spirword_t genmagic() const { return spv[2]; } // generator magic
|
||||
spirword_t genmagic(spirword_t m) { return spv[2] = m; }
|
||||
spirword_t schemaNum() const { return spv[4]; } // schema number from header
|
||||
|
||||
// Mapping fns: get
|
||||
spv::Id localId(spv::Id id) const { return idMapL[id]; }
|
||||
|
||||
// Mapping fns: set
|
||||
inline spv::Id localId(spv::Id id, spv::Id newId);
|
||||
void countIds(spv::Id id);
|
||||
|
||||
// Return next unused new local ID.
|
||||
// NOTE: boost::dynamic_bitset would be more efficient due to find_next(),
|
||||
// which std::vector<bool> doens't have.
|
||||
inline spv::Id nextUnusedId(spv::Id id);
|
||||
|
||||
void buildLocalMaps();
|
||||
std::string literalString(unsigned word) const; // Return literal as a std::string
|
||||
int literalStringWords(const std::string& str) const { return (int(str.size())+4)/4; }
|
||||
|
||||
bool isNewIdMapped(spv::Id newId) const { return isMapped(newId); }
|
||||
bool isOldIdUnmapped(spv::Id oldId) const { return localId(oldId) == unmapped; }
|
||||
bool isOldIdUnused(spv::Id oldId) const { return localId(oldId) == unused; }
|
||||
bool isOldIdMapped(spv::Id oldId) const { return !isOldIdUnused(oldId) && !isOldIdUnmapped(oldId); }
|
||||
bool isFunction(spv::Id oldId) const { return fnPos.find(oldId) != fnPos.end(); }
|
||||
|
||||
// bool matchType(const globaltypes_t& globalTypes, spv::Id lt, spv::Id gt) const;
|
||||
// spv::Id findType(const globaltypes_t& globalTypes, spv::Id lt) const;
|
||||
std::uint32_t hashType(unsigned typeStart) const;
|
||||
|
||||
spirvbin_t& process(instfn_t, idfn_t, unsigned begin = 0, unsigned end = 0);
|
||||
int processInstruction(unsigned word, instfn_t, idfn_t);
|
||||
|
||||
void validate() const;
|
||||
void mapTypeConst();
|
||||
void mapFnBodies();
|
||||
void optLoadStore();
|
||||
void dceFuncs();
|
||||
void dceVars();
|
||||
void dceTypes();
|
||||
void mapNames();
|
||||
void foldIds(); // fold IDs to smallest space
|
||||
void forwardLoadStores(); // load store forwarding (EXPERIMENTAL)
|
||||
void offsetIds(); // create relative offset IDs
|
||||
|
||||
void applyMap(); // remap per local name map
|
||||
void mapRemainder(); // map any IDs we haven't touched yet
|
||||
void stripDebug(); // strip debug info
|
||||
void strip(); // remove debug symbols
|
||||
|
||||
std::vector<spirword_t> spv; // SPIR words
|
||||
|
||||
namemap_t nameMap; // ID names from OpName
|
||||
|
||||
// Since we want to also do binary ops, we can't use std::vector<bool>. we could use
|
||||
// boost::dynamic_bitset, but we're trying to avoid a boost dependency.
|
||||
typedef std::uint64_t bits_t;
|
||||
std::vector<bits_t> mapped; // which new IDs have been mapped
|
||||
static const int mBits = sizeof(bits_t) * 4;
|
||||
|
||||
bool isMapped(spv::Id id) const { return id < maxMappedId() && ((mapped[id/mBits] & (1LL<<(id%mBits))) != 0); }
|
||||
void setMapped(spv::Id id) { resizeMapped(id); mapped[id/mBits] |= (1LL<<(id%mBits)); }
|
||||
void resizeMapped(spv::Id id) { if (id >= maxMappedId()) mapped.resize(id/mBits+1, 0); }
|
||||
size_t maxMappedId() const { return mapped.size() * mBits; }
|
||||
|
||||
// Add a strip range for a given instruction starting at 'start'
|
||||
// Note: avoiding brace initializers to please older versions os MSVC.
|
||||
void stripInst(unsigned start) { stripRange.push_back(range_t(start, start + asWordCount(start))); }
|
||||
|
||||
// Function start and end. use unordered_map because we'll have
|
||||
// many fewer functions than IDs.
|
||||
std::unordered_map<spv::Id, range_t> fnPos;
|
||||
std::unordered_map<spv::Id, range_t> fnPosDCE; // deleted functions
|
||||
|
||||
// Which functions are called, anywhere in the module, with a call count
|
||||
std::unordered_map<spv::Id, int> fnCalls;
|
||||
|
||||
posmap_t typeConstPos; // word positions that define types & consts (ordered)
|
||||
posmap_rev_t typeConstPosR; // reverse map from IDs to positions
|
||||
|
||||
std::vector<spv::Id> idMapL; // ID {M}ap from {L}ocal to {G}lobal IDs
|
||||
|
||||
spv::Id entryPoint; // module entry point
|
||||
spv::Id largestNewId; // biggest new ID we have mapped anything to
|
||||
|
||||
// Sections of the binary to strip, given as [begin,end)
|
||||
std::vector<range_t> stripRange;
|
||||
|
||||
// processing options:
|
||||
std::uint32_t options;
|
||||
int verbose; // verbosity level
|
||||
|
||||
static errorfn_t errorHandler;
|
||||
static logfn_t logHandler;
|
||||
};
|
||||
|
||||
} // namespace SPV
|
||||
|
||||
#endif // defined (use_cpp11)
|
||||
#endif // SPIRVREMAPPER_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,593 @@
|
|||
//
|
||||
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||
//Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// "Builder" is an interface to fully build SPIR-V IR. Allocate one of
|
||||
// these to build (a thread safe) internal SPIR-V representation (IR),
|
||||
// and then dump it as a binary stream according to the SPIR-V specification.
|
||||
//
|
||||
// A Builder has a 1:1 relationship with a SPIR-V module.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef SpvBuilder_H
|
||||
#define SpvBuilder_H
|
||||
|
||||
#include "Logger.h"
|
||||
#include "spirv.hpp"
|
||||
#include "spvIR.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
|
||||
namespace spv {
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
Builder(unsigned int userNumber, SpvBuildLogger* logger);
|
||||
virtual ~Builder();
|
||||
|
||||
static const int maxMatrixSize = 4;
|
||||
|
||||
void setSource(spv::SourceLanguage lang, int version)
|
||||
{
|
||||
source = lang;
|
||||
sourceVersion = version;
|
||||
}
|
||||
void addSourceExtension(const char* ext) { extensions.push_back(ext); }
|
||||
Id import(const char*);
|
||||
void setMemoryModel(spv::AddressingModel addr, spv::MemoryModel mem)
|
||||
{
|
||||
addressModel = addr;
|
||||
memoryModel = mem;
|
||||
}
|
||||
|
||||
void addCapability(spv::Capability cap) { capabilities.insert(cap); }
|
||||
|
||||
// To get a new <id> for anything needing a new one.
|
||||
Id getUniqueId() { return ++uniqueId; }
|
||||
|
||||
// To get a set of new <id>s, e.g., for a set of function parameters
|
||||
Id getUniqueIds(int numIds)
|
||||
{
|
||||
Id id = uniqueId + 1;
|
||||
uniqueId += numIds;
|
||||
return id;
|
||||
}
|
||||
|
||||
// For creating new types (will return old type if the requested one was already made).
|
||||
Id makeVoidType();
|
||||
Id makeBoolType();
|
||||
Id makePointer(StorageClass, Id type);
|
||||
Id makeIntegerType(int width, bool hasSign); // generic
|
||||
Id makeIntType(int width) { return makeIntegerType(width, true); }
|
||||
Id makeUintType(int width) { return makeIntegerType(width, false); }
|
||||
Id makeFloatType(int width);
|
||||
Id makeStructType(const std::vector<Id>& members, const char*);
|
||||
Id makeStructResultType(Id type0, Id type1);
|
||||
Id makeVectorType(Id component, int size);
|
||||
Id makeMatrixType(Id component, int cols, int rows);
|
||||
Id makeArrayType(Id element, Id sizeId, int stride); // 0 stride means no stride decoration
|
||||
Id makeRuntimeArray(Id element);
|
||||
Id makeFunctionType(Id returnType, const std::vector<Id>& paramTypes);
|
||||
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
|
||||
Id makeSamplerType();
|
||||
Id makeSampledImageType(Id imageType);
|
||||
|
||||
// For querying about types.
|
||||
Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
|
||||
Id getDerefTypeId(Id resultId) const;
|
||||
Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); }
|
||||
Op getTypeClass(Id typeId) const { return getOpCode(typeId); }
|
||||
Op getMostBasicTypeClass(Id typeId) const;
|
||||
int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); }
|
||||
int getNumTypeConstituents(Id typeId) const;
|
||||
int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); }
|
||||
Id getScalarTypeId(Id typeId) const;
|
||||
Id getContainedTypeId(Id typeId) const;
|
||||
Id getContainedTypeId(Id typeId, int) const;
|
||||
StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
|
||||
ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
|
||||
|
||||
bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
|
||||
bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
|
||||
bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
|
||||
bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
|
||||
bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
|
||||
bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
|
||||
|
||||
bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
|
||||
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
|
||||
bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
|
||||
bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
|
||||
bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
|
||||
bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
|
||||
bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
|
||||
bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
|
||||
bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
|
||||
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
|
||||
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
|
||||
|
||||
bool isConstantOpCode(Op opcode) const;
|
||||
bool isSpecConstantOpCode(Op opcode) const;
|
||||
bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
|
||||
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
|
||||
bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
|
||||
unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
|
||||
StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
|
||||
|
||||
int getTypeNumColumns(Id typeId) const
|
||||
{
|
||||
assert(isMatrixType(typeId));
|
||||
return getNumTypeConstituents(typeId);
|
||||
}
|
||||
int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); }
|
||||
int getTypeNumRows(Id typeId) const
|
||||
{
|
||||
assert(isMatrixType(typeId));
|
||||
return getNumTypeComponents(getContainedTypeId(typeId));
|
||||
}
|
||||
int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
|
||||
|
||||
Dim getTypeDimensionality(Id typeId) const
|
||||
{
|
||||
assert(isImageType(typeId));
|
||||
return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
|
||||
}
|
||||
Id getImageType(Id resultId) const
|
||||
{
|
||||
Id typeId = getTypeId(resultId);
|
||||
assert(isImageType(typeId) || isSampledImageType(typeId));
|
||||
return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
|
||||
}
|
||||
bool isArrayedImageType(Id typeId) const
|
||||
{
|
||||
assert(isImageType(typeId));
|
||||
return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
|
||||
}
|
||||
|
||||
// For making new constants (will return old constant if the requested one was already made).
|
||||
Id makeBoolConstant(bool b, bool specConstant = false);
|
||||
Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
|
||||
Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
|
||||
Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
|
||||
Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); }
|
||||
Id makeFloatConstant(float f, bool specConstant = false);
|
||||
Id makeDoubleConstant(double d, bool specConstant = false);
|
||||
|
||||
// Turn the array of constants into a proper spv constant of the requested type.
|
||||
Id makeCompositeConstant(Id type, std::vector<Id>& comps, bool specConst = false);
|
||||
|
||||
// Methods for adding information outside the CFG.
|
||||
Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
|
||||
void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
|
||||
void addName(Id, const char* name);
|
||||
void addMemberName(Id, int member, const char* name);
|
||||
void addLine(Id target, Id fileName, int line, int column);
|
||||
void addDecoration(Id, Decoration, int num = -1);
|
||||
void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1);
|
||||
|
||||
// At the end of what block do the next create*() instructions go?
|
||||
void setBuildPoint(Block* bp) { buildPoint = bp; }
|
||||
Block* getBuildPoint() const { return buildPoint; }
|
||||
|
||||
// Make the entry-point function. The returned pointer is only valid
|
||||
// for the lifetime of this builder.
|
||||
Function* makeEntrypoint(const char*);
|
||||
|
||||
// Make a shader-style function, and create its entry block if entry is non-zero.
|
||||
// Return the function, pass back the entry.
|
||||
// The returned pointer is only valid for the lifetime of this builder.
|
||||
Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes,
|
||||
const std::vector<Decoration>& precisions, Block **entry = 0);
|
||||
|
||||
// Create a return. An 'implicit' return is one not appearing in the source
|
||||
// code. In the case of an implicit return, no post-return block is inserted.
|
||||
void makeReturn(bool implicit, Id retVal = 0);
|
||||
|
||||
// Generate all the code needed to finish up a function.
|
||||
void leaveFunction();
|
||||
|
||||
// Create a discard.
|
||||
void makeDiscard();
|
||||
|
||||
// Create a global or function local or IO variable.
|
||||
Id createVariable(StorageClass, Id type, const char* name = 0);
|
||||
|
||||
// Create an intermediate with an undefined value.
|
||||
Id createUndefined(Id type);
|
||||
|
||||
// Store into an Id and return the l-value
|
||||
void createStore(Id rValue, Id lValue);
|
||||
|
||||
// Load from an Id and return it
|
||||
Id createLoad(Id lValue);
|
||||
|
||||
// Create an OpAccessChain instruction
|
||||
Id createAccessChain(StorageClass, Id base, std::vector<Id>& offsets);
|
||||
|
||||
// Create an OpArrayLength instruction
|
||||
Id createArrayLength(Id base, unsigned int member);
|
||||
|
||||
// Create an OpCompositeExtract instruction
|
||||
Id createCompositeExtract(Id composite, Id typeId, unsigned index);
|
||||
Id createCompositeExtract(Id composite, Id typeId, std::vector<unsigned>& indexes);
|
||||
Id createCompositeInsert(Id object, Id composite, Id typeId, unsigned index);
|
||||
Id createCompositeInsert(Id object, Id composite, Id typeId, std::vector<unsigned>& indexes);
|
||||
|
||||
Id createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex);
|
||||
Id createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex);
|
||||
|
||||
void createNoResultOp(Op);
|
||||
void createNoResultOp(Op, Id operand);
|
||||
void createNoResultOp(Op, const std::vector<Id>& operands);
|
||||
void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
|
||||
void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
|
||||
Id createUnaryOp(Op, Id typeId, Id operand);
|
||||
Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
|
||||
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
|
||||
Id createOp(Op, Id typeId, const std::vector<Id>& operands);
|
||||
Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
|
||||
Id createSpecConstantOp(Op, Id typeId, const std::vector<spv::Id>& operands, const std::vector<unsigned>& literals);
|
||||
|
||||
// Take an rvalue (source) and a set of channels to extract from it to
|
||||
// make a new rvalue, which is returned.
|
||||
Id createRvalueSwizzle(Decoration precision, Id typeId, Id source, std::vector<unsigned>& channels);
|
||||
|
||||
// Take a copy of an lvalue (target) and a source of components, and set the
|
||||
// source components into the lvalue where the 'channels' say to put them.
|
||||
// An updated version of the target is returned.
|
||||
// (No true lvalue or stores are used.)
|
||||
Id createLvalueSwizzle(Id typeId, Id target, Id source, std::vector<unsigned>& channels);
|
||||
|
||||
// If both the id and precision are valid, the id
|
||||
// gets tagged with the requested precision.
|
||||
// The passed in id is always the returned id, to simplify use patterns.
|
||||
Id setPrecision(Id id, Decoration precision)
|
||||
{
|
||||
if (precision != NoPrecision && id != NoResult)
|
||||
addDecoration(id, precision);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// Can smear a scalar to a vector for the following forms:
|
||||
// - promoteScalar(scalar, vector) // smear scalar to width of vector
|
||||
// - promoteScalar(vector, scalar) // smear scalar to width of vector
|
||||
// - promoteScalar(pointer, scalar) // smear scalar to width of what pointer points to
|
||||
// - promoteScalar(scalar, scalar) // do nothing
|
||||
// Other forms are not allowed.
|
||||
//
|
||||
// Generally, the type of 'scalar' does not need to be the same type as the components in 'vector'.
|
||||
// The type of the created vector is a vector of components of the same type as the scalar.
|
||||
//
|
||||
// Note: One of the arguments will change, with the result coming back that way rather than
|
||||
// through the return value.
|
||||
void promoteScalar(Decoration precision, Id& left, Id& right);
|
||||
|
||||
// Make a value by smearing the scalar to fill the type.
|
||||
// vectorType should be the correct type for making a vector of scalarVal.
|
||||
// (No conversions are done.)
|
||||
Id smearScalar(Decoration precision, Id scalarVal, Id vectorType);
|
||||
|
||||
// Create a call to a built-in function.
|
||||
Id createBuiltinCall(Id resultType, Id builtins, int entryPoint, std::vector<Id>& args);
|
||||
|
||||
// List of parameters used to create a texture operation
|
||||
struct TextureParameters {
|
||||
Id sampler;
|
||||
Id coords;
|
||||
Id bias;
|
||||
Id lod;
|
||||
Id Dref;
|
||||
Id offset;
|
||||
Id offsets;
|
||||
Id gradX;
|
||||
Id gradY;
|
||||
Id sample;
|
||||
Id component;
|
||||
Id texelOut;
|
||||
Id lodClamp;
|
||||
};
|
||||
|
||||
// Select the correct texture operation based on all inputs, and emit the correct instruction
|
||||
Id createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicit, const TextureParameters&);
|
||||
|
||||
// Emit the OpTextureQuery* instruction that was passed in.
|
||||
// Figure out the right return value and type, and return it.
|
||||
Id createTextureQueryCall(Op, const TextureParameters&);
|
||||
|
||||
Id createSamplePositionCall(Decoration precision, Id, Id);
|
||||
|
||||
Id createBitFieldExtractCall(Decoration precision, Id, Id, Id, bool isSigned);
|
||||
Id createBitFieldInsertCall(Decoration precision, Id, Id, Id, Id);
|
||||
|
||||
// Reduction comparison for composites: For equal and not-equal resulting in a scalar.
|
||||
Id createCompositeCompare(Decoration precision, Id, Id, bool /* true if for equal, false if for not-equal */);
|
||||
|
||||
// OpCompositeConstruct
|
||||
Id createCompositeConstruct(Id typeId, std::vector<Id>& constituents);
|
||||
|
||||
// vector or scalar constructor
|
||||
Id createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId);
|
||||
|
||||
// matrix constructor
|
||||
Id createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id constructee);
|
||||
|
||||
// Helper to use for building nested control flow with if-then-else.
|
||||
class If {
|
||||
public:
|
||||
If(Id condition, Builder& builder);
|
||||
~If() {}
|
||||
|
||||
void makeBeginElse();
|
||||
void makeEndIf();
|
||||
|
||||
private:
|
||||
If(const If&);
|
||||
If& operator=(If&);
|
||||
|
||||
Builder& builder;
|
||||
Id condition;
|
||||
Function* function;
|
||||
Block* headerBlock;
|
||||
Block* thenBlock;
|
||||
Block* elseBlock;
|
||||
Block* mergeBlock;
|
||||
};
|
||||
|
||||
// Make a switch statement. A switch has 'numSegments' of pieces of code, not containing
|
||||
// any case/default labels, all separated by one or more case/default labels. Each possible
|
||||
// case value v is a jump to the caseValues[v] segment. The defaultSegment is also in this
|
||||
// number space. How to compute the value is given by 'condition', as in switch(condition).
|
||||
//
|
||||
// The SPIR-V Builder will maintain the stack of post-switch merge blocks for nested switches.
|
||||
//
|
||||
// Use a defaultSegment < 0 if there is no default segment (to branch to post switch).
|
||||
//
|
||||
// Returns the right set of basic blocks to start each code segment with, so that the caller's
|
||||
// recursion stack can hold the memory for it.
|
||||
//
|
||||
void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues, std::vector<int>& valueToSegment, int defaultSegment,
|
||||
std::vector<Block*>& segmentBB); // return argument
|
||||
|
||||
// Add a branch to the innermost switch's merge block.
|
||||
void addSwitchBreak();
|
||||
|
||||
// Move to the next code segment, passing in the return argument in makeSwitch()
|
||||
void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
|
||||
|
||||
// Finish off the innermost switch.
|
||||
void endSwitch(std::vector<Block*>& segmentBB);
|
||||
|
||||
struct LoopBlocks {
|
||||
LoopBlocks(Block& head, Block& body, Block& merge, Block& continue_target) :
|
||||
head(head), body(body), merge(merge), continue_target(continue_target) { }
|
||||
Block &head, &body, &merge, &continue_target;
|
||||
private:
|
||||
LoopBlocks();
|
||||
LoopBlocks& operator=(const LoopBlocks&);
|
||||
};
|
||||
|
||||
// Start a new loop and prepare the builder to generate code for it. Until
|
||||
// closeLoop() is called for this loop, createLoopContinue() and
|
||||
// createLoopExit() will target its corresponding blocks.
|
||||
LoopBlocks& makeNewLoop();
|
||||
|
||||
// Create a new block in the function containing the build point. Memory is
|
||||
// owned by the function object.
|
||||
Block& makeNewBlock();
|
||||
|
||||
// Add a branch to the continue_target of the current (innermost) loop.
|
||||
void createLoopContinue();
|
||||
|
||||
// Add an exit (e.g. "break") from the innermost loop that we're currently
|
||||
// in.
|
||||
void createLoopExit();
|
||||
|
||||
// Close the innermost loop that you're in
|
||||
void closeLoop();
|
||||
|
||||
//
|
||||
// Access chain design for an R-Value vs. L-Value:
|
||||
//
|
||||
// There is a single access chain the builder is building at
|
||||
// any particular time. Such a chain can be used to either to a load or
|
||||
// a store, when desired.
|
||||
//
|
||||
// Expressions can be r-values, l-values, or both, or only r-values:
|
||||
// a[b.c].d = .... // l-value
|
||||
// ... = a[b.c].d; // r-value, that also looks like an l-value
|
||||
// ++a[b.c].d; // r-value and l-value
|
||||
// (x + y)[2]; // r-value only, can't possibly be l-value
|
||||
//
|
||||
// Computing an r-value means generating code. Hence,
|
||||
// r-values should only be computed when they are needed, not speculatively.
|
||||
//
|
||||
// Computing an l-value means saving away information for later use in the compiler,
|
||||
// no code is generated until the l-value is later dereferenced. It is okay
|
||||
// to speculatively generate an l-value, just not okay to speculatively dereference it.
|
||||
//
|
||||
// The base of the access chain (the left-most variable or expression
|
||||
// from which everything is based) can be set either as an l-value
|
||||
// or as an r-value. Most efficient would be to set an l-value if one
|
||||
// is available. If an expression was evaluated, the resulting r-value
|
||||
// can be set as the chain base.
|
||||
//
|
||||
// The users of this single access chain can save and restore if they
|
||||
// want to nest or manage multiple chains.
|
||||
//
|
||||
|
||||
struct AccessChain {
|
||||
Id base; // for l-values, pointer to the base object, for r-values, the base object
|
||||
std::vector<Id> indexChain;
|
||||
Id instr; // cache the instruction that generates this access chain
|
||||
std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
|
||||
Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
|
||||
Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
|
||||
bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
|
||||
};
|
||||
|
||||
//
|
||||
// the SPIR-V builder maintains a single active chain that
|
||||
// the following methods operated on
|
||||
//
|
||||
|
||||
// for external save and restore
|
||||
AccessChain getAccessChain() { return accessChain; }
|
||||
void setAccessChain(AccessChain newChain) { accessChain = newChain; }
|
||||
|
||||
// clear accessChain
|
||||
void clearAccessChain();
|
||||
|
||||
// set new base as an l-value base
|
||||
void setAccessChainLValue(Id lValue)
|
||||
{
|
||||
assert(isPointer(lValue));
|
||||
accessChain.base = lValue;
|
||||
}
|
||||
|
||||
// set new base value as an r-value
|
||||
void setAccessChainRValue(Id rValue)
|
||||
{
|
||||
accessChain.isRValue = true;
|
||||
accessChain.base = rValue;
|
||||
}
|
||||
|
||||
// push offset onto the end of the chain
|
||||
void accessChainPush(Id offset)
|
||||
{
|
||||
accessChain.indexChain.push_back(offset);
|
||||
}
|
||||
|
||||
// push new swizzle onto the end of any existing swizzle, merging into a single swizzle
|
||||
void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
|
||||
|
||||
// push a variable component selection onto the access chain; supporting only one, so unsided
|
||||
void accessChainPushComponent(Id component, Id preSwizzleBaseType)
|
||||
{
|
||||
accessChain.component = component;
|
||||
if (accessChain.preSwizzleBaseType == NoType)
|
||||
accessChain.preSwizzleBaseType = preSwizzleBaseType;
|
||||
}
|
||||
|
||||
// use accessChain and swizzle to store value
|
||||
void accessChainStore(Id rvalue);
|
||||
|
||||
// use accessChain and swizzle to load an r-value
|
||||
Id accessChainLoad(Decoration precision, Id ResultType);
|
||||
|
||||
// get the direct pointer for an l-value
|
||||
Id accessChainGetLValue();
|
||||
|
||||
// Get the inferred SPIR-V type of the result of the current access chain,
|
||||
// based on the type of the base and the chain of dereferences.
|
||||
Id accessChainGetInferredType();
|
||||
|
||||
// Remove OpDecorate instructions whose operands are defined in unreachable
|
||||
// blocks.
|
||||
void eliminateDeadDecorations();
|
||||
void dump(std::vector<unsigned int>&) const;
|
||||
|
||||
void createBranch(Block* block);
|
||||
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
|
||||
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
|
||||
|
||||
// Sets to generate opcode for specialization constants.
|
||||
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
|
||||
// Sets to generate opcode for non-specialization constants (normal mode).
|
||||
void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; }
|
||||
// Check if the builder is generating code for spec constants.
|
||||
bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; }
|
||||
|
||||
protected:
|
||||
Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
|
||||
Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant);
|
||||
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
|
||||
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
|
||||
Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
|
||||
Id collapseAccessChain();
|
||||
void transferAccessChainSwizzle(bool dynamic);
|
||||
void simplifyAccessChainSwizzle();
|
||||
void createAndSetNoPredecessorBlock(const char*);
|
||||
void createSelectionMerge(Block* mergeBlock, unsigned int control);
|
||||
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
|
||||
|
||||
SourceLanguage source;
|
||||
int sourceVersion;
|
||||
std::vector<const char*> extensions;
|
||||
AddressingModel addressModel;
|
||||
MemoryModel memoryModel;
|
||||
std::set<spv::Capability> capabilities;
|
||||
int builderNumber;
|
||||
Module module;
|
||||
Block* buildPoint;
|
||||
Id uniqueId;
|
||||
Function* mainFunction;
|
||||
bool generatingOpCodeForSpecConst;
|
||||
AccessChain accessChain;
|
||||
|
||||
// special blocks of instructions for output
|
||||
std::vector<std::unique_ptr<Instruction> > imports;
|
||||
std::vector<std::unique_ptr<Instruction> > entryPoints;
|
||||
std::vector<std::unique_ptr<Instruction> > executionModes;
|
||||
std::vector<std::unique_ptr<Instruction> > names;
|
||||
std::vector<std::unique_ptr<Instruction> > lines;
|
||||
std::vector<std::unique_ptr<Instruction> > decorations;
|
||||
std::vector<std::unique_ptr<Instruction> > constantsTypesGlobals;
|
||||
std::vector<std::unique_ptr<Instruction> > externals;
|
||||
std::vector<std::unique_ptr<Function> > functions;
|
||||
|
||||
// not output, internally used for quick & dirty canonical (unique) creation
|
||||
std::vector<Instruction*> groupedConstants[OpConstant]; // all types appear before OpConstant
|
||||
std::vector<Instruction*> groupedTypes[OpConstant];
|
||||
|
||||
// stack of switches
|
||||
std::stack<Block*> switchMerges;
|
||||
|
||||
// Our loop stack.
|
||||
std::stack<LoopBlocks> loops;
|
||||
|
||||
// The stream for outputing warnings and errors.
|
||||
SpvBuildLogger* logger;
|
||||
}; // end Builder class
|
||||
|
||||
}; // end spv namespace
|
||||
|
||||
#endif // SpvBuilder_H
|
|
@ -0,0 +1,573 @@
|
|||
//
|
||||
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Disassembler for SPIR-V.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <iomanip>
|
||||
#include <stack>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
namespace spv {
|
||||
// Include C-based headers that don't have a namespace
|
||||
#include "GLSL.std.450.h"
|
||||
}
|
||||
const char* GlslStd450DebugNames[spv::GLSLstd450Count];
|
||||
|
||||
#include "disassemble.h"
|
||||
#include "doc.h"
|
||||
|
||||
namespace spv {
|
||||
|
||||
static void Kill(std::ostream& out, const char* message)
|
||||
{
|
||||
out << std::endl << "Disassembly failed: " << message << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// used to identify the extended instruction library imported when printing
|
||||
enum ExtInstSet {
|
||||
GLSL450Inst,
|
||||
OpenCLExtInst,
|
||||
};
|
||||
|
||||
// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
|
||||
class SpirvStream {
|
||||
public:
|
||||
SpirvStream(std::ostream& out, const std::vector<unsigned int>& stream) : out(out), stream(stream), word(0), nextNestedControl(0) { }
|
||||
virtual ~SpirvStream() { }
|
||||
|
||||
void validate();
|
||||
void processInstructions();
|
||||
|
||||
protected:
|
||||
SpirvStream(const SpirvStream&);
|
||||
SpirvStream& operator=(const SpirvStream&);
|
||||
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
|
||||
|
||||
// Output methods
|
||||
void outputIndent();
|
||||
void formatId(Id id, std::stringstream&);
|
||||
void outputResultId(Id id);
|
||||
void outputTypeId(Id id);
|
||||
void outputId(Id id);
|
||||
void outputMask(OperandClass operandClass, unsigned mask);
|
||||
void disassembleImmediates(int numOperands);
|
||||
void disassembleIds(int numOperands);
|
||||
int disassembleString();
|
||||
void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
|
||||
|
||||
// Data
|
||||
std::ostream& out; // where to write the disassembly
|
||||
const std::vector<unsigned int>& stream; // the actual word stream
|
||||
int size; // the size of the word stream
|
||||
int word; // the next word of the stream to read
|
||||
|
||||
// map each <id> to the instruction that created it
|
||||
Id bound;
|
||||
std::vector<unsigned int> idInstruction; // the word offset into the stream where the instruction for result [id] starts; 0 if not yet seen (forward reference or function parameter)
|
||||
|
||||
std::vector<std::string> idDescriptor; // the best text string known for explaining the <id>
|
||||
|
||||
// schema
|
||||
unsigned int schema;
|
||||
|
||||
// stack of structured-merge points
|
||||
std::stack<Id> nestedControl;
|
||||
Id nextNestedControl; // need a slight delay for when we are nested
|
||||
};
|
||||
|
||||
void SpirvStream::validate()
|
||||
{
|
||||
size = (int)stream.size();
|
||||
if (size < 4)
|
||||
Kill(out, "stream is too short");
|
||||
|
||||
// Magic number
|
||||
if (stream[word++] != MagicNumber) {
|
||||
out << "Bad magic number";
|
||||
return;
|
||||
}
|
||||
|
||||
// Version
|
||||
out << "// Module Version " << std::hex << stream[word++] << std::endl;
|
||||
|
||||
// Generator's magic number
|
||||
out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
|
||||
|
||||
// Result <id> bound
|
||||
bound = stream[word++];
|
||||
idInstruction.resize(bound);
|
||||
idDescriptor.resize(bound);
|
||||
out << "// Id's are bound by " << bound << std::endl;
|
||||
out << std::endl;
|
||||
|
||||
// Reserved schema, must be 0 for now
|
||||
schema = stream[word++];
|
||||
if (schema != 0)
|
||||
Kill(out, "bad schema, must be 0");
|
||||
}
|
||||
|
||||
// Loop over all the instructions, in order, processing each.
|
||||
// Boiler plate for each is handled here directly, the rest is dispatched.
|
||||
void SpirvStream::processInstructions()
|
||||
{
|
||||
// Instructions
|
||||
while (word < size) {
|
||||
int instructionStart = word;
|
||||
|
||||
// Instruction wordCount and opcode
|
||||
unsigned int firstWord = stream[word];
|
||||
unsigned wordCount = firstWord >> WordCountShift;
|
||||
Op opCode = (Op)(firstWord & OpCodeMask);
|
||||
int nextInst = word + wordCount;
|
||||
++word;
|
||||
|
||||
// Presence of full instruction
|
||||
if (nextInst > size)
|
||||
Kill(out, "stream instruction terminated too early");
|
||||
|
||||
// Base for computing number of operands; will be updated as more is learned
|
||||
unsigned numOperands = wordCount - 1;
|
||||
|
||||
// Type <id>
|
||||
Id typeId = 0;
|
||||
if (InstructionDesc[opCode].hasType()) {
|
||||
typeId = stream[word++];
|
||||
--numOperands;
|
||||
}
|
||||
|
||||
// Result <id>
|
||||
Id resultId = 0;
|
||||
if (InstructionDesc[opCode].hasResult()) {
|
||||
resultId = stream[word++];
|
||||
--numOperands;
|
||||
|
||||
// save instruction for future reference
|
||||
idInstruction[resultId] = instructionStart;
|
||||
}
|
||||
|
||||
outputResultId(resultId);
|
||||
outputTypeId(typeId);
|
||||
outputIndent();
|
||||
|
||||
// Hand off the Op and all its operands
|
||||
disassembleInstruction(resultId, typeId, opCode, numOperands);
|
||||
if (word != nextInst) {
|
||||
out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart;
|
||||
word = nextInst;
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::outputIndent()
|
||||
{
|
||||
for (int i = 0; i < (int)nestedControl.size(); ++i)
|
||||
out << " ";
|
||||
}
|
||||
|
||||
void SpirvStream::formatId(Id id, std::stringstream& idStream)
|
||||
{
|
||||
if (id >= bound)
|
||||
Kill(out, "Bad <id>");
|
||||
|
||||
if (id != 0) {
|
||||
idStream << id;
|
||||
if (idDescriptor[id].size() > 0)
|
||||
idStream << "(" << idDescriptor[id] << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::outputResultId(Id id)
|
||||
{
|
||||
const int width = 16;
|
||||
std::stringstream idStream;
|
||||
formatId(id, idStream);
|
||||
out << std::setw(width) << std::right << idStream.str();
|
||||
if (id != 0)
|
||||
out << ":";
|
||||
else
|
||||
out << " ";
|
||||
|
||||
if (nestedControl.size() && id == nestedControl.top())
|
||||
nestedControl.pop();
|
||||
}
|
||||
|
||||
void SpirvStream::outputTypeId(Id id)
|
||||
{
|
||||
const int width = 12;
|
||||
std::stringstream idStream;
|
||||
formatId(id, idStream);
|
||||
out << std::setw(width) << std::right << idStream.str() << " ";
|
||||
}
|
||||
|
||||
void SpirvStream::outputId(Id id)
|
||||
{
|
||||
if (id >= bound)
|
||||
Kill(out, "Bad <id>");
|
||||
|
||||
out << id;
|
||||
if (idDescriptor[id].size() > 0)
|
||||
out << "(" << idDescriptor[id] << ")";
|
||||
}
|
||||
|
||||
void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
|
||||
{
|
||||
if (mask == 0)
|
||||
out << "None";
|
||||
else {
|
||||
for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
|
||||
if (mask & (1 << m))
|
||||
out << OperandClassParams[operandClass].getName(m) << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleImmediates(int numOperands)
|
||||
{
|
||||
for (int i = 0; i < numOperands; ++i) {
|
||||
out << stream[word++];
|
||||
if (i < numOperands - 1)
|
||||
out << " ";
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleIds(int numOperands)
|
||||
{
|
||||
for (int i = 0; i < numOperands; ++i) {
|
||||
outputId(stream[word++]);
|
||||
if (i < numOperands - 1)
|
||||
out << " ";
|
||||
}
|
||||
}
|
||||
|
||||
// return the number of operands consumed by the string
|
||||
int SpirvStream::disassembleString()
|
||||
{
|
||||
int startWord = word;
|
||||
|
||||
out << " \"";
|
||||
|
||||
const char* wordString;
|
||||
bool done = false;
|
||||
do {
|
||||
unsigned int content = stream[word];
|
||||
wordString = (const char*)&content;
|
||||
for (int charCount = 0; charCount < 4; ++charCount) {
|
||||
if (*wordString == 0) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
out << *(wordString++);
|
||||
}
|
||||
++word;
|
||||
} while (! done);
|
||||
|
||||
out << "\"";
|
||||
|
||||
return word - startWord;
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
|
||||
{
|
||||
// Process the opcode
|
||||
|
||||
out << (OpcodeString(opCode) + 2); // leave out the "Op"
|
||||
|
||||
if (opCode == OpLoopMerge || opCode == OpSelectionMerge)
|
||||
nextNestedControl = stream[word];
|
||||
else if (opCode == OpBranchConditional || opCode == OpSwitch) {
|
||||
if (nextNestedControl) {
|
||||
nestedControl.push(nextNestedControl);
|
||||
nextNestedControl = 0;
|
||||
}
|
||||
} else if (opCode == OpExtInstImport) {
|
||||
idDescriptor[resultId] = (const char*)(&stream[word]);
|
||||
}
|
||||
else {
|
||||
if (idDescriptor[resultId].size() == 0) {
|
||||
switch (opCode) {
|
||||
case OpTypeInt:
|
||||
idDescriptor[resultId] = "int";
|
||||
break;
|
||||
case OpTypeFloat:
|
||||
idDescriptor[resultId] = "float";
|
||||
break;
|
||||
case OpTypeBool:
|
||||
idDescriptor[resultId] = "bool";
|
||||
break;
|
||||
case OpTypeStruct:
|
||||
idDescriptor[resultId] = "struct";
|
||||
break;
|
||||
case OpTypePointer:
|
||||
idDescriptor[resultId] = "ptr";
|
||||
break;
|
||||
case OpTypeVector:
|
||||
if (idDescriptor[stream[word]].size() > 0)
|
||||
idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1);
|
||||
idDescriptor[resultId].append("vec");
|
||||
switch (stream[word + 1]) {
|
||||
case 2: idDescriptor[resultId].append("2"); break;
|
||||
case 3: idDescriptor[resultId].append("3"); break;
|
||||
case 4: idDescriptor[resultId].append("4"); break;
|
||||
case 8: idDescriptor[resultId].append("8"); break;
|
||||
case 16: idDescriptor[resultId].append("16"); break;
|
||||
case 32: idDescriptor[resultId].append("32"); break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process the operands. Note, a new context-dependent set could be
|
||||
// swapped in mid-traversal.
|
||||
|
||||
// Handle images specially, so can put out helpful strings.
|
||||
if (opCode == OpTypeImage) {
|
||||
out << " ";
|
||||
disassembleIds(1);
|
||||
out << " " << DimensionString((Dim)stream[word++]);
|
||||
out << (stream[word++] != 0 ? " depth" : "");
|
||||
out << (stream[word++] != 0 ? " array" : "");
|
||||
out << (stream[word++] != 0 ? " multi-sampled" : "");
|
||||
switch (stream[word++]) {
|
||||
case 0: out << " runtime"; break;
|
||||
case 1: out << " sampled"; break;
|
||||
case 2: out << " nonsampled"; break;
|
||||
}
|
||||
out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
|
||||
|
||||
if (numOperands == 8) {
|
||||
out << " " << AccessQualifierString(stream[word++]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle all the parameterized operands
|
||||
for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
|
||||
out << " ";
|
||||
OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
|
||||
switch (operandClass) {
|
||||
case OperandId:
|
||||
case OperandScope:
|
||||
case OperandMemorySemantics:
|
||||
disassembleIds(1);
|
||||
--numOperands;
|
||||
// Get names for printing "(XXX)" for readability, *after* this id
|
||||
if (opCode == OpName)
|
||||
idDescriptor[stream[word - 1]] = (const char*)(&stream[word]);
|
||||
break;
|
||||
case OperandVariableIds:
|
||||
disassembleIds(numOperands);
|
||||
return;
|
||||
case OperandImageOperands:
|
||||
outputMask(OperandImageOperands, stream[word++]);
|
||||
--numOperands;
|
||||
disassembleIds(numOperands);
|
||||
return;
|
||||
case OperandOptionalLiteral:
|
||||
case OperandVariableLiterals:
|
||||
if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
|
||||
(opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
|
||||
out << BuiltInString(stream[word++]);
|
||||
--numOperands;
|
||||
++op;
|
||||
}
|
||||
disassembleImmediates(numOperands);
|
||||
return;
|
||||
case OperandVariableIdLiteral:
|
||||
while (numOperands > 0) {
|
||||
out << std::endl;
|
||||
outputResultId(0);
|
||||
outputTypeId(0);
|
||||
outputIndent();
|
||||
out << " Type ";
|
||||
disassembleIds(1);
|
||||
out << ", member ";
|
||||
disassembleImmediates(1);
|
||||
numOperands -= 2;
|
||||
}
|
||||
return;
|
||||
case OperandVariableLiteralId:
|
||||
while (numOperands > 0) {
|
||||
out << std::endl;
|
||||
outputResultId(0);
|
||||
outputTypeId(0);
|
||||
outputIndent();
|
||||
out << " case ";
|
||||
disassembleImmediates(1);
|
||||
out << ": ";
|
||||
disassembleIds(1);
|
||||
numOperands -= 2;
|
||||
}
|
||||
return;
|
||||
case OperandLiteralNumber:
|
||||
disassembleImmediates(1);
|
||||
--numOperands;
|
||||
if (opCode == OpExtInst) {
|
||||
ExtInstSet extInstSet = GLSL450Inst;
|
||||
if (0 == memcmp("OpenCL", (const char*)(idDescriptor[stream[word-2]].c_str()), 6)) {
|
||||
extInstSet = OpenCLExtInst;
|
||||
}
|
||||
unsigned entrypoint = stream[word - 1];
|
||||
if (extInstSet == GLSL450Inst) {
|
||||
if (entrypoint < GLSLstd450Count) {
|
||||
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OperandOptionalLiteralString:
|
||||
case OperandLiteralString:
|
||||
numOperands -= disassembleString();
|
||||
break;
|
||||
default:
|
||||
assert(operandClass >= OperandSource && operandClass < OperandOpcode);
|
||||
|
||||
if (OperandClassParams[operandClass].bitmask)
|
||||
outputMask(operandClass, stream[word++]);
|
||||
else
|
||||
out << OperandClassParams[operandClass].getName(stream[word++]);
|
||||
--numOperands;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void GLSLstd450GetDebugNames(const char** names)
|
||||
{
|
||||
for (int i = 0; i < GLSLstd450Count; ++i)
|
||||
names[i] = "Unknown";
|
||||
|
||||
names[GLSLstd450Round] = "Round";
|
||||
names[GLSLstd450RoundEven] = "RoundEven";
|
||||
names[GLSLstd450Trunc] = "Trunc";
|
||||
names[GLSLstd450FAbs] = "FAbs";
|
||||
names[GLSLstd450SAbs] = "SAbs";
|
||||
names[GLSLstd450FSign] = "FSign";
|
||||
names[GLSLstd450SSign] = "SSign";
|
||||
names[GLSLstd450Floor] = "Floor";
|
||||
names[GLSLstd450Ceil] = "Ceil";
|
||||
names[GLSLstd450Fract] = "Fract";
|
||||
names[GLSLstd450Radians] = "Radians";
|
||||
names[GLSLstd450Degrees] = "Degrees";
|
||||
names[GLSLstd450Sin] = "Sin";
|
||||
names[GLSLstd450Cos] = "Cos";
|
||||
names[GLSLstd450Tan] = "Tan";
|
||||
names[GLSLstd450Asin] = "Asin";
|
||||
names[GLSLstd450Acos] = "Acos";
|
||||
names[GLSLstd450Atan] = "Atan";
|
||||
names[GLSLstd450Sinh] = "Sinh";
|
||||
names[GLSLstd450Cosh] = "Cosh";
|
||||
names[GLSLstd450Tanh] = "Tanh";
|
||||
names[GLSLstd450Asinh] = "Asinh";
|
||||
names[GLSLstd450Acosh] = "Acosh";
|
||||
names[GLSLstd450Atanh] = "Atanh";
|
||||
names[GLSLstd450Atan2] = "Atan2";
|
||||
names[GLSLstd450Pow] = "Pow";
|
||||
names[GLSLstd450Exp] = "Exp";
|
||||
names[GLSLstd450Log] = "Log";
|
||||
names[GLSLstd450Exp2] = "Exp2";
|
||||
names[GLSLstd450Log2] = "Log2";
|
||||
names[GLSLstd450Sqrt] = "Sqrt";
|
||||
names[GLSLstd450InverseSqrt] = "InverseSqrt";
|
||||
names[GLSLstd450Determinant] = "Determinant";
|
||||
names[GLSLstd450MatrixInverse] = "MatrixInverse";
|
||||
names[GLSLstd450Modf] = "Modf";
|
||||
names[GLSLstd450ModfStruct] = "ModfStruct";
|
||||
names[GLSLstd450FMin] = "FMin";
|
||||
names[GLSLstd450SMin] = "SMin";
|
||||
names[GLSLstd450UMin] = "UMin";
|
||||
names[GLSLstd450FMax] = "FMax";
|
||||
names[GLSLstd450SMax] = "SMax";
|
||||
names[GLSLstd450UMax] = "UMax";
|
||||
names[GLSLstd450FClamp] = "FClamp";
|
||||
names[GLSLstd450SClamp] = "SClamp";
|
||||
names[GLSLstd450UClamp] = "UClamp";
|
||||
names[GLSLstd450FMix] = "FMix";
|
||||
names[GLSLstd450Step] = "Step";
|
||||
names[GLSLstd450SmoothStep] = "SmoothStep";
|
||||
names[GLSLstd450Fma] = "Fma";
|
||||
names[GLSLstd450Frexp] = "Frexp";
|
||||
names[GLSLstd450FrexpStruct] = "FrexpStruct";
|
||||
names[GLSLstd450Ldexp] = "Ldexp";
|
||||
names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
|
||||
names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
|
||||
names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
|
||||
names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
|
||||
names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
|
||||
names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
|
||||
names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
|
||||
names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
|
||||
names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
|
||||
names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
|
||||
names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
|
||||
names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
|
||||
names[GLSLstd450Length] = "Length";
|
||||
names[GLSLstd450Distance] = "Distance";
|
||||
names[GLSLstd450Cross] = "Cross";
|
||||
names[GLSLstd450Normalize] = "Normalize";
|
||||
names[GLSLstd450FaceForward] = "FaceForward";
|
||||
names[GLSLstd450Reflect] = "Reflect";
|
||||
names[GLSLstd450Refract] = "Refract";
|
||||
names[GLSLstd450FindILsb] = "FindILsb";
|
||||
names[GLSLstd450FindSMsb] = "FindSMsb";
|
||||
names[GLSLstd450FindUMsb] = "FindUMsb";
|
||||
names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
|
||||
names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
|
||||
names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
|
||||
}
|
||||
|
||||
void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
|
||||
{
|
||||
SpirvStream SpirvStream(out, stream);
|
||||
spv::Parameterize();
|
||||
GLSLstd450GetDebugNames(GlslStd450DebugNames);
|
||||
SpirvStream.validate();
|
||||
SpirvStream.processInstructions();
|
||||
}
|
||||
|
||||
}; // end namespace spv
|
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Disassembler for SPIR-V.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef disassembler_H
|
||||
#define disassembler_H
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
|
||||
|
||||
}; // end namespace spv
|
||||
|
||||
#endif // disassembler_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,260 @@
|
|||
//
|
||||
//Copyright (C) 2014-2015 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Parameterize the SPIR-V enumerants.
|
||||
//
|
||||
|
||||
#include "spirv.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
// Fill in all the parameters
|
||||
void Parameterize();
|
||||
|
||||
// Return the English names of all the enums.
|
||||
const char* SourceString(int);
|
||||
const char* AddressingString(int);
|
||||
const char* MemoryString(int);
|
||||
const char* ExecutionModelString(int);
|
||||
const char* ExecutionModeString(int);
|
||||
const char* StorageClassString(int);
|
||||
const char* DecorationString(int);
|
||||
const char* BuiltInString(int);
|
||||
const char* DimensionString(int);
|
||||
const char* SelectControlString(int);
|
||||
const char* LoopControlString(int);
|
||||
const char* FunctionControlString(int);
|
||||
const char* SamplerAddressingModeString(int);
|
||||
const char* SamplerFilterModeString(int);
|
||||
const char* ImageFormatString(int);
|
||||
const char* ImageChannelOrderString(int);
|
||||
const char* ImageChannelTypeString(int);
|
||||
const char* ImageChannelDataTypeString(int type);
|
||||
const char* ImageOperandsString(int format);
|
||||
const char* ImageOperands(int);
|
||||
const char* FPFastMathString(int);
|
||||
const char* FPRoundingModeString(int);
|
||||
const char* LinkageTypeString(int);
|
||||
const char* FuncParamAttrString(int);
|
||||
const char* AccessQualifierString(int);
|
||||
const char* MemorySemanticsString(int);
|
||||
const char* MemoryAccessString(int);
|
||||
const char* ExecutionScopeString(int);
|
||||
const char* GroupOperationString(int);
|
||||
const char* KernelEnqueueFlagsString(int);
|
||||
const char* KernelProfilingInfoString(int);
|
||||
const char* CapabilityString(int);
|
||||
const char* OpcodeString(int);
|
||||
const char* ScopeString(int mem);
|
||||
|
||||
// For grouping opcodes into subsections
|
||||
enum OpcodeClass {
|
||||
OpClassMisc,
|
||||
OpClassDebug,
|
||||
OpClassAnnotate,
|
||||
OpClassExtension,
|
||||
OpClassMode,
|
||||
OpClassType,
|
||||
OpClassConstant,
|
||||
OpClassMemory,
|
||||
OpClassFunction,
|
||||
OpClassImage,
|
||||
OpClassConvert,
|
||||
OpClassComposite,
|
||||
OpClassArithmetic,
|
||||
OpClassBit,
|
||||
OpClassRelationalLogical,
|
||||
OpClassDerivative,
|
||||
OpClassFlowControl,
|
||||
OpClassAtomic,
|
||||
OpClassPrimitive,
|
||||
OpClassBarrier,
|
||||
OpClassGroup,
|
||||
OpClassDeviceSideEnqueue,
|
||||
OpClassPipe,
|
||||
|
||||
OpClassCount,
|
||||
OpClassMissing // all instructions start out as missing
|
||||
};
|
||||
|
||||
// For parameterizing operands.
|
||||
enum OperandClass {
|
||||
OperandNone,
|
||||
OperandId,
|
||||
OperandVariableIds,
|
||||
OperandOptionalLiteral,
|
||||
OperandOptionalLiteralString,
|
||||
OperandVariableLiterals,
|
||||
OperandVariableIdLiteral,
|
||||
OperandVariableLiteralId,
|
||||
OperandLiteralNumber,
|
||||
OperandLiteralString,
|
||||
OperandSource,
|
||||
OperandExecutionModel,
|
||||
OperandAddressing,
|
||||
OperandMemory,
|
||||
OperandExecutionMode,
|
||||
OperandStorage,
|
||||
OperandDimensionality,
|
||||
OperandSamplerAddressingMode,
|
||||
OperandSamplerFilterMode,
|
||||
OperandSamplerImageFormat,
|
||||
OperandImageChannelOrder,
|
||||
OperandImageChannelDataType,
|
||||
OperandImageOperands,
|
||||
OperandFPFastMath,
|
||||
OperandFPRoundingMode,
|
||||
OperandLinkageType,
|
||||
OperandAccessQualifier,
|
||||
OperandFuncParamAttr,
|
||||
OperandDecoration,
|
||||
OperandBuiltIn,
|
||||
OperandSelect,
|
||||
OperandLoop,
|
||||
OperandFunction,
|
||||
OperandMemorySemantics,
|
||||
OperandMemoryAccess,
|
||||
OperandScope,
|
||||
OperandGroupOperation,
|
||||
OperandKernelEnqueueFlags,
|
||||
OperandKernelProfilingInfo,
|
||||
OperandCapability,
|
||||
|
||||
OperandOpcode,
|
||||
|
||||
OperandCount
|
||||
};
|
||||
|
||||
// Any specific enum can have a set of capabilities that allow it:
|
||||
typedef std::vector<Capability> EnumCaps;
|
||||
|
||||
// Parameterize a set of operands with their OperandClass(es) and descriptions.
|
||||
class OperandParameters {
|
||||
public:
|
||||
OperandParameters() { }
|
||||
void push(OperandClass oc, const char* d, bool opt = false)
|
||||
{
|
||||
opClass.push_back(oc);
|
||||
desc.push_back(d);
|
||||
optional.push_back(opt);
|
||||
}
|
||||
void setOptional();
|
||||
OperandClass getClass(int op) const { return opClass[op]; }
|
||||
const char* getDesc(int op) const { return desc[op]; }
|
||||
bool isOptional(int op) const { return optional[op]; }
|
||||
int getNum() const { return (int)opClass.size(); }
|
||||
|
||||
protected:
|
||||
std::vector<OperandClass> opClass;
|
||||
std::vector<const char*> desc;
|
||||
std::vector<bool> optional;
|
||||
};
|
||||
|
||||
// Parameterize an enumerant
|
||||
class EnumParameters {
|
||||
public:
|
||||
EnumParameters() : desc(0) { }
|
||||
EnumCaps caps;
|
||||
const char* desc;
|
||||
};
|
||||
|
||||
// Parameterize a set of enumerants that form an enum
|
||||
class EnumDefinition : public EnumParameters {
|
||||
public:
|
||||
EnumDefinition() :
|
||||
ceiling(0), bitmask(false), getName(0), enumParams(0), operandParams(0) { }
|
||||
void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false)
|
||||
{
|
||||
ceiling = ceil;
|
||||
getName = name;
|
||||
bitmask = mask;
|
||||
enumParams = ep;
|
||||
}
|
||||
void setOperands(OperandParameters* op) { operandParams = op; }
|
||||
int ceiling; // ceiling of enumerants
|
||||
bool bitmask; // true if these enumerants combine into a bitmask
|
||||
const char* (*getName)(int); // a function that returns the name for each enumerant value (or shift)
|
||||
EnumParameters* enumParams; // parameters for each individual enumerant
|
||||
OperandParameters* operandParams; // sets of operands
|
||||
};
|
||||
|
||||
// Parameterize an instruction's logical format, including its known set of operands,
|
||||
// per OperandParameters above.
|
||||
class InstructionParameters {
|
||||
public:
|
||||
InstructionParameters() :
|
||||
opDesc("TBD"),
|
||||
opClass(OpClassMissing),
|
||||
typePresent(true), // most normal, only exceptions have to be spelled out
|
||||
resultPresent(true) // most normal, only exceptions have to be spelled out
|
||||
{ }
|
||||
|
||||
void setResultAndType(bool r, bool t)
|
||||
{
|
||||
resultPresent = r;
|
||||
typePresent = t;
|
||||
}
|
||||
|
||||
bool hasResult() const { return resultPresent != 0; }
|
||||
bool hasType() const { return typePresent != 0; }
|
||||
|
||||
const char* opDesc;
|
||||
EnumCaps capabilities;
|
||||
OpcodeClass opClass;
|
||||
OperandParameters operands;
|
||||
|
||||
protected:
|
||||
int typePresent : 1;
|
||||
int resultPresent : 1;
|
||||
};
|
||||
|
||||
const int OpcodeCeiling = 321;
|
||||
|
||||
// The set of objects that hold all the instruction/operand
|
||||
// parameterization information.
|
||||
extern InstructionParameters InstructionDesc[];
|
||||
|
||||
// These hold definitions of the enumerants used for operands
|
||||
extern EnumDefinition OperandClassParams[];
|
||||
|
||||
const char* GetOperandDesc(OperandClass operand);
|
||||
void PrintImmediateRow(int imm, const char* name, const EnumParameters* enumParams, bool caps, bool hex = false);
|
||||
const char* AccessQualifierString(int attr);
|
||||
|
||||
void PrintOperands(const OperandParameters& operands, int reservedOperands);
|
||||
|
||||
}; // end namespace spv
|
|
@ -0,0 +1,913 @@
|
|||
// Copyright (c) 2014-2016 The Khronos Group 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 and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
|
||||
// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
|
||||
// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This header is automatically generated by the same tool that creates
|
||||
// the Binary Section of the SPIR-V specification.
|
||||
|
||||
// Enumeration tokens for SPIR-V, in various styles:
|
||||
// C, C++, C++11, JSON, Lua, Python
|
||||
//
|
||||
// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL
|
||||
// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL
|
||||
// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL
|
||||
// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL
|
||||
// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']
|
||||
//
|
||||
// Some tokens act like mask values, which can be OR'd together,
|
||||
// while others are mutually exclusive. The mask-like ones have
|
||||
// "Mask" in their name, and a parallel enum that has the shift
|
||||
// amount (1 << x) for each corresponding enumerant.
|
||||
|
||||
#ifndef spirv_HPP
|
||||
#define spirv_HPP
|
||||
|
||||
namespace spv {
|
||||
|
||||
typedef unsigned int Id;
|
||||
|
||||
#define SPV_VERSION 0x10000
|
||||
#define SPV_REVISION 6
|
||||
|
||||
static const unsigned int MagicNumber = 0x07230203;
|
||||
static const unsigned int Version = 0x00010000;
|
||||
static const unsigned int Revision = 6;
|
||||
static const unsigned int OpCodeMask = 0xffff;
|
||||
static const unsigned int WordCountShift = 16;
|
||||
|
||||
enum SourceLanguage {
|
||||
SourceLanguageUnknown = 0,
|
||||
SourceLanguageESSL = 1,
|
||||
SourceLanguageGLSL = 2,
|
||||
SourceLanguageOpenCL_C = 3,
|
||||
SourceLanguageOpenCL_CPP = 4,
|
||||
SourceLanguageHLSL = 5,
|
||||
SourceLanguageMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum ExecutionModel {
|
||||
ExecutionModelVertex = 0,
|
||||
ExecutionModelTessellationControl = 1,
|
||||
ExecutionModelTessellationEvaluation = 2,
|
||||
ExecutionModelGeometry = 3,
|
||||
ExecutionModelFragment = 4,
|
||||
ExecutionModelGLCompute = 5,
|
||||
ExecutionModelKernel = 6,
|
||||
ExecutionModelMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum AddressingModel {
|
||||
AddressingModelLogical = 0,
|
||||
AddressingModelPhysical32 = 1,
|
||||
AddressingModelPhysical64 = 2,
|
||||
AddressingModelMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum MemoryModel {
|
||||
MemoryModelSimple = 0,
|
||||
MemoryModelGLSL450 = 1,
|
||||
MemoryModelOpenCL = 2,
|
||||
MemoryModelMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum ExecutionMode {
|
||||
ExecutionModeInvocations = 0,
|
||||
ExecutionModeSpacingEqual = 1,
|
||||
ExecutionModeSpacingFractionalEven = 2,
|
||||
ExecutionModeSpacingFractionalOdd = 3,
|
||||
ExecutionModeVertexOrderCw = 4,
|
||||
ExecutionModeVertexOrderCcw = 5,
|
||||
ExecutionModePixelCenterInteger = 6,
|
||||
ExecutionModeOriginUpperLeft = 7,
|
||||
ExecutionModeOriginLowerLeft = 8,
|
||||
ExecutionModeEarlyFragmentTests = 9,
|
||||
ExecutionModePointMode = 10,
|
||||
ExecutionModeXfb = 11,
|
||||
ExecutionModeDepthReplacing = 12,
|
||||
ExecutionModeDepthGreater = 14,
|
||||
ExecutionModeDepthLess = 15,
|
||||
ExecutionModeDepthUnchanged = 16,
|
||||
ExecutionModeLocalSize = 17,
|
||||
ExecutionModeLocalSizeHint = 18,
|
||||
ExecutionModeInputPoints = 19,
|
||||
ExecutionModeInputLines = 20,
|
||||
ExecutionModeInputLinesAdjacency = 21,
|
||||
ExecutionModeTriangles = 22,
|
||||
ExecutionModeInputTrianglesAdjacency = 23,
|
||||
ExecutionModeQuads = 24,
|
||||
ExecutionModeIsolines = 25,
|
||||
ExecutionModeOutputVertices = 26,
|
||||
ExecutionModeOutputPoints = 27,
|
||||
ExecutionModeOutputLineStrip = 28,
|
||||
ExecutionModeOutputTriangleStrip = 29,
|
||||
ExecutionModeVecTypeHint = 30,
|
||||
ExecutionModeContractionOff = 31,
|
||||
ExecutionModeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum StorageClass {
|
||||
StorageClassUniformConstant = 0,
|
||||
StorageClassInput = 1,
|
||||
StorageClassUniform = 2,
|
||||
StorageClassOutput = 3,
|
||||
StorageClassWorkgroup = 4,
|
||||
StorageClassCrossWorkgroup = 5,
|
||||
StorageClassPrivate = 6,
|
||||
StorageClassFunction = 7,
|
||||
StorageClassGeneric = 8,
|
||||
StorageClassPushConstant = 9,
|
||||
StorageClassAtomicCounter = 10,
|
||||
StorageClassImage = 11,
|
||||
StorageClassMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum Dim {
|
||||
Dim1D = 0,
|
||||
Dim2D = 1,
|
||||
Dim3D = 2,
|
||||
DimCube = 3,
|
||||
DimRect = 4,
|
||||
DimBuffer = 5,
|
||||
DimSubpassData = 6,
|
||||
DimMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum SamplerAddressingMode {
|
||||
SamplerAddressingModeNone = 0,
|
||||
SamplerAddressingModeClampToEdge = 1,
|
||||
SamplerAddressingModeClamp = 2,
|
||||
SamplerAddressingModeRepeat = 3,
|
||||
SamplerAddressingModeRepeatMirrored = 4,
|
||||
SamplerAddressingModeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum SamplerFilterMode {
|
||||
SamplerFilterModeNearest = 0,
|
||||
SamplerFilterModeLinear = 1,
|
||||
SamplerFilterModeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum ImageFormat {
|
||||
ImageFormatUnknown = 0,
|
||||
ImageFormatRgba32f = 1,
|
||||
ImageFormatRgba16f = 2,
|
||||
ImageFormatR32f = 3,
|
||||
ImageFormatRgba8 = 4,
|
||||
ImageFormatRgba8Snorm = 5,
|
||||
ImageFormatRg32f = 6,
|
||||
ImageFormatRg16f = 7,
|
||||
ImageFormatR11fG11fB10f = 8,
|
||||
ImageFormatR16f = 9,
|
||||
ImageFormatRgba16 = 10,
|
||||
ImageFormatRgb10A2 = 11,
|
||||
ImageFormatRg16 = 12,
|
||||
ImageFormatRg8 = 13,
|
||||
ImageFormatR16 = 14,
|
||||
ImageFormatR8 = 15,
|
||||
ImageFormatRgba16Snorm = 16,
|
||||
ImageFormatRg16Snorm = 17,
|
||||
ImageFormatRg8Snorm = 18,
|
||||
ImageFormatR16Snorm = 19,
|
||||
ImageFormatR8Snorm = 20,
|
||||
ImageFormatRgba32i = 21,
|
||||
ImageFormatRgba16i = 22,
|
||||
ImageFormatRgba8i = 23,
|
||||
ImageFormatR32i = 24,
|
||||
ImageFormatRg32i = 25,
|
||||
ImageFormatRg16i = 26,
|
||||
ImageFormatRg8i = 27,
|
||||
ImageFormatR16i = 28,
|
||||
ImageFormatR8i = 29,
|
||||
ImageFormatRgba32ui = 30,
|
||||
ImageFormatRgba16ui = 31,
|
||||
ImageFormatRgba8ui = 32,
|
||||
ImageFormatR32ui = 33,
|
||||
ImageFormatRgb10a2ui = 34,
|
||||
ImageFormatRg32ui = 35,
|
||||
ImageFormatRg16ui = 36,
|
||||
ImageFormatRg8ui = 37,
|
||||
ImageFormatR16ui = 38,
|
||||
ImageFormatR8ui = 39,
|
||||
ImageFormatMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum ImageChannelOrder {
|
||||
ImageChannelOrderR = 0,
|
||||
ImageChannelOrderA = 1,
|
||||
ImageChannelOrderRG = 2,
|
||||
ImageChannelOrderRA = 3,
|
||||
ImageChannelOrderRGB = 4,
|
||||
ImageChannelOrderRGBA = 5,
|
||||
ImageChannelOrderBGRA = 6,
|
||||
ImageChannelOrderARGB = 7,
|
||||
ImageChannelOrderIntensity = 8,
|
||||
ImageChannelOrderLuminance = 9,
|
||||
ImageChannelOrderRx = 10,
|
||||
ImageChannelOrderRGx = 11,
|
||||
ImageChannelOrderRGBx = 12,
|
||||
ImageChannelOrderDepth = 13,
|
||||
ImageChannelOrderDepthStencil = 14,
|
||||
ImageChannelOrdersRGB = 15,
|
||||
ImageChannelOrdersRGBx = 16,
|
||||
ImageChannelOrdersRGBA = 17,
|
||||
ImageChannelOrdersBGRA = 18,
|
||||
ImageChannelOrderABGR = 19,
|
||||
ImageChannelOrderMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum ImageChannelDataType {
|
||||
ImageChannelDataTypeSnormInt8 = 0,
|
||||
ImageChannelDataTypeSnormInt16 = 1,
|
||||
ImageChannelDataTypeUnormInt8 = 2,
|
||||
ImageChannelDataTypeUnormInt16 = 3,
|
||||
ImageChannelDataTypeUnormShort565 = 4,
|
||||
ImageChannelDataTypeUnormShort555 = 5,
|
||||
ImageChannelDataTypeUnormInt101010 = 6,
|
||||
ImageChannelDataTypeSignedInt8 = 7,
|
||||
ImageChannelDataTypeSignedInt16 = 8,
|
||||
ImageChannelDataTypeSignedInt32 = 9,
|
||||
ImageChannelDataTypeUnsignedInt8 = 10,
|
||||
ImageChannelDataTypeUnsignedInt16 = 11,
|
||||
ImageChannelDataTypeUnsignedInt32 = 12,
|
||||
ImageChannelDataTypeHalfFloat = 13,
|
||||
ImageChannelDataTypeFloat = 14,
|
||||
ImageChannelDataTypeUnormInt24 = 15,
|
||||
ImageChannelDataTypeUnormInt101010_2 = 16,
|
||||
ImageChannelDataTypeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum ImageOperandsShift {
|
||||
ImageOperandsBiasShift = 0,
|
||||
ImageOperandsLodShift = 1,
|
||||
ImageOperandsGradShift = 2,
|
||||
ImageOperandsConstOffsetShift = 3,
|
||||
ImageOperandsOffsetShift = 4,
|
||||
ImageOperandsConstOffsetsShift = 5,
|
||||
ImageOperandsSampleShift = 6,
|
||||
ImageOperandsMinLodShift = 7,
|
||||
ImageOperandsMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum ImageOperandsMask {
|
||||
ImageOperandsMaskNone = 0,
|
||||
ImageOperandsBiasMask = 0x00000001,
|
||||
ImageOperandsLodMask = 0x00000002,
|
||||
ImageOperandsGradMask = 0x00000004,
|
||||
ImageOperandsConstOffsetMask = 0x00000008,
|
||||
ImageOperandsOffsetMask = 0x00000010,
|
||||
ImageOperandsConstOffsetsMask = 0x00000020,
|
||||
ImageOperandsSampleMask = 0x00000040,
|
||||
ImageOperandsMinLodMask = 0x00000080,
|
||||
};
|
||||
|
||||
enum FPFastMathModeShift {
|
||||
FPFastMathModeNotNaNShift = 0,
|
||||
FPFastMathModeNotInfShift = 1,
|
||||
FPFastMathModeNSZShift = 2,
|
||||
FPFastMathModeAllowRecipShift = 3,
|
||||
FPFastMathModeFastShift = 4,
|
||||
FPFastMathModeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum FPFastMathModeMask {
|
||||
FPFastMathModeMaskNone = 0,
|
||||
FPFastMathModeNotNaNMask = 0x00000001,
|
||||
FPFastMathModeNotInfMask = 0x00000002,
|
||||
FPFastMathModeNSZMask = 0x00000004,
|
||||
FPFastMathModeAllowRecipMask = 0x00000008,
|
||||
FPFastMathModeFastMask = 0x00000010,
|
||||
};
|
||||
|
||||
enum FPRoundingMode {
|
||||
FPRoundingModeRTE = 0,
|
||||
FPRoundingModeRTZ = 1,
|
||||
FPRoundingModeRTP = 2,
|
||||
FPRoundingModeRTN = 3,
|
||||
FPRoundingModeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum LinkageType {
|
||||
LinkageTypeExport = 0,
|
||||
LinkageTypeImport = 1,
|
||||
LinkageTypeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum AccessQualifier {
|
||||
AccessQualifierReadOnly = 0,
|
||||
AccessQualifierWriteOnly = 1,
|
||||
AccessQualifierReadWrite = 2,
|
||||
AccessQualifierMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum FunctionParameterAttribute {
|
||||
FunctionParameterAttributeZext = 0,
|
||||
FunctionParameterAttributeSext = 1,
|
||||
FunctionParameterAttributeByVal = 2,
|
||||
FunctionParameterAttributeSret = 3,
|
||||
FunctionParameterAttributeNoAlias = 4,
|
||||
FunctionParameterAttributeNoCapture = 5,
|
||||
FunctionParameterAttributeNoWrite = 6,
|
||||
FunctionParameterAttributeNoReadWrite = 7,
|
||||
FunctionParameterAttributeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum Decoration {
|
||||
DecorationRelaxedPrecision = 0,
|
||||
DecorationSpecId = 1,
|
||||
DecorationBlock = 2,
|
||||
DecorationBufferBlock = 3,
|
||||
DecorationRowMajor = 4,
|
||||
DecorationColMajor = 5,
|
||||
DecorationArrayStride = 6,
|
||||
DecorationMatrixStride = 7,
|
||||
DecorationGLSLShared = 8,
|
||||
DecorationGLSLPacked = 9,
|
||||
DecorationCPacked = 10,
|
||||
DecorationBuiltIn = 11,
|
||||
DecorationNoPerspective = 13,
|
||||
DecorationFlat = 14,
|
||||
DecorationPatch = 15,
|
||||
DecorationCentroid = 16,
|
||||
DecorationSample = 17,
|
||||
DecorationInvariant = 18,
|
||||
DecorationRestrict = 19,
|
||||
DecorationAliased = 20,
|
||||
DecorationVolatile = 21,
|
||||
DecorationConstant = 22,
|
||||
DecorationCoherent = 23,
|
||||
DecorationNonWritable = 24,
|
||||
DecorationNonReadable = 25,
|
||||
DecorationUniform = 26,
|
||||
DecorationSaturatedConversion = 28,
|
||||
DecorationStream = 29,
|
||||
DecorationLocation = 30,
|
||||
DecorationComponent = 31,
|
||||
DecorationIndex = 32,
|
||||
DecorationBinding = 33,
|
||||
DecorationDescriptorSet = 34,
|
||||
DecorationOffset = 35,
|
||||
DecorationXfbBuffer = 36,
|
||||
DecorationXfbStride = 37,
|
||||
DecorationFuncParamAttr = 38,
|
||||
DecorationFPRoundingMode = 39,
|
||||
DecorationFPFastMathMode = 40,
|
||||
DecorationLinkageAttributes = 41,
|
||||
DecorationNoContraction = 42,
|
||||
DecorationInputAttachmentIndex = 43,
|
||||
DecorationAlignment = 44,
|
||||
DecorationMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum BuiltIn {
|
||||
BuiltInPosition = 0,
|
||||
BuiltInPointSize = 1,
|
||||
BuiltInClipDistance = 3,
|
||||
BuiltInCullDistance = 4,
|
||||
BuiltInVertexId = 5,
|
||||
BuiltInInstanceId = 6,
|
||||
BuiltInPrimitiveId = 7,
|
||||
BuiltInInvocationId = 8,
|
||||
BuiltInLayer = 9,
|
||||
BuiltInViewportIndex = 10,
|
||||
BuiltInTessLevelOuter = 11,
|
||||
BuiltInTessLevelInner = 12,
|
||||
BuiltInTessCoord = 13,
|
||||
BuiltInPatchVertices = 14,
|
||||
BuiltInFragCoord = 15,
|
||||
BuiltInPointCoord = 16,
|
||||
BuiltInFrontFacing = 17,
|
||||
BuiltInSampleId = 18,
|
||||
BuiltInSamplePosition = 19,
|
||||
BuiltInSampleMask = 20,
|
||||
BuiltInFragDepth = 22,
|
||||
BuiltInHelperInvocation = 23,
|
||||
BuiltInNumWorkgroups = 24,
|
||||
BuiltInWorkgroupSize = 25,
|
||||
BuiltInWorkgroupId = 26,
|
||||
BuiltInLocalInvocationId = 27,
|
||||
BuiltInGlobalInvocationId = 28,
|
||||
BuiltInLocalInvocationIndex = 29,
|
||||
BuiltInWorkDim = 30,
|
||||
BuiltInGlobalSize = 31,
|
||||
BuiltInEnqueuedWorkgroupSize = 32,
|
||||
BuiltInGlobalOffset = 33,
|
||||
BuiltInGlobalLinearId = 34,
|
||||
BuiltInSubgroupSize = 36,
|
||||
BuiltInSubgroupMaxSize = 37,
|
||||
BuiltInNumSubgroups = 38,
|
||||
BuiltInNumEnqueuedSubgroups = 39,
|
||||
BuiltInSubgroupId = 40,
|
||||
BuiltInSubgroupLocalInvocationId = 41,
|
||||
BuiltInVertexIndex = 42,
|
||||
BuiltInInstanceIndex = 43,
|
||||
BuiltInMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum SelectionControlShift {
|
||||
SelectionControlFlattenShift = 0,
|
||||
SelectionControlDontFlattenShift = 1,
|
||||
SelectionControlMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum SelectionControlMask {
|
||||
SelectionControlMaskNone = 0,
|
||||
SelectionControlFlattenMask = 0x00000001,
|
||||
SelectionControlDontFlattenMask = 0x00000002,
|
||||
};
|
||||
|
||||
enum LoopControlShift {
|
||||
LoopControlUnrollShift = 0,
|
||||
LoopControlDontUnrollShift = 1,
|
||||
LoopControlMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum LoopControlMask {
|
||||
LoopControlMaskNone = 0,
|
||||
LoopControlUnrollMask = 0x00000001,
|
||||
LoopControlDontUnrollMask = 0x00000002,
|
||||
};
|
||||
|
||||
enum FunctionControlShift {
|
||||
FunctionControlInlineShift = 0,
|
||||
FunctionControlDontInlineShift = 1,
|
||||
FunctionControlPureShift = 2,
|
||||
FunctionControlConstShift = 3,
|
||||
FunctionControlMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum FunctionControlMask {
|
||||
FunctionControlMaskNone = 0,
|
||||
FunctionControlInlineMask = 0x00000001,
|
||||
FunctionControlDontInlineMask = 0x00000002,
|
||||
FunctionControlPureMask = 0x00000004,
|
||||
FunctionControlConstMask = 0x00000008,
|
||||
};
|
||||
|
||||
enum MemorySemanticsShift {
|
||||
MemorySemanticsAcquireShift = 1,
|
||||
MemorySemanticsReleaseShift = 2,
|
||||
MemorySemanticsAcquireReleaseShift = 3,
|
||||
MemorySemanticsSequentiallyConsistentShift = 4,
|
||||
MemorySemanticsUniformMemoryShift = 6,
|
||||
MemorySemanticsSubgroupMemoryShift = 7,
|
||||
MemorySemanticsWorkgroupMemoryShift = 8,
|
||||
MemorySemanticsCrossWorkgroupMemoryShift = 9,
|
||||
MemorySemanticsAtomicCounterMemoryShift = 10,
|
||||
MemorySemanticsImageMemoryShift = 11,
|
||||
MemorySemanticsMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum MemorySemanticsMask {
|
||||
MemorySemanticsMaskNone = 0,
|
||||
MemorySemanticsAcquireMask = 0x00000002,
|
||||
MemorySemanticsReleaseMask = 0x00000004,
|
||||
MemorySemanticsAcquireReleaseMask = 0x00000008,
|
||||
MemorySemanticsSequentiallyConsistentMask = 0x00000010,
|
||||
MemorySemanticsUniformMemoryMask = 0x00000040,
|
||||
MemorySemanticsSubgroupMemoryMask = 0x00000080,
|
||||
MemorySemanticsWorkgroupMemoryMask = 0x00000100,
|
||||
MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200,
|
||||
MemorySemanticsAtomicCounterMemoryMask = 0x00000400,
|
||||
MemorySemanticsImageMemoryMask = 0x00000800,
|
||||
};
|
||||
|
||||
enum MemoryAccessShift {
|
||||
MemoryAccessVolatileShift = 0,
|
||||
MemoryAccessAlignedShift = 1,
|
||||
MemoryAccessNontemporalShift = 2,
|
||||
MemoryAccessMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum MemoryAccessMask {
|
||||
MemoryAccessMaskNone = 0,
|
||||
MemoryAccessVolatileMask = 0x00000001,
|
||||
MemoryAccessAlignedMask = 0x00000002,
|
||||
MemoryAccessNontemporalMask = 0x00000004,
|
||||
};
|
||||
|
||||
enum Scope {
|
||||
ScopeCrossDevice = 0,
|
||||
ScopeDevice = 1,
|
||||
ScopeWorkgroup = 2,
|
||||
ScopeSubgroup = 3,
|
||||
ScopeInvocation = 4,
|
||||
ScopeMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum GroupOperation {
|
||||
GroupOperationReduce = 0,
|
||||
GroupOperationInclusiveScan = 1,
|
||||
GroupOperationExclusiveScan = 2,
|
||||
GroupOperationMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum KernelEnqueueFlags {
|
||||
KernelEnqueueFlagsNoWait = 0,
|
||||
KernelEnqueueFlagsWaitKernel = 1,
|
||||
KernelEnqueueFlagsWaitWorkGroup = 2,
|
||||
KernelEnqueueFlagsMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum KernelProfilingInfoShift {
|
||||
KernelProfilingInfoCmdExecTimeShift = 0,
|
||||
KernelProfilingInfoMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum KernelProfilingInfoMask {
|
||||
KernelProfilingInfoMaskNone = 0,
|
||||
KernelProfilingInfoCmdExecTimeMask = 0x00000001,
|
||||
};
|
||||
|
||||
enum Capability {
|
||||
CapabilityMatrix = 0,
|
||||
CapabilityShader = 1,
|
||||
CapabilityGeometry = 2,
|
||||
CapabilityTessellation = 3,
|
||||
CapabilityAddresses = 4,
|
||||
CapabilityLinkage = 5,
|
||||
CapabilityKernel = 6,
|
||||
CapabilityVector16 = 7,
|
||||
CapabilityFloat16Buffer = 8,
|
||||
CapabilityFloat16 = 9,
|
||||
CapabilityFloat64 = 10,
|
||||
CapabilityInt64 = 11,
|
||||
CapabilityInt64Atomics = 12,
|
||||
CapabilityImageBasic = 13,
|
||||
CapabilityImageReadWrite = 14,
|
||||
CapabilityImageMipmap = 15,
|
||||
CapabilityPipes = 17,
|
||||
CapabilityGroups = 18,
|
||||
CapabilityDeviceEnqueue = 19,
|
||||
CapabilityLiteralSampler = 20,
|
||||
CapabilityAtomicStorage = 21,
|
||||
CapabilityInt16 = 22,
|
||||
CapabilityTessellationPointSize = 23,
|
||||
CapabilityGeometryPointSize = 24,
|
||||
CapabilityImageGatherExtended = 25,
|
||||
CapabilityStorageImageMultisample = 27,
|
||||
CapabilityUniformBufferArrayDynamicIndexing = 28,
|
||||
CapabilitySampledImageArrayDynamicIndexing = 29,
|
||||
CapabilityStorageBufferArrayDynamicIndexing = 30,
|
||||
CapabilityStorageImageArrayDynamicIndexing = 31,
|
||||
CapabilityClipDistance = 32,
|
||||
CapabilityCullDistance = 33,
|
||||
CapabilityImageCubeArray = 34,
|
||||
CapabilitySampleRateShading = 35,
|
||||
CapabilityImageRect = 36,
|
||||
CapabilitySampledRect = 37,
|
||||
CapabilityGenericPointer = 38,
|
||||
CapabilityInt8 = 39,
|
||||
CapabilityInputAttachment = 40,
|
||||
CapabilitySparseResidency = 41,
|
||||
CapabilityMinLod = 42,
|
||||
CapabilitySampled1D = 43,
|
||||
CapabilityImage1D = 44,
|
||||
CapabilitySampledCubeArray = 45,
|
||||
CapabilitySampledBuffer = 46,
|
||||
CapabilityImageBuffer = 47,
|
||||
CapabilityImageMSArray = 48,
|
||||
CapabilityStorageImageExtendedFormats = 49,
|
||||
CapabilityImageQuery = 50,
|
||||
CapabilityDerivativeControl = 51,
|
||||
CapabilityInterpolationFunction = 52,
|
||||
CapabilityTransformFeedback = 53,
|
||||
CapabilityGeometryStreams = 54,
|
||||
CapabilityStorageImageReadWithoutFormat = 55,
|
||||
CapabilityStorageImageWriteWithoutFormat = 56,
|
||||
CapabilityMultiViewport = 57,
|
||||
CapabilityMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
enum Op {
|
||||
OpNop = 0,
|
||||
OpUndef = 1,
|
||||
OpSourceContinued = 2,
|
||||
OpSource = 3,
|
||||
OpSourceExtension = 4,
|
||||
OpName = 5,
|
||||
OpMemberName = 6,
|
||||
OpString = 7,
|
||||
OpLine = 8,
|
||||
OpExtension = 10,
|
||||
OpExtInstImport = 11,
|
||||
OpExtInst = 12,
|
||||
OpMemoryModel = 14,
|
||||
OpEntryPoint = 15,
|
||||
OpExecutionMode = 16,
|
||||
OpCapability = 17,
|
||||
OpTypeVoid = 19,
|
||||
OpTypeBool = 20,
|
||||
OpTypeInt = 21,
|
||||
OpTypeFloat = 22,
|
||||
OpTypeVector = 23,
|
||||
OpTypeMatrix = 24,
|
||||
OpTypeImage = 25,
|
||||
OpTypeSampler = 26,
|
||||
OpTypeSampledImage = 27,
|
||||
OpTypeArray = 28,
|
||||
OpTypeRuntimeArray = 29,
|
||||
OpTypeStruct = 30,
|
||||
OpTypeOpaque = 31,
|
||||
OpTypePointer = 32,
|
||||
OpTypeFunction = 33,
|
||||
OpTypeEvent = 34,
|
||||
OpTypeDeviceEvent = 35,
|
||||
OpTypeReserveId = 36,
|
||||
OpTypeQueue = 37,
|
||||
OpTypePipe = 38,
|
||||
OpTypeForwardPointer = 39,
|
||||
OpConstantTrue = 41,
|
||||
OpConstantFalse = 42,
|
||||
OpConstant = 43,
|
||||
OpConstantComposite = 44,
|
||||
OpConstantSampler = 45,
|
||||
OpConstantNull = 46,
|
||||
OpSpecConstantTrue = 48,
|
||||
OpSpecConstantFalse = 49,
|
||||
OpSpecConstant = 50,
|
||||
OpSpecConstantComposite = 51,
|
||||
OpSpecConstantOp = 52,
|
||||
OpFunction = 54,
|
||||
OpFunctionParameter = 55,
|
||||
OpFunctionEnd = 56,
|
||||
OpFunctionCall = 57,
|
||||
OpVariable = 59,
|
||||
OpImageTexelPointer = 60,
|
||||
OpLoad = 61,
|
||||
OpStore = 62,
|
||||
OpCopyMemory = 63,
|
||||
OpCopyMemorySized = 64,
|
||||
OpAccessChain = 65,
|
||||
OpInBoundsAccessChain = 66,
|
||||
OpPtrAccessChain = 67,
|
||||
OpArrayLength = 68,
|
||||
OpGenericPtrMemSemantics = 69,
|
||||
OpInBoundsPtrAccessChain = 70,
|
||||
OpDecorate = 71,
|
||||
OpMemberDecorate = 72,
|
||||
OpDecorationGroup = 73,
|
||||
OpGroupDecorate = 74,
|
||||
OpGroupMemberDecorate = 75,
|
||||
OpVectorExtractDynamic = 77,
|
||||
OpVectorInsertDynamic = 78,
|
||||
OpVectorShuffle = 79,
|
||||
OpCompositeConstruct = 80,
|
||||
OpCompositeExtract = 81,
|
||||
OpCompositeInsert = 82,
|
||||
OpCopyObject = 83,
|
||||
OpTranspose = 84,
|
||||
OpSampledImage = 86,
|
||||
OpImageSampleImplicitLod = 87,
|
||||
OpImageSampleExplicitLod = 88,
|
||||
OpImageSampleDrefImplicitLod = 89,
|
||||
OpImageSampleDrefExplicitLod = 90,
|
||||
OpImageSampleProjImplicitLod = 91,
|
||||
OpImageSampleProjExplicitLod = 92,
|
||||
OpImageSampleProjDrefImplicitLod = 93,
|
||||
OpImageSampleProjDrefExplicitLod = 94,
|
||||
OpImageFetch = 95,
|
||||
OpImageGather = 96,
|
||||
OpImageDrefGather = 97,
|
||||
OpImageRead = 98,
|
||||
OpImageWrite = 99,
|
||||
OpImage = 100,
|
||||
OpImageQueryFormat = 101,
|
||||
OpImageQueryOrder = 102,
|
||||
OpImageQuerySizeLod = 103,
|
||||
OpImageQuerySize = 104,
|
||||
OpImageQueryLod = 105,
|
||||
OpImageQueryLevels = 106,
|
||||
OpImageQuerySamples = 107,
|
||||
OpConvertFToU = 109,
|
||||
OpConvertFToS = 110,
|
||||
OpConvertSToF = 111,
|
||||
OpConvertUToF = 112,
|
||||
OpUConvert = 113,
|
||||
OpSConvert = 114,
|
||||
OpFConvert = 115,
|
||||
OpQuantizeToF16 = 116,
|
||||
OpConvertPtrToU = 117,
|
||||
OpSatConvertSToU = 118,
|
||||
OpSatConvertUToS = 119,
|
||||
OpConvertUToPtr = 120,
|
||||
OpPtrCastToGeneric = 121,
|
||||
OpGenericCastToPtr = 122,
|
||||
OpGenericCastToPtrExplicit = 123,
|
||||
OpBitcast = 124,
|
||||
OpSNegate = 126,
|
||||
OpFNegate = 127,
|
||||
OpIAdd = 128,
|
||||
OpFAdd = 129,
|
||||
OpISub = 130,
|
||||
OpFSub = 131,
|
||||
OpIMul = 132,
|
||||
OpFMul = 133,
|
||||
OpUDiv = 134,
|
||||
OpSDiv = 135,
|
||||
OpFDiv = 136,
|
||||
OpUMod = 137,
|
||||
OpSRem = 138,
|
||||
OpSMod = 139,
|
||||
OpFRem = 140,
|
||||
OpFMod = 141,
|
||||
OpVectorTimesScalar = 142,
|
||||
OpMatrixTimesScalar = 143,
|
||||
OpVectorTimesMatrix = 144,
|
||||
OpMatrixTimesVector = 145,
|
||||
OpMatrixTimesMatrix = 146,
|
||||
OpOuterProduct = 147,
|
||||
OpDot = 148,
|
||||
OpIAddCarry = 149,
|
||||
OpISubBorrow = 150,
|
||||
OpUMulExtended = 151,
|
||||
OpSMulExtended = 152,
|
||||
OpAny = 154,
|
||||
OpAll = 155,
|
||||
OpIsNan = 156,
|
||||
OpIsInf = 157,
|
||||
OpIsFinite = 158,
|
||||
OpIsNormal = 159,
|
||||
OpSignBitSet = 160,
|
||||
OpLessOrGreater = 161,
|
||||
OpOrdered = 162,
|
||||
OpUnordered = 163,
|
||||
OpLogicalEqual = 164,
|
||||
OpLogicalNotEqual = 165,
|
||||
OpLogicalOr = 166,
|
||||
OpLogicalAnd = 167,
|
||||
OpLogicalNot = 168,
|
||||
OpSelect = 169,
|
||||
OpIEqual = 170,
|
||||
OpINotEqual = 171,
|
||||
OpUGreaterThan = 172,
|
||||
OpSGreaterThan = 173,
|
||||
OpUGreaterThanEqual = 174,
|
||||
OpSGreaterThanEqual = 175,
|
||||
OpULessThan = 176,
|
||||
OpSLessThan = 177,
|
||||
OpULessThanEqual = 178,
|
||||
OpSLessThanEqual = 179,
|
||||
OpFOrdEqual = 180,
|
||||
OpFUnordEqual = 181,
|
||||
OpFOrdNotEqual = 182,
|
||||
OpFUnordNotEqual = 183,
|
||||
OpFOrdLessThan = 184,
|
||||
OpFUnordLessThan = 185,
|
||||
OpFOrdGreaterThan = 186,
|
||||
OpFUnordGreaterThan = 187,
|
||||
OpFOrdLessThanEqual = 188,
|
||||
OpFUnordLessThanEqual = 189,
|
||||
OpFOrdGreaterThanEqual = 190,
|
||||
OpFUnordGreaterThanEqual = 191,
|
||||
OpShiftRightLogical = 194,
|
||||
OpShiftRightArithmetic = 195,
|
||||
OpShiftLeftLogical = 196,
|
||||
OpBitwiseOr = 197,
|
||||
OpBitwiseXor = 198,
|
||||
OpBitwiseAnd = 199,
|
||||
OpNot = 200,
|
||||
OpBitFieldInsert = 201,
|
||||
OpBitFieldSExtract = 202,
|
||||
OpBitFieldUExtract = 203,
|
||||
OpBitReverse = 204,
|
||||
OpBitCount = 205,
|
||||
OpDPdx = 207,
|
||||
OpDPdy = 208,
|
||||
OpFwidth = 209,
|
||||
OpDPdxFine = 210,
|
||||
OpDPdyFine = 211,
|
||||
OpFwidthFine = 212,
|
||||
OpDPdxCoarse = 213,
|
||||
OpDPdyCoarse = 214,
|
||||
OpFwidthCoarse = 215,
|
||||
OpEmitVertex = 218,
|
||||
OpEndPrimitive = 219,
|
||||
OpEmitStreamVertex = 220,
|
||||
OpEndStreamPrimitive = 221,
|
||||
OpControlBarrier = 224,
|
||||
OpMemoryBarrier = 225,
|
||||
OpAtomicLoad = 227,
|
||||
OpAtomicStore = 228,
|
||||
OpAtomicExchange = 229,
|
||||
OpAtomicCompareExchange = 230,
|
||||
OpAtomicCompareExchangeWeak = 231,
|
||||
OpAtomicIIncrement = 232,
|
||||
OpAtomicIDecrement = 233,
|
||||
OpAtomicIAdd = 234,
|
||||
OpAtomicISub = 235,
|
||||
OpAtomicSMin = 236,
|
||||
OpAtomicUMin = 237,
|
||||
OpAtomicSMax = 238,
|
||||
OpAtomicUMax = 239,
|
||||
OpAtomicAnd = 240,
|
||||
OpAtomicOr = 241,
|
||||
OpAtomicXor = 242,
|
||||
OpPhi = 245,
|
||||
OpLoopMerge = 246,
|
||||
OpSelectionMerge = 247,
|
||||
OpLabel = 248,
|
||||
OpBranch = 249,
|
||||
OpBranchConditional = 250,
|
||||
OpSwitch = 251,
|
||||
OpKill = 252,
|
||||
OpReturn = 253,
|
||||
OpReturnValue = 254,
|
||||
OpUnreachable = 255,
|
||||
OpLifetimeStart = 256,
|
||||
OpLifetimeStop = 257,
|
||||
OpGroupAsyncCopy = 259,
|
||||
OpGroupWaitEvents = 260,
|
||||
OpGroupAll = 261,
|
||||
OpGroupAny = 262,
|
||||
OpGroupBroadcast = 263,
|
||||
OpGroupIAdd = 264,
|
||||
OpGroupFAdd = 265,
|
||||
OpGroupFMin = 266,
|
||||
OpGroupUMin = 267,
|
||||
OpGroupSMin = 268,
|
||||
OpGroupFMax = 269,
|
||||
OpGroupUMax = 270,
|
||||
OpGroupSMax = 271,
|
||||
OpReadPipe = 274,
|
||||
OpWritePipe = 275,
|
||||
OpReservedReadPipe = 276,
|
||||
OpReservedWritePipe = 277,
|
||||
OpReserveReadPipePackets = 278,
|
||||
OpReserveWritePipePackets = 279,
|
||||
OpCommitReadPipe = 280,
|
||||
OpCommitWritePipe = 281,
|
||||
OpIsValidReserveId = 282,
|
||||
OpGetNumPipePackets = 283,
|
||||
OpGetMaxPipePackets = 284,
|
||||
OpGroupReserveReadPipePackets = 285,
|
||||
OpGroupReserveWritePipePackets = 286,
|
||||
OpGroupCommitReadPipe = 287,
|
||||
OpGroupCommitWritePipe = 288,
|
||||
OpEnqueueMarker = 291,
|
||||
OpEnqueueKernel = 292,
|
||||
OpGetKernelNDrangeSubGroupCount = 293,
|
||||
OpGetKernelNDrangeMaxSubGroupSize = 294,
|
||||
OpGetKernelWorkGroupSize = 295,
|
||||
OpGetKernelPreferredWorkGroupSizeMultiple = 296,
|
||||
OpRetainEvent = 297,
|
||||
OpReleaseEvent = 298,
|
||||
OpCreateUserEvent = 299,
|
||||
OpIsValidEvent = 300,
|
||||
OpSetUserEventStatus = 301,
|
||||
OpCaptureEventProfilingInfo = 302,
|
||||
OpGetDefaultQueue = 303,
|
||||
OpBuildNDRange = 304,
|
||||
OpImageSparseSampleImplicitLod = 305,
|
||||
OpImageSparseSampleExplicitLod = 306,
|
||||
OpImageSparseSampleDrefImplicitLod = 307,
|
||||
OpImageSparseSampleDrefExplicitLod = 308,
|
||||
OpImageSparseSampleProjImplicitLod = 309,
|
||||
OpImageSparseSampleProjExplicitLod = 310,
|
||||
OpImageSparseSampleProjDrefImplicitLod = 311,
|
||||
OpImageSparseSampleProjDrefExplicitLod = 312,
|
||||
OpImageSparseFetch = 313,
|
||||
OpImageSparseGather = 314,
|
||||
OpImageSparseDrefGather = 315,
|
||||
OpImageSparseTexelsResident = 316,
|
||||
OpNoLine = 317,
|
||||
OpAtomicFlagTestAndSet = 318,
|
||||
OpAtomicFlagClear = 319,
|
||||
OpImageSparseRead = 320,
|
||||
OpMax = 0x7fffffff,
|
||||
};
|
||||
|
||||
// Overload operator| for mask bit combining
|
||||
|
||||
inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); }
|
||||
inline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); }
|
||||
inline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); }
|
||||
inline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); }
|
||||
inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); }
|
||||
inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); }
|
||||
inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); }
|
||||
inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); }
|
||||
|
||||
} // end namespace spv
|
||||
|
||||
#endif // #ifndef spirv_HPP
|
||||
|
|
@ -0,0 +1,400 @@
|
|||
//
|
||||
//Copyright (C) 2014 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// SPIRV-IR
|
||||
//
|
||||
// Simple in-memory representation (IR) of SPIRV. Just for holding
|
||||
// Each function's CFG of blocks. Has this hierarchy:
|
||||
// - Module, which is a list of
|
||||
// - Function, which is a list of
|
||||
// - Block, which is a list of
|
||||
// - Instruction
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef spvIR_H
|
||||
#define spvIR_H
|
||||
|
||||
#include "spirv.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace spv {
|
||||
|
||||
class Block;
|
||||
class Function;
|
||||
class Module;
|
||||
|
||||
const Id NoResult = 0;
|
||||
const Id NoType = 0;
|
||||
|
||||
const Decoration NoPrecision = DecorationMax;
|
||||
const MemorySemanticsMask MemorySemanticsAllMemory =
|
||||
(MemorySemanticsMask)(MemorySemanticsSequentiallyConsistentMask |
|
||||
MemorySemanticsUniformMemoryMask |
|
||||
MemorySemanticsSubgroupMemoryMask |
|
||||
MemorySemanticsWorkgroupMemoryMask |
|
||||
MemorySemanticsCrossWorkgroupMemoryMask |
|
||||
MemorySemanticsAtomicCounterMemoryMask |
|
||||
MemorySemanticsImageMemoryMask);
|
||||
|
||||
//
|
||||
// SPIR-V IR instruction.
|
||||
//
|
||||
|
||||
class Instruction {
|
||||
public:
|
||||
Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), block(nullptr) { }
|
||||
explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { }
|
||||
virtual ~Instruction() {}
|
||||
void addIdOperand(Id id) { operands.push_back(id); }
|
||||
void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }
|
||||
void addStringOperand(const char* str)
|
||||
{
|
||||
originalString = str;
|
||||
unsigned int word;
|
||||
char* wordString = (char*)&word;
|
||||
char* wordPtr = wordString;
|
||||
int charCount = 0;
|
||||
char c;
|
||||
do {
|
||||
c = *(str++);
|
||||
*(wordPtr++) = c;
|
||||
++charCount;
|
||||
if (charCount == 4) {
|
||||
addImmediateOperand(word);
|
||||
wordPtr = wordString;
|
||||
charCount = 0;
|
||||
}
|
||||
} while (c != 0);
|
||||
|
||||
// deal with partial last word
|
||||
if (charCount > 0) {
|
||||
// pad with 0s
|
||||
for (; charCount < 4; ++charCount)
|
||||
*(wordPtr++) = 0;
|
||||
addImmediateOperand(word);
|
||||
}
|
||||
}
|
||||
void setBlock(Block* b) { block = b; }
|
||||
Block* getBlock() const { return block; }
|
||||
Op getOpCode() const { return opCode; }
|
||||
int getNumOperands() const { return (int)operands.size(); }
|
||||
Id getResultId() const { return resultId; }
|
||||
Id getTypeId() const { return typeId; }
|
||||
Id getIdOperand(int op) const { return operands[op]; }
|
||||
unsigned int getImmediateOperand(int op) const { return operands[op]; }
|
||||
const char* getStringOperand() const { return originalString.c_str(); }
|
||||
|
||||
// Write out the binary form.
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
// Compute the wordCount
|
||||
unsigned int wordCount = 1;
|
||||
if (typeId)
|
||||
++wordCount;
|
||||
if (resultId)
|
||||
++wordCount;
|
||||
wordCount += (unsigned int)operands.size();
|
||||
|
||||
// Write out the beginning of the instruction
|
||||
out.push_back(((wordCount) << WordCountShift) | opCode);
|
||||
if (typeId)
|
||||
out.push_back(typeId);
|
||||
if (resultId)
|
||||
out.push_back(resultId);
|
||||
|
||||
// Write out the operands
|
||||
for (int op = 0; op < (int)operands.size(); ++op)
|
||||
out.push_back(operands[op]);
|
||||
}
|
||||
|
||||
protected:
|
||||
Instruction(const Instruction&);
|
||||
Id resultId;
|
||||
Id typeId;
|
||||
Op opCode;
|
||||
std::vector<Id> operands;
|
||||
std::string originalString; // could be optimized away; convenience for getting string operand
|
||||
Block* block;
|
||||
};
|
||||
|
||||
//
|
||||
// SPIR-V IR block.
|
||||
//
|
||||
|
||||
class Block {
|
||||
public:
|
||||
Block(Id id, Function& parent);
|
||||
virtual ~Block()
|
||||
{
|
||||
}
|
||||
|
||||
Id getId() { return instructions.front()->getResultId(); }
|
||||
|
||||
Function& getParent() const { return parent; }
|
||||
void addInstruction(std::unique_ptr<Instruction> inst);
|
||||
void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);}
|
||||
void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
|
||||
const std::vector<Block*>& getPredecessors() const { return predecessors; }
|
||||
const std::vector<Block*>& getSuccessors() const { return successors; }
|
||||
const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
|
||||
return instructions;
|
||||
}
|
||||
void setUnreachable() { unreachable = true; }
|
||||
bool isUnreachable() const { return unreachable; }
|
||||
// Returns the block's merge instruction, if one exists (otherwise null).
|
||||
const Instruction* getMergeInstruction() const {
|
||||
if (instructions.size() < 2) return nullptr;
|
||||
const Instruction* nextToLast = (instructions.cend() - 2)->get();
|
||||
switch (nextToLast->getOpCode()) {
|
||||
case OpSelectionMerge:
|
||||
case OpLoopMerge:
|
||||
return nextToLast;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isTerminated() const
|
||||
{
|
||||
switch (instructions.back()->getOpCode()) {
|
||||
case OpBranch:
|
||||
case OpBranchConditional:
|
||||
case OpSwitch:
|
||||
case OpKill:
|
||||
case OpReturn:
|
||||
case OpReturnValue:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
instructions[0]->dump(out);
|
||||
for (int i = 0; i < (int)localVariables.size(); ++i)
|
||||
localVariables[i]->dump(out);
|
||||
for (int i = 1; i < (int)instructions.size(); ++i)
|
||||
instructions[i]->dump(out);
|
||||
}
|
||||
|
||||
protected:
|
||||
Block(const Block&);
|
||||
Block& operator=(Block&);
|
||||
|
||||
// To enforce keeping parent and ownership in sync:
|
||||
friend Function;
|
||||
|
||||
std::vector<std::unique_ptr<Instruction> > instructions;
|
||||
std::vector<Block*> predecessors, successors;
|
||||
std::vector<std::unique_ptr<Instruction> > localVariables;
|
||||
Function& parent;
|
||||
|
||||
// track whether this block is known to be uncreachable (not necessarily
|
||||
// true for all unreachable blocks, but should be set at least
|
||||
// for the extraneous ones introduced by the builder).
|
||||
bool unreachable;
|
||||
};
|
||||
|
||||
// Traverses the control-flow graph rooted at root in an order suited for
|
||||
// readable code generation. Invokes callback at every node in the traversal
|
||||
// order.
|
||||
void inReadableOrder(Block* root, std::function<void(Block*)> callback);
|
||||
|
||||
//
|
||||
// SPIR-V IR Function.
|
||||
//
|
||||
|
||||
class Function {
|
||||
public:
|
||||
Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
|
||||
virtual ~Function()
|
||||
{
|
||||
for (int i = 0; i < (int)parameterInstructions.size(); ++i)
|
||||
delete parameterInstructions[i];
|
||||
|
||||
for (int i = 0; i < (int)blocks.size(); ++i)
|
||||
delete blocks[i];
|
||||
}
|
||||
Id getId() const { return functionInstruction.getResultId(); }
|
||||
Id getParamId(int p) { return parameterInstructions[p]->getResultId(); }
|
||||
|
||||
void addBlock(Block* block) { blocks.push_back(block); }
|
||||
void removeBlock(Block* block)
|
||||
{
|
||||
auto found = find(blocks.begin(), blocks.end(), block);
|
||||
assert(found != blocks.end());
|
||||
blocks.erase(found);
|
||||
delete block;
|
||||
}
|
||||
|
||||
Module& getParent() const { return parent; }
|
||||
Block* getEntryBlock() const { return blocks.front(); }
|
||||
Block* getLastBlock() const { return blocks.back(); }
|
||||
const std::vector<Block*>& getBlocks() const { return blocks; }
|
||||
void addLocalVariable(std::unique_ptr<Instruction> inst);
|
||||
Id getReturnType() const { return functionInstruction.getTypeId(); }
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
// OpFunction
|
||||
functionInstruction.dump(out);
|
||||
|
||||
// OpFunctionParameter
|
||||
for (int p = 0; p < (int)parameterInstructions.size(); ++p)
|
||||
parameterInstructions[p]->dump(out);
|
||||
|
||||
// Blocks
|
||||
inReadableOrder(blocks[0], [&out](const Block* b) { b->dump(out); });
|
||||
Instruction end(0, 0, OpFunctionEnd);
|
||||
end.dump(out);
|
||||
}
|
||||
|
||||
protected:
|
||||
Function(const Function&);
|
||||
Function& operator=(Function&);
|
||||
|
||||
Module& parent;
|
||||
Instruction functionInstruction;
|
||||
std::vector<Instruction*> parameterInstructions;
|
||||
std::vector<Block*> blocks;
|
||||
};
|
||||
|
||||
//
|
||||
// SPIR-V IR Module.
|
||||
//
|
||||
|
||||
class Module {
|
||||
public:
|
||||
Module() {}
|
||||
virtual ~Module()
|
||||
{
|
||||
// TODO delete things
|
||||
}
|
||||
|
||||
void addFunction(Function *fun) { functions.push_back(fun); }
|
||||
|
||||
void mapInstruction(Instruction *instruction)
|
||||
{
|
||||
spv::Id resultId = instruction->getResultId();
|
||||
// map the instruction's result id
|
||||
if (resultId >= idToInstruction.size())
|
||||
idToInstruction.resize(resultId + 16);
|
||||
idToInstruction[resultId] = instruction;
|
||||
}
|
||||
|
||||
Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
|
||||
const std::vector<Function*>& getFunctions() const { return functions; }
|
||||
spv::Id getTypeId(Id resultId) const { return idToInstruction[resultId]->getTypeId(); }
|
||||
StorageClass getStorageClass(Id typeId) const
|
||||
{
|
||||
assert(idToInstruction[typeId]->getOpCode() == spv::OpTypePointer);
|
||||
return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0);
|
||||
}
|
||||
|
||||
void dump(std::vector<unsigned int>& out) const
|
||||
{
|
||||
for (int f = 0; f < (int)functions.size(); ++f)
|
||||
functions[f]->dump(out);
|
||||
}
|
||||
|
||||
protected:
|
||||
Module(const Module&);
|
||||
std::vector<Function*> functions;
|
||||
|
||||
// map from result id to instruction having that result id
|
||||
std::vector<Instruction*> idToInstruction;
|
||||
|
||||
// map from a result id to its type id
|
||||
};
|
||||
|
||||
//
|
||||
// Implementation (it's here due to circular type definitions).
|
||||
//
|
||||
|
||||
// Add both
|
||||
// - the OpFunction instruction
|
||||
// - all the OpFunctionParameter instructions
|
||||
__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
|
||||
: parent(parent), functionInstruction(id, resultType, OpFunction)
|
||||
{
|
||||
// OpFunction
|
||||
functionInstruction.addImmediateOperand(FunctionControlMaskNone);
|
||||
functionInstruction.addIdOperand(functionType);
|
||||
parent.mapInstruction(&functionInstruction);
|
||||
parent.addFunction(this);
|
||||
|
||||
// OpFunctionParameter
|
||||
Instruction* typeInst = parent.getInstruction(functionType);
|
||||
int numParams = typeInst->getNumOperands() - 1;
|
||||
for (int p = 0; p < numParams; ++p) {
|
||||
Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
|
||||
parent.mapInstruction(param);
|
||||
parameterInstructions.push_back(param);
|
||||
}
|
||||
}
|
||||
|
||||
__inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
|
||||
{
|
||||
Instruction* raw_instruction = inst.get();
|
||||
blocks[0]->addLocalVariable(std::move(inst));
|
||||
parent.mapInstruction(raw_instruction);
|
||||
}
|
||||
|
||||
__inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
|
||||
{
|
||||
instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, OpLabel)));
|
||||
instructions.back()->setBlock(this);
|
||||
parent.getParent().mapInstruction(instructions.back().get());
|
||||
}
|
||||
|
||||
__inline void Block::addInstruction(std::unique_ptr<Instruction> inst)
|
||||
{
|
||||
Instruction* raw_instruction = inst.get();
|
||||
instructions.push_back(std::move(inst));
|
||||
raw_instruction->setBlock(this);
|
||||
if (raw_instruction->getResultId())
|
||||
parent.getParent().mapInstruction(raw_instruction);
|
||||
}
|
||||
|
||||
}; // end spv namespace
|
||||
|
||||
#endif // spvIR_H
|
|
@ -0,0 +1,48 @@
|
|||
add_library(glslang-default-resource-limits
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ResourceLimits.cpp
|
||||
)
|
||||
set_property(TARGET glslang-default-resource-limits PROPERTY FOLDER glslang)
|
||||
|
||||
target_include_directories(glslang-default-resource-limits
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PUBLIC ${PROJECT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
set(SOURCES StandAlone.cpp)
|
||||
set(REMAPPER_SOURCES spirv-remap.cpp)
|
||||
|
||||
add_executable(glslangValidator ${SOURCES})
|
||||
add_executable(spirv-remap ${REMAPPER_SOURCES})
|
||||
set_property(TARGET glslangValidator PROPERTY FOLDER tools)
|
||||
set_property(TARGET spirv-remap PROPERTY FOLDER tools)
|
||||
glslang_set_link_args(glslangValidator)
|
||||
glslang_set_link_args(spirv-remap)
|
||||
|
||||
set(LIBRARIES
|
||||
glslang
|
||||
OGLCompiler
|
||||
OSDependent
|
||||
HLSL
|
||||
SPIRV
|
||||
glslang-default-resource-limits)
|
||||
|
||||
if(WIN32)
|
||||
set(LIBRARIES ${LIBRARIES} psapi)
|
||||
elseif(UNIX)
|
||||
if(NOT ANDROID)
|
||||
set(LIBRARIES ${LIBRARIES} pthread)
|
||||
endif()
|
||||
endif(WIN32)
|
||||
|
||||
target_link_libraries(glslangValidator ${LIBRARIES})
|
||||
target_link_libraries(spirv-remap ${LIBRARIES})
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES})
|
||||
endif(WIN32)
|
||||
|
||||
install(TARGETS glslangValidator
|
||||
RUNTIME DESTINATION bin)
|
||||
|
||||
install(TARGETS spirv-remap
|
||||
RUNTIME DESTINATION bin)
|
|
@ -0,0 +1,445 @@
|
|||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
#include "ResourceLimits.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
const TBuiltInResource DefaultTBuiltInResource = {
|
||||
/* .MaxLights = */ 32,
|
||||
/* .MaxClipPlanes = */ 6,
|
||||
/* .MaxTextureUnits = */ 32,
|
||||
/* .MaxTextureCoords = */ 32,
|
||||
/* .MaxVertexAttribs = */ 64,
|
||||
/* .MaxVertexUniformComponents = */ 4096,
|
||||
/* .MaxVaryingFloats = */ 64,
|
||||
/* .MaxVertexTextureImageUnits = */ 32,
|
||||
/* .MaxCombinedTextureImageUnits = */ 80,
|
||||
/* .MaxTextureImageUnits = */ 32,
|
||||
/* .MaxFragmentUniformComponents = */ 4096,
|
||||
/* .MaxDrawBuffers = */ 32,
|
||||
/* .MaxVertexUniformVectors = */ 128,
|
||||
/* .MaxVaryingVectors = */ 8,
|
||||
/* .MaxFragmentUniformVectors = */ 16,
|
||||
/* .MaxVertexOutputVectors = */ 16,
|
||||
/* .MaxFragmentInputVectors = */ 15,
|
||||
/* .MinProgramTexelOffset = */ -8,
|
||||
/* .MaxProgramTexelOffset = */ 7,
|
||||
/* .MaxClipDistances = */ 8,
|
||||
/* .MaxComputeWorkGroupCountX = */ 65535,
|
||||
/* .MaxComputeWorkGroupCountY = */ 65535,
|
||||
/* .MaxComputeWorkGroupCountZ = */ 65535,
|
||||
/* .MaxComputeWorkGroupSizeX = */ 1024,
|
||||
/* .MaxComputeWorkGroupSizeY = */ 1024,
|
||||
/* .MaxComputeWorkGroupSizeZ = */ 64,
|
||||
/* .MaxComputeUniformComponents = */ 1024,
|
||||
/* .MaxComputeTextureImageUnits = */ 16,
|
||||
/* .MaxComputeImageUniforms = */ 8,
|
||||
/* .MaxComputeAtomicCounters = */ 8,
|
||||
/* .MaxComputeAtomicCounterBuffers = */ 1,
|
||||
/* .MaxVaryingComponents = */ 60,
|
||||
/* .MaxVertexOutputComponents = */ 64,
|
||||
/* .MaxGeometryInputComponents = */ 64,
|
||||
/* .MaxGeometryOutputComponents = */ 128,
|
||||
/* .MaxFragmentInputComponents = */ 128,
|
||||
/* .MaxImageUnits = */ 8,
|
||||
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 8,
|
||||
/* .MaxCombinedShaderOutputResources = */ 8,
|
||||
/* .MaxImageSamples = */ 0,
|
||||
/* .MaxVertexImageUniforms = */ 0,
|
||||
/* .MaxTessControlImageUniforms = */ 0,
|
||||
/* .MaxTessEvaluationImageUniforms = */ 0,
|
||||
/* .MaxGeometryImageUniforms = */ 0,
|
||||
/* .MaxFragmentImageUniforms = */ 8,
|
||||
/* .MaxCombinedImageUniforms = */ 8,
|
||||
/* .MaxGeometryTextureImageUnits = */ 16,
|
||||
/* .MaxGeometryOutputVertices = */ 256,
|
||||
/* .MaxGeometryTotalOutputComponents = */ 1024,
|
||||
/* .MaxGeometryUniformComponents = */ 1024,
|
||||
/* .MaxGeometryVaryingComponents = */ 64,
|
||||
/* .MaxTessControlInputComponents = */ 128,
|
||||
/* .MaxTessControlOutputComponents = */ 128,
|
||||
/* .MaxTessControlTextureImageUnits = */ 16,
|
||||
/* .MaxTessControlUniformComponents = */ 1024,
|
||||
/* .MaxTessControlTotalOutputComponents = */ 4096,
|
||||
/* .MaxTessEvaluationInputComponents = */ 128,
|
||||
/* .MaxTessEvaluationOutputComponents = */ 128,
|
||||
/* .MaxTessEvaluationTextureImageUnits = */ 16,
|
||||
/* .MaxTessEvaluationUniformComponents = */ 1024,
|
||||
/* .MaxTessPatchComponents = */ 120,
|
||||
/* .MaxPatchVertices = */ 32,
|
||||
/* .MaxTessGenLevel = */ 64,
|
||||
/* .MaxViewports = */ 16,
|
||||
/* .MaxVertexAtomicCounters = */ 0,
|
||||
/* .MaxTessControlAtomicCounters = */ 0,
|
||||
/* .MaxTessEvaluationAtomicCounters = */ 0,
|
||||
/* .MaxGeometryAtomicCounters = */ 0,
|
||||
/* .MaxFragmentAtomicCounters = */ 8,
|
||||
/* .MaxCombinedAtomicCounters = */ 8,
|
||||
/* .MaxAtomicCounterBindings = */ 1,
|
||||
/* .MaxVertexAtomicCounterBuffers = */ 0,
|
||||
/* .MaxTessControlAtomicCounterBuffers = */ 0,
|
||||
/* .MaxTessEvaluationAtomicCounterBuffers = */ 0,
|
||||
/* .MaxGeometryAtomicCounterBuffers = */ 0,
|
||||
/* .MaxFragmentAtomicCounterBuffers = */ 1,
|
||||
/* .MaxCombinedAtomicCounterBuffers = */ 1,
|
||||
/* .MaxAtomicCounterBufferSize = */ 16384,
|
||||
/* .MaxTransformFeedbackBuffers = */ 4,
|
||||
/* .MaxTransformFeedbackInterleavedComponents = */ 64,
|
||||
/* .MaxCullDistances = */ 8,
|
||||
/* .MaxCombinedClipAndCullDistances = */ 8,
|
||||
/* .MaxSamples = */ 4,
|
||||
/* .limits = */ {
|
||||
/* .nonInductiveForLoops = */ 1,
|
||||
/* .whileLoops = */ 1,
|
||||
/* .doWhileLoops = */ 1,
|
||||
/* .generalUniformIndexing = */ 1,
|
||||
/* .generalAttributeMatrixVectorIndexing = */ 1,
|
||||
/* .generalVaryingIndexing = */ 1,
|
||||
/* .generalSamplerIndexing = */ 1,
|
||||
/* .generalVariableIndexing = */ 1,
|
||||
/* .generalConstantMatrixVectorIndexing = */ 1,
|
||||
}};
|
||||
|
||||
std::string GetDefaultTBuiltInResourceString()
|
||||
{
|
||||
std::ostringstream ostream;
|
||||
|
||||
ostream << "MaxLights " << DefaultTBuiltInResource.maxLights << "\n"
|
||||
<< "MaxClipPlanes " << DefaultTBuiltInResource.maxClipPlanes << "\n"
|
||||
<< "MaxTextureUnits " << DefaultTBuiltInResource.maxTextureUnits << "\n"
|
||||
<< "MaxTextureCoords " << DefaultTBuiltInResource.maxTextureCoords << "\n"
|
||||
<< "MaxVertexAttribs " << DefaultTBuiltInResource.maxVertexAttribs << "\n"
|
||||
<< "MaxVertexUniformComponents " << DefaultTBuiltInResource.maxVertexUniformComponents << "\n"
|
||||
<< "MaxVaryingFloats " << DefaultTBuiltInResource.maxVaryingFloats << "\n"
|
||||
<< "MaxVertexTextureImageUnits " << DefaultTBuiltInResource.maxVertexTextureImageUnits << "\n"
|
||||
<< "MaxCombinedTextureImageUnits " << DefaultTBuiltInResource.maxCombinedTextureImageUnits << "\n"
|
||||
<< "MaxTextureImageUnits " << DefaultTBuiltInResource.maxTextureImageUnits << "\n"
|
||||
<< "MaxFragmentUniformComponents " << DefaultTBuiltInResource.maxFragmentUniformComponents << "\n"
|
||||
<< "MaxDrawBuffers " << DefaultTBuiltInResource.maxDrawBuffers << "\n"
|
||||
<< "MaxVertexUniformVectors " << DefaultTBuiltInResource.maxVertexUniformVectors << "\n"
|
||||
<< "MaxVaryingVectors " << DefaultTBuiltInResource.maxVaryingVectors << "\n"
|
||||
<< "MaxFragmentUniformVectors " << DefaultTBuiltInResource.maxFragmentUniformVectors << "\n"
|
||||
<< "MaxVertexOutputVectors " << DefaultTBuiltInResource.maxVertexOutputVectors << "\n"
|
||||
<< "MaxFragmentInputVectors " << DefaultTBuiltInResource.maxFragmentInputVectors << "\n"
|
||||
<< "MinProgramTexelOffset " << DefaultTBuiltInResource.minProgramTexelOffset << "\n"
|
||||
<< "MaxProgramTexelOffset " << DefaultTBuiltInResource.maxProgramTexelOffset << "\n"
|
||||
<< "MaxClipDistances " << DefaultTBuiltInResource.maxClipDistances << "\n"
|
||||
<< "MaxComputeWorkGroupCountX " << DefaultTBuiltInResource.maxComputeWorkGroupCountX << "\n"
|
||||
<< "MaxComputeWorkGroupCountY " << DefaultTBuiltInResource.maxComputeWorkGroupCountY << "\n"
|
||||
<< "MaxComputeWorkGroupCountZ " << DefaultTBuiltInResource.maxComputeWorkGroupCountZ << "\n"
|
||||
<< "MaxComputeWorkGroupSizeX " << DefaultTBuiltInResource.maxComputeWorkGroupSizeX << "\n"
|
||||
<< "MaxComputeWorkGroupSizeY " << DefaultTBuiltInResource.maxComputeWorkGroupSizeY << "\n"
|
||||
<< "MaxComputeWorkGroupSizeZ " << DefaultTBuiltInResource.maxComputeWorkGroupSizeZ << "\n"
|
||||
<< "MaxComputeUniformComponents " << DefaultTBuiltInResource.maxComputeUniformComponents << "\n"
|
||||
<< "MaxComputeTextureImageUnits " << DefaultTBuiltInResource.maxComputeTextureImageUnits << "\n"
|
||||
<< "MaxComputeImageUniforms " << DefaultTBuiltInResource.maxComputeImageUniforms << "\n"
|
||||
<< "MaxComputeAtomicCounters " << DefaultTBuiltInResource.maxComputeAtomicCounters << "\n"
|
||||
<< "MaxComputeAtomicCounterBuffers " << DefaultTBuiltInResource.maxComputeAtomicCounterBuffers << "\n"
|
||||
<< "MaxVaryingComponents " << DefaultTBuiltInResource.maxVaryingComponents << "\n"
|
||||
<< "MaxVertexOutputComponents " << DefaultTBuiltInResource.maxVertexOutputComponents << "\n"
|
||||
<< "MaxGeometryInputComponents " << DefaultTBuiltInResource.maxGeometryInputComponents << "\n"
|
||||
<< "MaxGeometryOutputComponents " << DefaultTBuiltInResource.maxGeometryOutputComponents << "\n"
|
||||
<< "MaxFragmentInputComponents " << DefaultTBuiltInResource.maxFragmentInputComponents << "\n"
|
||||
<< "MaxImageUnits " << DefaultTBuiltInResource.maxImageUnits << "\n"
|
||||
<< "MaxCombinedImageUnitsAndFragmentOutputs " << DefaultTBuiltInResource.maxCombinedImageUnitsAndFragmentOutputs << "\n"
|
||||
<< "MaxCombinedShaderOutputResources " << DefaultTBuiltInResource.maxCombinedShaderOutputResources << "\n"
|
||||
<< "MaxImageSamples " << DefaultTBuiltInResource.maxImageSamples << "\n"
|
||||
<< "MaxVertexImageUniforms " << DefaultTBuiltInResource.maxVertexImageUniforms << "\n"
|
||||
<< "MaxTessControlImageUniforms " << DefaultTBuiltInResource.maxTessControlImageUniforms << "\n"
|
||||
<< "MaxTessEvaluationImageUniforms " << DefaultTBuiltInResource.maxTessEvaluationImageUniforms << "\n"
|
||||
<< "MaxGeometryImageUniforms " << DefaultTBuiltInResource.maxGeometryImageUniforms << "\n"
|
||||
<< "MaxFragmentImageUniforms " << DefaultTBuiltInResource.maxFragmentImageUniforms << "\n"
|
||||
<< "MaxCombinedImageUniforms " << DefaultTBuiltInResource.maxCombinedImageUniforms << "\n"
|
||||
<< "MaxGeometryTextureImageUnits " << DefaultTBuiltInResource.maxGeometryTextureImageUnits << "\n"
|
||||
<< "MaxGeometryOutputVertices " << DefaultTBuiltInResource.maxGeometryOutputVertices << "\n"
|
||||
<< "MaxGeometryTotalOutputComponents " << DefaultTBuiltInResource.maxGeometryTotalOutputComponents << "\n"
|
||||
<< "MaxGeometryUniformComponents " << DefaultTBuiltInResource.maxGeometryUniformComponents << "\n"
|
||||
<< "MaxGeometryVaryingComponents " << DefaultTBuiltInResource.maxGeometryVaryingComponents << "\n"
|
||||
<< "MaxTessControlInputComponents " << DefaultTBuiltInResource.maxTessControlInputComponents << "\n"
|
||||
<< "MaxTessControlOutputComponents " << DefaultTBuiltInResource.maxTessControlOutputComponents << "\n"
|
||||
<< "MaxTessControlTextureImageUnits " << DefaultTBuiltInResource.maxTessControlTextureImageUnits << "\n"
|
||||
<< "MaxTessControlUniformComponents " << DefaultTBuiltInResource.maxTessControlUniformComponents << "\n"
|
||||
<< "MaxTessControlTotalOutputComponents " << DefaultTBuiltInResource.maxTessControlTotalOutputComponents << "\n"
|
||||
<< "MaxTessEvaluationInputComponents " << DefaultTBuiltInResource.maxTessEvaluationInputComponents << "\n"
|
||||
<< "MaxTessEvaluationOutputComponents " << DefaultTBuiltInResource.maxTessEvaluationOutputComponents << "\n"
|
||||
<< "MaxTessEvaluationTextureImageUnits " << DefaultTBuiltInResource.maxTessEvaluationTextureImageUnits << "\n"
|
||||
<< "MaxTessEvaluationUniformComponents " << DefaultTBuiltInResource.maxTessEvaluationUniformComponents << "\n"
|
||||
<< "MaxTessPatchComponents " << DefaultTBuiltInResource.maxTessPatchComponents << "\n"
|
||||
<< "MaxPatchVertices " << DefaultTBuiltInResource.maxPatchVertices << "\n"
|
||||
<< "MaxTessGenLevel " << DefaultTBuiltInResource.maxTessGenLevel << "\n"
|
||||
<< "MaxViewports " << DefaultTBuiltInResource.maxViewports << "\n"
|
||||
<< "MaxVertexAtomicCounters " << DefaultTBuiltInResource.maxVertexAtomicCounters << "\n"
|
||||
<< "MaxTessControlAtomicCounters " << DefaultTBuiltInResource.maxTessControlAtomicCounters << "\n"
|
||||
<< "MaxTessEvaluationAtomicCounters " << DefaultTBuiltInResource.maxTessEvaluationAtomicCounters << "\n"
|
||||
<< "MaxGeometryAtomicCounters " << DefaultTBuiltInResource.maxGeometryAtomicCounters << "\n"
|
||||
<< "MaxFragmentAtomicCounters " << DefaultTBuiltInResource.maxFragmentAtomicCounters << "\n"
|
||||
<< "MaxCombinedAtomicCounters " << DefaultTBuiltInResource.maxCombinedAtomicCounters << "\n"
|
||||
<< "MaxAtomicCounterBindings " << DefaultTBuiltInResource.maxAtomicCounterBindings << "\n"
|
||||
<< "MaxVertexAtomicCounterBuffers " << DefaultTBuiltInResource.maxVertexAtomicCounterBuffers << "\n"
|
||||
<< "MaxTessControlAtomicCounterBuffers " << DefaultTBuiltInResource.maxTessControlAtomicCounterBuffers << "\n"
|
||||
<< "MaxTessEvaluationAtomicCounterBuffers " << DefaultTBuiltInResource.maxTessEvaluationAtomicCounterBuffers << "\n"
|
||||
<< "MaxGeometryAtomicCounterBuffers " << DefaultTBuiltInResource.maxGeometryAtomicCounterBuffers << "\n"
|
||||
<< "MaxFragmentAtomicCounterBuffers " << DefaultTBuiltInResource.maxFragmentAtomicCounterBuffers << "\n"
|
||||
<< "MaxCombinedAtomicCounterBuffers " << DefaultTBuiltInResource.maxCombinedAtomicCounterBuffers << "\n"
|
||||
<< "MaxAtomicCounterBufferSize " << DefaultTBuiltInResource.maxAtomicCounterBufferSize << "\n"
|
||||
<< "MaxTransformFeedbackBuffers " << DefaultTBuiltInResource.maxTransformFeedbackBuffers << "\n"
|
||||
<< "MaxTransformFeedbackInterleavedComponents " << DefaultTBuiltInResource.maxTransformFeedbackInterleavedComponents << "\n"
|
||||
<< "MaxCullDistances " << DefaultTBuiltInResource.maxCullDistances << "\n"
|
||||
<< "MaxCombinedClipAndCullDistances " << DefaultTBuiltInResource.maxCombinedClipAndCullDistances << "\n"
|
||||
<< "MaxSamples " << DefaultTBuiltInResource.maxSamples << "\n"
|
||||
|
||||
<< "nonInductiveForLoops " << DefaultTBuiltInResource.limits.nonInductiveForLoops << "\n"
|
||||
<< "whileLoops " << DefaultTBuiltInResource.limits.whileLoops << "\n"
|
||||
<< "doWhileLoops " << DefaultTBuiltInResource.limits.doWhileLoops << "\n"
|
||||
<< "generalUniformIndexing " << DefaultTBuiltInResource.limits.generalUniformIndexing << "\n"
|
||||
<< "generalAttributeMatrixVectorIndexing " << DefaultTBuiltInResource.limits.generalAttributeMatrixVectorIndexing << "\n"
|
||||
<< "generalVaryingIndexing " << DefaultTBuiltInResource.limits.generalVaryingIndexing << "\n"
|
||||
<< "generalSamplerIndexing " << DefaultTBuiltInResource.limits.generalSamplerIndexing << "\n"
|
||||
<< "generalVariableIndexing " << DefaultTBuiltInResource.limits.generalVariableIndexing << "\n"
|
||||
<< "generalConstantMatrixVectorIndexing " << DefaultTBuiltInResource.limits.generalConstantMatrixVectorIndexing << "\n"
|
||||
;
|
||||
|
||||
return ostream.str();
|
||||
}
|
||||
|
||||
void DecodeResourceLimits(TBuiltInResource* resources, char* config)
|
||||
{
|
||||
const char* delims = " \t\n\r";
|
||||
const char* token = strtok(config, delims);
|
||||
while (token) {
|
||||
const char* valueStr = strtok(0, delims);
|
||||
if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
|
||||
printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
|
||||
return;
|
||||
}
|
||||
int value = atoi(valueStr);
|
||||
|
||||
if (strcmp(token, "MaxLights") == 0)
|
||||
resources->maxLights = value;
|
||||
else if (strcmp(token, "MaxClipPlanes") == 0)
|
||||
resources->maxClipPlanes = value;
|
||||
else if (strcmp(token, "MaxTextureUnits") == 0)
|
||||
resources->maxTextureUnits = value;
|
||||
else if (strcmp(token, "MaxTextureCoords") == 0)
|
||||
resources->maxTextureCoords = value;
|
||||
else if (strcmp(token, "MaxVertexAttribs") == 0)
|
||||
resources->maxVertexAttribs = value;
|
||||
else if (strcmp(token, "MaxVertexUniformComponents") == 0)
|
||||
resources->maxVertexUniformComponents = value;
|
||||
else if (strcmp(token, "MaxVaryingFloats") == 0)
|
||||
resources->maxVaryingFloats = value;
|
||||
else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
|
||||
resources->maxVertexTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
|
||||
resources->maxCombinedTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxTextureImageUnits") == 0)
|
||||
resources->maxTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
|
||||
resources->maxFragmentUniformComponents = value;
|
||||
else if (strcmp(token, "MaxDrawBuffers") == 0)
|
||||
resources->maxDrawBuffers = value;
|
||||
else if (strcmp(token, "MaxVertexUniformVectors") == 0)
|
||||
resources->maxVertexUniformVectors = value;
|
||||
else if (strcmp(token, "MaxVaryingVectors") == 0)
|
||||
resources->maxVaryingVectors = value;
|
||||
else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
|
||||
resources->maxFragmentUniformVectors = value;
|
||||
else if (strcmp(token, "MaxVertexOutputVectors") == 0)
|
||||
resources->maxVertexOutputVectors = value;
|
||||
else if (strcmp(token, "MaxFragmentInputVectors") == 0)
|
||||
resources->maxFragmentInputVectors = value;
|
||||
else if (strcmp(token, "MinProgramTexelOffset") == 0)
|
||||
resources->minProgramTexelOffset = value;
|
||||
else if (strcmp(token, "MaxProgramTexelOffset") == 0)
|
||||
resources->maxProgramTexelOffset = value;
|
||||
else if (strcmp(token, "MaxClipDistances") == 0)
|
||||
resources->maxClipDistances = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
|
||||
resources->maxComputeWorkGroupCountX = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
|
||||
resources->maxComputeWorkGroupCountY = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
|
||||
resources->maxComputeWorkGroupCountZ = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
|
||||
resources->maxComputeWorkGroupSizeX = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
|
||||
resources->maxComputeWorkGroupSizeY = value;
|
||||
else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
|
||||
resources->maxComputeWorkGroupSizeZ = value;
|
||||
else if (strcmp(token, "MaxComputeUniformComponents") == 0)
|
||||
resources->maxComputeUniformComponents = value;
|
||||
else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
|
||||
resources->maxComputeTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxComputeImageUniforms") == 0)
|
||||
resources->maxComputeImageUniforms = value;
|
||||
else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
|
||||
resources->maxComputeAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
|
||||
resources->maxComputeAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxVaryingComponents") == 0)
|
||||
resources->maxVaryingComponents = value;
|
||||
else if (strcmp(token, "MaxVertexOutputComponents") == 0)
|
||||
resources->maxVertexOutputComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryInputComponents") == 0)
|
||||
resources->maxGeometryInputComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
|
||||
resources->maxGeometryOutputComponents = value;
|
||||
else if (strcmp(token, "MaxFragmentInputComponents") == 0)
|
||||
resources->maxFragmentInputComponents = value;
|
||||
else if (strcmp(token, "MaxImageUnits") == 0)
|
||||
resources->maxImageUnits = value;
|
||||
else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
|
||||
resources->maxCombinedImageUnitsAndFragmentOutputs = value;
|
||||
else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
|
||||
resources->maxCombinedShaderOutputResources = value;
|
||||
else if (strcmp(token, "MaxImageSamples") == 0)
|
||||
resources->maxImageSamples = value;
|
||||
else if (strcmp(token, "MaxVertexImageUniforms") == 0)
|
||||
resources->maxVertexImageUniforms = value;
|
||||
else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
|
||||
resources->maxTessControlImageUniforms = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
|
||||
resources->maxTessEvaluationImageUniforms = value;
|
||||
else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
|
||||
resources->maxGeometryImageUniforms = value;
|
||||
else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
|
||||
resources->maxFragmentImageUniforms = value;
|
||||
else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
|
||||
resources->maxCombinedImageUniforms = value;
|
||||
else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
|
||||
resources->maxGeometryTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
|
||||
resources->maxGeometryOutputVertices = value;
|
||||
else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
|
||||
resources->maxGeometryTotalOutputComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
|
||||
resources->maxGeometryUniformComponents = value;
|
||||
else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
|
||||
resources->maxGeometryVaryingComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlInputComponents") == 0)
|
||||
resources->maxTessControlInputComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
|
||||
resources->maxTessControlOutputComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
|
||||
resources->maxTessControlTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
|
||||
resources->maxTessControlUniformComponents = value;
|
||||
else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
|
||||
resources->maxTessControlTotalOutputComponents = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
|
||||
resources->maxTessEvaluationInputComponents = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
|
||||
resources->maxTessEvaluationOutputComponents = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
|
||||
resources->maxTessEvaluationTextureImageUnits = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
|
||||
resources->maxTessEvaluationUniformComponents = value;
|
||||
else if (strcmp(token, "MaxTessPatchComponents") == 0)
|
||||
resources->maxTessPatchComponents = value;
|
||||
else if (strcmp(token, "MaxPatchVertices") == 0)
|
||||
resources->maxPatchVertices = value;
|
||||
else if (strcmp(token, "MaxTessGenLevel") == 0)
|
||||
resources->maxTessGenLevel = value;
|
||||
else if (strcmp(token, "MaxViewports") == 0)
|
||||
resources->maxViewports = value;
|
||||
else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
|
||||
resources->maxVertexAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
|
||||
resources->maxTessControlAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
|
||||
resources->maxTessEvaluationAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
|
||||
resources->maxGeometryAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
|
||||
resources->maxFragmentAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
|
||||
resources->maxCombinedAtomicCounters = value;
|
||||
else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
|
||||
resources->maxAtomicCounterBindings = value;
|
||||
else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
|
||||
resources->maxVertexAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
|
||||
resources->maxTessControlAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
|
||||
resources->maxTessEvaluationAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
|
||||
resources->maxGeometryAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
|
||||
resources->maxFragmentAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
|
||||
resources->maxCombinedAtomicCounterBuffers = value;
|
||||
else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
|
||||
resources->maxAtomicCounterBufferSize = value;
|
||||
else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
|
||||
resources->maxTransformFeedbackBuffers = value;
|
||||
else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
|
||||
resources->maxTransformFeedbackInterleavedComponents = value;
|
||||
else if (strcmp(token, "MaxCullDistances") == 0)
|
||||
resources->maxCullDistances = value;
|
||||
else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
|
||||
resources->maxCombinedClipAndCullDistances = value;
|
||||
else if (strcmp(token, "MaxSamples") == 0)
|
||||
resources->maxSamples = value;
|
||||
|
||||
else if (strcmp(token, "nonInductiveForLoops") == 0)
|
||||
resources->limits.nonInductiveForLoops = (value != 0);
|
||||
else if (strcmp(token, "whileLoops") == 0)
|
||||
resources->limits.whileLoops = (value != 0);
|
||||
else if (strcmp(token, "doWhileLoops") == 0)
|
||||
resources->limits.doWhileLoops = (value != 0);
|
||||
else if (strcmp(token, "generalUniformIndexing") == 0)
|
||||
resources->limits.generalUniformIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
|
||||
resources->limits.generalAttributeMatrixVectorIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalVaryingIndexing") == 0)
|
||||
resources->limits.generalVaryingIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalSamplerIndexing") == 0)
|
||||
resources->limits.generalSamplerIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalVariableIndexing") == 0)
|
||||
resources->limits.generalVariableIndexing = (value != 0);
|
||||
else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
|
||||
resources->limits.generalConstantMatrixVectorIndexing = (value != 0);
|
||||
else
|
||||
printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
|
||||
|
||||
token = strtok(0, delims);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
|
||||
#define _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "glslang/Include/ResourceLimits.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// These are the default resources for TBuiltInResources, used for both
|
||||
// - parsing this string for the case where the user didn't supply one,
|
||||
// - dumping out a template for user construction of a config file.
|
||||
extern const TBuiltInResource DefaultTBuiltInResource;
|
||||
|
||||
// Returns the DefaultTBuiltInResource as a human-readable string.
|
||||
std::string GetDefaultTBuiltInResourceString();
|
||||
|
||||
// Decodes the resource limits from |config| to |resources|.
|
||||
void DecodeResourceLimits(TBuiltInResource* resources, char* config);
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_
|
|
@ -0,0 +1,914 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
// this only applies to the standalone wrapper, not the front end in general
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include "ResourceLimits.h"
|
||||
#include "Worklist.h"
|
||||
#include "./../glslang/Include/ShHandle.h"
|
||||
#include "./../glslang/Include/revision.h"
|
||||
#include "./../glslang/Public/ShaderLang.h"
|
||||
#include "../SPIRV/GlslangToSpv.h"
|
||||
#include "../SPIRV/GLSL.std.450.h"
|
||||
#include "../SPIRV/doc.h"
|
||||
#include "../SPIRV/disassemble.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../glslang/OSDependent/osinclude.h"
|
||||
|
||||
extern "C" {
|
||||
SH_IMPORT_EXPORT void ShOutputHtml();
|
||||
}
|
||||
|
||||
// Command-line options
|
||||
enum TOptions {
|
||||
EOptionNone = 0,
|
||||
EOptionIntermediate = (1 << 0),
|
||||
EOptionSuppressInfolog = (1 << 1),
|
||||
EOptionMemoryLeakMode = (1 << 2),
|
||||
EOptionRelaxedErrors = (1 << 3),
|
||||
EOptionGiveWarnings = (1 << 4),
|
||||
EOptionLinkProgram = (1 << 5),
|
||||
EOptionMultiThreaded = (1 << 6),
|
||||
EOptionDumpConfig = (1 << 7),
|
||||
EOptionDumpReflection = (1 << 8),
|
||||
EOptionSuppressWarnings = (1 << 9),
|
||||
EOptionDumpVersions = (1 << 10),
|
||||
EOptionSpv = (1 << 11),
|
||||
EOptionHumanReadableSpv = (1 << 12),
|
||||
EOptionVulkanRules = (1 << 13),
|
||||
EOptionDefaultDesktop = (1 << 14),
|
||||
EOptionOutputPreprocessed = (1 << 15),
|
||||
EOptionOutputHexadecimal = (1 << 16),
|
||||
EOptionReadHlsl = (1 << 17),
|
||||
EOptionCascadingErrors = (1 << 18),
|
||||
};
|
||||
|
||||
//
|
||||
// Return codes from main/exit().
|
||||
//
|
||||
enum TFailCode {
|
||||
ESuccess = 0,
|
||||
EFailUsage,
|
||||
EFailCompile,
|
||||
EFailLink,
|
||||
EFailCompilerCreate,
|
||||
EFailThreadCreate,
|
||||
EFailLinkerCreate
|
||||
};
|
||||
|
||||
//
|
||||
// Forward declarations.
|
||||
//
|
||||
EShLanguage FindLanguage(const std::string& name);
|
||||
void CompileFile(const char* fileName, ShHandle);
|
||||
void usage();
|
||||
void FreeFileData(char** data);
|
||||
char** ReadFileData(const char* fileName);
|
||||
void InfoLogMsg(const char* msg, const char* name, const int num);
|
||||
|
||||
// Globally track if any compile or link failure.
|
||||
bool CompileFailed = false;
|
||||
bool LinkFailed = false;
|
||||
|
||||
// Use to test breaking up a single shader file into multiple strings.
|
||||
// Set in ReadFileData().
|
||||
int NumShaderStrings;
|
||||
|
||||
TBuiltInResource Resources;
|
||||
std::string ConfigFile;
|
||||
|
||||
//
|
||||
// Parse either a .conf file provided by the user or the default from glslang::DefaultTBuiltInResource
|
||||
//
|
||||
void ProcessConfigFile()
|
||||
{
|
||||
char** configStrings = 0;
|
||||
char* config = 0;
|
||||
if (ConfigFile.size() > 0) {
|
||||
configStrings = ReadFileData(ConfigFile.c_str());
|
||||
if (configStrings)
|
||||
config = *configStrings;
|
||||
else {
|
||||
printf("Error opening configuration file; will instead use the default configuration\n");
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (config == 0) {
|
||||
Resources = glslang::DefaultTBuiltInResource;
|
||||
return;
|
||||
}
|
||||
|
||||
glslang::DecodeResourceLimits(&Resources, config);
|
||||
|
||||
if (configStrings)
|
||||
FreeFileData(configStrings);
|
||||
else
|
||||
delete[] config;
|
||||
}
|
||||
|
||||
// thread-safe list of shaders to asynchronously grab and compile
|
||||
glslang::TWorklist Worklist;
|
||||
|
||||
// array of unique places to leave the shader names and infologs for the asynchronous compiles
|
||||
glslang::TWorkItem** Work = 0;
|
||||
int NumWorkItems = 0;
|
||||
|
||||
int Options = 0;
|
||||
const char* ExecutableName = nullptr;
|
||||
const char* binaryFileName = nullptr;
|
||||
const char* entryPointName = nullptr;
|
||||
|
||||
//
|
||||
// Create the default name for saving a binary if -o is not provided.
|
||||
//
|
||||
const char* GetBinaryName(EShLanguage stage)
|
||||
{
|
||||
const char* name;
|
||||
if (binaryFileName == nullptr) {
|
||||
switch (stage) {
|
||||
case EShLangVertex: name = "vert.spv"; break;
|
||||
case EShLangTessControl: name = "tesc.spv"; break;
|
||||
case EShLangTessEvaluation: name = "tese.spv"; break;
|
||||
case EShLangGeometry: name = "geom.spv"; break;
|
||||
case EShLangFragment: name = "frag.spv"; break;
|
||||
case EShLangCompute: name = "comp.spv"; break;
|
||||
default: name = "unknown"; break;
|
||||
}
|
||||
} else
|
||||
name = binaryFileName;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
//
|
||||
// *.conf => this is a config file that can set limits/resources
|
||||
//
|
||||
bool SetConfigFile(const std::string& name)
|
||||
{
|
||||
if (name.size() < 5)
|
||||
return false;
|
||||
|
||||
if (name.compare(name.size() - 5, 5, ".conf") == 0) {
|
||||
ConfigFile = name;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Give error and exit with failure code.
|
||||
//
|
||||
void Error(const char* message)
|
||||
{
|
||||
printf("%s: Error %s (use -h for usage)\n", ExecutableName, message);
|
||||
exit(EFailUsage);
|
||||
}
|
||||
|
||||
//
|
||||
// Do all command-line argument parsing. This includes building up the work-items
|
||||
// to be processed later, and saving all the command-line options.
|
||||
//
|
||||
// Does not return (it exits) if command-line is fatally flawed.
|
||||
//
|
||||
void ProcessArguments(int argc, char* argv[])
|
||||
{
|
||||
ExecutableName = argv[0];
|
||||
NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
|
||||
Work = new glslang::TWorkItem*[NumWorkItems];
|
||||
for (int w = 0; w < NumWorkItems; ++w)
|
||||
Work[w] = 0;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
for (; argc >= 1; argc--, argv++) {
|
||||
if (argv[0][0] == '-') {
|
||||
switch (argv[0][1]) {
|
||||
case 'H':
|
||||
Options |= EOptionHumanReadableSpv;
|
||||
if ((Options & EOptionSpv) == 0) {
|
||||
// default to Vulkan
|
||||
Options |= EOptionSpv;
|
||||
Options |= EOptionVulkanRules;
|
||||
Options |= EOptionLinkProgram;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
Options |= EOptionSpv;
|
||||
Options |= EOptionVulkanRules;
|
||||
Options |= EOptionLinkProgram;
|
||||
break;
|
||||
case 'G':
|
||||
Options |= EOptionSpv;
|
||||
Options |= EOptionLinkProgram;
|
||||
// undo a -H default to Vulkan
|
||||
Options &= ~EOptionVulkanRules;
|
||||
break;
|
||||
case 'E':
|
||||
Options |= EOptionOutputPreprocessed;
|
||||
break;
|
||||
case 'c':
|
||||
Options |= EOptionDumpConfig;
|
||||
break;
|
||||
case 'C':
|
||||
Options |= EOptionCascadingErrors;
|
||||
break;
|
||||
case 'd':
|
||||
Options |= EOptionDefaultDesktop;
|
||||
break;
|
||||
case 'D':
|
||||
Options |= EOptionReadHlsl;
|
||||
break;
|
||||
case 'e':
|
||||
// HLSL todo: entry point handle needs much more sophistication.
|
||||
// This is okay for one compilation unit with one entry point.
|
||||
entryPointName = argv[1];
|
||||
if (argc > 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
} else
|
||||
Error("no <entry-point> provided for -e");
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'i':
|
||||
Options |= EOptionIntermediate;
|
||||
break;
|
||||
case 'l':
|
||||
Options |= EOptionLinkProgram;
|
||||
break;
|
||||
case 'm':
|
||||
Options |= EOptionMemoryLeakMode;
|
||||
break;
|
||||
case 'o':
|
||||
binaryFileName = argv[1];
|
||||
if (argc > 0) {
|
||||
argc--;
|
||||
argv++;
|
||||
} else
|
||||
Error("no <file> provided for -o");
|
||||
break;
|
||||
case 'q':
|
||||
Options |= EOptionDumpReflection;
|
||||
break;
|
||||
case 'r':
|
||||
Options |= EOptionRelaxedErrors;
|
||||
break;
|
||||
case 's':
|
||||
Options |= EOptionSuppressInfolog;
|
||||
break;
|
||||
case 't':
|
||||
#ifdef _WIN32
|
||||
Options |= EOptionMultiThreaded;
|
||||
#endif
|
||||
break;
|
||||
case 'v':
|
||||
Options |= EOptionDumpVersions;
|
||||
break;
|
||||
case 'w':
|
||||
Options |= EOptionSuppressWarnings;
|
||||
break;
|
||||
case 'x':
|
||||
Options |= EOptionOutputHexadecimal;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
std::string name(argv[0]);
|
||||
if (! SetConfigFile(name)) {
|
||||
Work[argc] = new glslang::TWorkItem(name);
|
||||
Worklist.add(Work[argc]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that -E is not specified alongside linking (which includes SPV generation)
|
||||
if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
|
||||
Error("can't use -E when linking is selected");
|
||||
|
||||
// -o or -x makes no sense if there is no target binary
|
||||
if (binaryFileName && (Options & EOptionSpv) == 0)
|
||||
Error("no binary generation requested (e.g., -V)");
|
||||
}
|
||||
|
||||
//
|
||||
// Translate the meaningful subset of command-line options to parser-behavior options.
|
||||
//
|
||||
void SetMessageOptions(EShMessages& messages)
|
||||
{
|
||||
if (Options & EOptionRelaxedErrors)
|
||||
messages = (EShMessages)(messages | EShMsgRelaxedErrors);
|
||||
if (Options & EOptionIntermediate)
|
||||
messages = (EShMessages)(messages | EShMsgAST);
|
||||
if (Options & EOptionSuppressWarnings)
|
||||
messages = (EShMessages)(messages | EShMsgSuppressWarnings);
|
||||
if (Options & EOptionSpv)
|
||||
messages = (EShMessages)(messages | EShMsgSpvRules);
|
||||
if (Options & EOptionVulkanRules)
|
||||
messages = (EShMessages)(messages | EShMsgVulkanRules);
|
||||
if (Options & EOptionOutputPreprocessed)
|
||||
messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
|
||||
if (Options & EOptionReadHlsl)
|
||||
messages = (EShMessages)(messages | EShMsgReadHlsl);
|
||||
if (Options & EOptionCascadingErrors)
|
||||
messages = (EShMessages)(messages | EShMsgCascadingErrors);
|
||||
}
|
||||
|
||||
//
|
||||
// Thread entry point, for non-linking asynchronous mode.
|
||||
//
|
||||
// Return 0 for failure, 1 for success.
|
||||
//
|
||||
unsigned int CompileShaders(void*)
|
||||
{
|
||||
glslang::TWorkItem* workItem;
|
||||
while (Worklist.remove(workItem)) {
|
||||
ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
|
||||
if (compiler == 0)
|
||||
return 0;
|
||||
|
||||
CompileFile(workItem->name.c_str(), compiler);
|
||||
|
||||
if (! (Options & EOptionSuppressInfolog))
|
||||
workItem->results = ShGetInfoLog(compiler);
|
||||
|
||||
ShDestruct(compiler);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Outputs the given string, but only if it is non-null and non-empty.
|
||||
// This prevents erroneous newlines from appearing.
|
||||
void PutsIfNonEmpty(const char* str)
|
||||
{
|
||||
if (str && str[0]) {
|
||||
puts(str);
|
||||
}
|
||||
}
|
||||
|
||||
// Outputs the given string to stderr, but only if it is non-null and non-empty.
|
||||
// This prevents erroneous newlines from appearing.
|
||||
void StderrIfNonEmpty(const char* str)
|
||||
{
|
||||
if (str && str[0]) {
|
||||
fprintf(stderr, "%s\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple bundling of what makes a compilation unit for ease in passing around,
|
||||
// and separation of handling file IO versus API (programmatic) compilation.
|
||||
struct ShaderCompUnit {
|
||||
EShLanguage stage;
|
||||
std::string fileName;
|
||||
char** text; // memory owned/managed externally
|
||||
};
|
||||
|
||||
//
|
||||
// For linking mode: Will independently parse each compilation unit, but then put them
|
||||
// in the same program and link them together, making at most one linked module per
|
||||
// pipeline stage.
|
||||
//
|
||||
// Uses the new C++ interface instead of the old handle-based interface.
|
||||
//
|
||||
|
||||
void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
|
||||
{
|
||||
// keep track of what to free
|
||||
std::list<glslang::TShader*> shaders;
|
||||
|
||||
EShMessages messages = EShMsgDefault;
|
||||
SetMessageOptions(messages);
|
||||
|
||||
//
|
||||
// Per-shader processing...
|
||||
//
|
||||
|
||||
glslang::TProgram& program = *new glslang::TProgram;
|
||||
for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
|
||||
const auto &compUnit = *it;
|
||||
glslang::TShader* shader = new glslang::TShader(compUnit.stage);
|
||||
shader->setStrings(compUnit.text, 1);
|
||||
if (entryPointName) // HLSL todo: this needs to be tracked per compUnits
|
||||
shader->setEntryPoint(entryPointName);
|
||||
shaders.push_back(shader);
|
||||
|
||||
const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;
|
||||
|
||||
if (Options & EOptionOutputPreprocessed) {
|
||||
std::string str;
|
||||
glslang::TShader::ForbidInclude includer;
|
||||
if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
|
||||
messages, &str, includer)) {
|
||||
PutsIfNonEmpty(str.c_str());
|
||||
} else {
|
||||
CompileFailed = true;
|
||||
}
|
||||
StderrIfNonEmpty(shader->getInfoLog());
|
||||
StderrIfNonEmpty(shader->getInfoDebugLog());
|
||||
continue;
|
||||
}
|
||||
if (! shader->parse(&Resources, defaultVersion, false, messages))
|
||||
CompileFailed = true;
|
||||
|
||||
program.addShader(shader);
|
||||
|
||||
if (! (Options & EOptionSuppressInfolog) &&
|
||||
! (Options & EOptionMemoryLeakMode)) {
|
||||
PutsIfNonEmpty(compUnit.fileName.c_str());
|
||||
PutsIfNonEmpty(shader->getInfoLog());
|
||||
PutsIfNonEmpty(shader->getInfoDebugLog());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Program-level processing...
|
||||
//
|
||||
|
||||
// Link
|
||||
if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
|
||||
LinkFailed = true;
|
||||
|
||||
// Report
|
||||
if (! (Options & EOptionSuppressInfolog) &&
|
||||
! (Options & EOptionMemoryLeakMode)) {
|
||||
PutsIfNonEmpty(program.getInfoLog());
|
||||
PutsIfNonEmpty(program.getInfoDebugLog());
|
||||
}
|
||||
|
||||
// Reflect
|
||||
if (Options & EOptionDumpReflection) {
|
||||
program.buildReflection();
|
||||
program.dumpReflection();
|
||||
}
|
||||
|
||||
// Dump SPIR-V
|
||||
if (Options & EOptionSpv) {
|
||||
if (CompileFailed || LinkFailed)
|
||||
printf("SPIR-V is not generated for failed compile or link\n");
|
||||
else {
|
||||
for (int stage = 0; stage < EShLangCount; ++stage) {
|
||||
if (program.getIntermediate((EShLanguage)stage)) {
|
||||
std::vector<unsigned int> spirv;
|
||||
std::string warningsErrors;
|
||||
spv::SpvBuildLogger logger;
|
||||
glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger);
|
||||
|
||||
// Dump the spv to a file or stdout, etc., but only if not doing
|
||||
// memory/perf testing, as it's not internal to programmatic use.
|
||||
if (! (Options & EOptionMemoryLeakMode)) {
|
||||
printf("%s", logger.getAllMessages().c_str());
|
||||
if (Options & EOptionOutputHexadecimal) {
|
||||
glslang::OutputSpvHex(spirv, GetBinaryName((EShLanguage)stage));
|
||||
} else {
|
||||
glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage));
|
||||
}
|
||||
if (Options & EOptionHumanReadableSpv) {
|
||||
spv::Disassemble(std::cout, spirv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free everything up, program has to go before the shaders
|
||||
// because it might have merged stuff from the shaders, and
|
||||
// the stuff from the shaders has to have its destructors called
|
||||
// before the pools holding the memory in the shaders is freed.
|
||||
delete &program;
|
||||
while (shaders.size() > 0) {
|
||||
delete shaders.back();
|
||||
shaders.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Do file IO part of compile and link, handing off the pure
|
||||
// API/programmatic mode to CompileAndLinkShaderUnits(), which can
|
||||
// be put in a loop for testing memory footprint and performance.
|
||||
//
|
||||
// This is just for linking mode: meaning all the shaders will be put into the
|
||||
// the same program linked together.
|
||||
//
|
||||
// This means there are a limited number of work items (not multi-threading mode)
|
||||
// and that the point is testing at the linking level. Hence, to enable
|
||||
// performance and memory testing, the actual compile/link can be put in
|
||||
// a loop, independent of processing the work items and file IO.
|
||||
//
|
||||
void CompileAndLinkShaderFiles()
|
||||
{
|
||||
std::vector<ShaderCompUnit> compUnits;
|
||||
|
||||
// Transfer all the work items from to a simple list of
|
||||
// of compilation units. (We don't care about the thread
|
||||
// work-item distribution properties in this path, which
|
||||
// is okay due to the limited number of shaders, know since
|
||||
// they are all getting linked together.)
|
||||
glslang::TWorkItem* workItem;
|
||||
while (Worklist.remove(workItem)) {
|
||||
ShaderCompUnit compUnit = {
|
||||
FindLanguage(workItem->name),
|
||||
workItem->name,
|
||||
ReadFileData(workItem->name.c_str())
|
||||
};
|
||||
|
||||
if (! compUnit.text) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
compUnits.push_back(compUnit);
|
||||
}
|
||||
|
||||
// Actual call to programmatic processing of compile and link,
|
||||
// in a loop for testing memory and performance. This part contains
|
||||
// all the perf/memory that a programmatic consumer will care about.
|
||||
for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
|
||||
for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
|
||||
CompileAndLinkShaderUnits(compUnits);
|
||||
|
||||
if (Options & EOptionMemoryLeakMode)
|
||||
glslang::OS_DumpMemoryCounters();
|
||||
}
|
||||
|
||||
for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
|
||||
FreeFileData(it->text);
|
||||
}
|
||||
|
||||
int C_DECL main(int argc, char* argv[])
|
||||
{
|
||||
ProcessArguments(argc, argv);
|
||||
|
||||
if (Options & EOptionDumpConfig) {
|
||||
printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str());
|
||||
if (Worklist.empty())
|
||||
return ESuccess;
|
||||
}
|
||||
|
||||
if (Options & EOptionDumpVersions) {
|
||||
printf("Glslang Version: %s %s\n", GLSLANG_REVISION, GLSLANG_DATE);
|
||||
printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
|
||||
printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
|
||||
std::string spirvVersion;
|
||||
glslang::GetSpirvVersion(spirvVersion);
|
||||
printf("SPIR-V Version %s\n", spirvVersion.c_str());
|
||||
printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
|
||||
printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
|
||||
if (Worklist.empty())
|
||||
return ESuccess;
|
||||
}
|
||||
|
||||
if (Worklist.empty()) {
|
||||
usage();
|
||||
}
|
||||
|
||||
ProcessConfigFile();
|
||||
|
||||
//
|
||||
// Two modes:
|
||||
// 1) linking all arguments together, single-threaded, new C++ interface
|
||||
// 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety, using the old handle interface
|
||||
//
|
||||
if (Options & EOptionLinkProgram ||
|
||||
Options & EOptionOutputPreprocessed) {
|
||||
glslang::InitializeProcess();
|
||||
CompileAndLinkShaderFiles();
|
||||
glslang::FinalizeProcess();
|
||||
for (int w = 0; w < NumWorkItems; ++w) {
|
||||
if (Work[w]) {
|
||||
delete Work[w];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ShInitialize();
|
||||
|
||||
bool printShaderNames = Worklist.size() > 1;
|
||||
|
||||
if (Options & EOptionMultiThreaded) {
|
||||
const int NumThreads = 16;
|
||||
void* threads[NumThreads];
|
||||
for (int t = 0; t < NumThreads; ++t) {
|
||||
threads[t] = glslang::OS_CreateThread(&CompileShaders);
|
||||
if (! threads[t]) {
|
||||
printf("Failed to create thread\n");
|
||||
return EFailThreadCreate;
|
||||
}
|
||||
}
|
||||
glslang::OS_WaitForAllThreads(threads, NumThreads);
|
||||
} else
|
||||
CompileShaders(0);
|
||||
|
||||
// Print out all the resulting infologs
|
||||
for (int w = 0; w < NumWorkItems; ++w) {
|
||||
if (Work[w]) {
|
||||
if (printShaderNames || Work[w]->results.size() > 0)
|
||||
PutsIfNonEmpty(Work[w]->name.c_str());
|
||||
PutsIfNonEmpty(Work[w]->results.c_str());
|
||||
delete Work[w];
|
||||
}
|
||||
}
|
||||
|
||||
ShFinalize();
|
||||
}
|
||||
|
||||
delete[] Work;
|
||||
|
||||
if (CompileFailed)
|
||||
return EFailCompile;
|
||||
if (LinkFailed)
|
||||
return EFailLink;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Deduce the language from the filename. Files must end in one of the
|
||||
// following extensions:
|
||||
//
|
||||
// .vert = vertex
|
||||
// .tesc = tessellation control
|
||||
// .tese = tessellation evaluation
|
||||
// .geom = geometry
|
||||
// .frag = fragment
|
||||
// .comp = compute
|
||||
//
|
||||
EShLanguage FindLanguage(const std::string& name)
|
||||
{
|
||||
size_t ext = name.rfind('.');
|
||||
if (ext == std::string::npos) {
|
||||
usage();
|
||||
return EShLangVertex;
|
||||
}
|
||||
|
||||
std::string suffix = name.substr(ext + 1, std::string::npos);
|
||||
if (suffix == "vert")
|
||||
return EShLangVertex;
|
||||
else if (suffix == "tesc")
|
||||
return EShLangTessControl;
|
||||
else if (suffix == "tese")
|
||||
return EShLangTessEvaluation;
|
||||
else if (suffix == "geom")
|
||||
return EShLangGeometry;
|
||||
else if (suffix == "frag")
|
||||
return EShLangFragment;
|
||||
else if (suffix == "comp")
|
||||
return EShLangCompute;
|
||||
|
||||
usage();
|
||||
return EShLangVertex;
|
||||
}
|
||||
|
||||
//
|
||||
// Read a file's data into a string, and compile it using the old interface ShCompile,
|
||||
// for non-linkable results.
|
||||
//
|
||||
void CompileFile(const char* fileName, ShHandle compiler)
|
||||
{
|
||||
int ret = 0;
|
||||
char** shaderStrings = ReadFileData(fileName);
|
||||
if (! shaderStrings) {
|
||||
usage();
|
||||
}
|
||||
|
||||
int* lengths = new int[NumShaderStrings];
|
||||
|
||||
// move to length-based strings, rather than null-terminated strings
|
||||
for (int s = 0; s < NumShaderStrings; ++s)
|
||||
lengths[s] = (int)strlen(shaderStrings[s]);
|
||||
|
||||
if (! shaderStrings) {
|
||||
CompileFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
EShMessages messages = EShMsgDefault;
|
||||
SetMessageOptions(messages);
|
||||
|
||||
for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
|
||||
for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
|
||||
//ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
|
||||
ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
|
||||
//const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
|
||||
// "or should be l", "ine 1", "string 5\n", "float glo", "bal",
|
||||
// ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
|
||||
//const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
|
||||
//ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
|
||||
}
|
||||
|
||||
if (Options & EOptionMemoryLeakMode)
|
||||
glslang::OS_DumpMemoryCounters();
|
||||
}
|
||||
|
||||
delete [] lengths;
|
||||
FreeFileData(shaderStrings);
|
||||
|
||||
if (ret == 0)
|
||||
CompileFailed = true;
|
||||
}
|
||||
|
||||
//
|
||||
// print usage to stdout
|
||||
//
|
||||
void usage()
|
||||
{
|
||||
printf("Usage: glslangValidator [option]... [file]...\n"
|
||||
"\n"
|
||||
"Where: each 'file' ends in .<stage>, where <stage> is one of\n"
|
||||
" .conf to provide an optional config file that replaces the default configuration\n"
|
||||
" (see -c option below for generating a template)\n"
|
||||
" .vert for a vertex shader\n"
|
||||
" .tesc for a tessellation control shader\n"
|
||||
" .tese for a tessellation evaluation shader\n"
|
||||
" .geom for a geometry shader\n"
|
||||
" .frag for a fragment shader\n"
|
||||
" .comp for a compute shader\n"
|
||||
"\n"
|
||||
"Compilation warnings and errors will be printed to stdout.\n"
|
||||
"\n"
|
||||
"To get other information, use one of the following options:\n"
|
||||
"Each option must be specified separately.\n"
|
||||
" -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
|
||||
" default file name is <stage>.spv (-o overrides this)\n"
|
||||
" -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
|
||||
" default file name is <stage>.spv (-o overrides this)\n"
|
||||
" -H print human readable form of SPIR-V; turns on -V\n"
|
||||
" -E print pre-processed GLSL; cannot be used with -l;\n"
|
||||
" errors will appear on stderr.\n"
|
||||
" -c configuration dump;\n"
|
||||
" creates the default configuration file (redirect to a .conf file)\n"
|
||||
" -C cascading errors; risks crashes from accumulation of error recoveries\n"
|
||||
" -d default to desktop (#version 110) when there is no shader #version\n"
|
||||
" (default is ES version 100)\n"
|
||||
" -D input is HLSL\n"
|
||||
" -e specify entry-point name\n"
|
||||
" -h print this usage message\n"
|
||||
" -i intermediate tree (glslang AST) is printed out\n"
|
||||
" -l link all input files together to form a single module\n"
|
||||
" -m memory leak mode\n"
|
||||
" -o <file> save binary to <file>, requires a binary option (e.g., -V)\n"
|
||||
" -q dump reflection query database\n"
|
||||
" -r relaxed semantic error-checking mode\n"
|
||||
" -s silent mode\n"
|
||||
" -t multi-threaded mode\n"
|
||||
" -v print version strings\n"
|
||||
" -w suppress warnings (except as required by #extension : warn)\n"
|
||||
" -x save 32-bit hexadecimal numbers as text, requires a binary option (e.g., -V)\n"
|
||||
);
|
||||
|
||||
exit(EFailUsage);
|
||||
}
|
||||
|
||||
#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
int fopen_s(
|
||||
FILE** pFile,
|
||||
const char* filename,
|
||||
const char* mode
|
||||
)
|
||||
{
|
||||
if (!pFile || !filename || !mode) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
FILE* f = fopen(filename, mode);
|
||||
if (! f) {
|
||||
if (errno != 0) {
|
||||
return errno;
|
||||
} else {
|
||||
return ENOENT;
|
||||
}
|
||||
}
|
||||
*pFile = f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Malloc a string of sufficient size and read a string into it.
|
||||
//
|
||||
char** ReadFileData(const char* fileName)
|
||||
{
|
||||
FILE *in = nullptr;
|
||||
int errorCode = fopen_s(&in, fileName, "r");
|
||||
|
||||
int count = 0;
|
||||
const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
|
||||
char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
|
||||
|
||||
if (errorCode || in == nullptr)
|
||||
Error("unable to open input file");
|
||||
|
||||
while (fgetc(in) != EOF)
|
||||
count++;
|
||||
|
||||
fseek(in, 0, SEEK_SET);
|
||||
|
||||
char *fdata = (char*)malloc(count+2); // freed before return of this function
|
||||
if (! fdata)
|
||||
Error("can't allocate memory");
|
||||
|
||||
if ((int)fread(fdata, 1, count, in) != count) {
|
||||
free(fdata);
|
||||
Error("can't read input file");
|
||||
}
|
||||
|
||||
fdata[count] = '\0';
|
||||
fclose(in);
|
||||
|
||||
if (count == 0) {
|
||||
// recover from empty file
|
||||
return_data[0] = (char*)malloc(count+2); // freed in FreeFileData()
|
||||
return_data[0][0]='\0';
|
||||
NumShaderStrings = 0;
|
||||
free(fdata);
|
||||
|
||||
return return_data;
|
||||
} else
|
||||
NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings
|
||||
|
||||
// compute how to split up the file into multiple strings, for testing multiple strings
|
||||
int len = (int)(ceil)((float)count/(float)NumShaderStrings);
|
||||
int ptr_len = 0;
|
||||
int i = 0;
|
||||
while (count > 0) {
|
||||
return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData()
|
||||
memcpy(return_data[i], fdata + ptr_len, len);
|
||||
return_data[i][len] = '\0';
|
||||
count -= len;
|
||||
ptr_len += len;
|
||||
if (count < len) {
|
||||
if (count == 0) {
|
||||
NumShaderStrings = i + 1;
|
||||
break;
|
||||
}
|
||||
len = count;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
free(fdata);
|
||||
|
||||
return return_data;
|
||||
}
|
||||
|
||||
void FreeFileData(char** data)
|
||||
{
|
||||
for(int i = 0; i < NumShaderStrings; i++)
|
||||
free(data[i]);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
void InfoLogMsg(const char* msg, const char* name, const int num)
|
||||
{
|
||||
if (num >= 0 )
|
||||
printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
|
||||
else
|
||||
printf("#### %s %s INFO LOG ####\n", msg, name);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifndef WORKLIST_H_INCLUDED
|
||||
#define WORKLIST_H_INCLUDED
|
||||
|
||||
#include "../glslang/OSDependent/osinclude.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TWorkItem {
|
||||
public:
|
||||
TWorkItem() { }
|
||||
explicit TWorkItem(const std::string& s) :
|
||||
name(s) { }
|
||||
std::string name;
|
||||
std::string results;
|
||||
std::string resultsIndex;
|
||||
};
|
||||
|
||||
class TWorklist {
|
||||
public:
|
||||
TWorklist() { }
|
||||
virtual ~TWorklist() { }
|
||||
|
||||
void add(TWorkItem* item)
|
||||
{
|
||||
GetGlobalLock();
|
||||
|
||||
worklist.push_back(item);
|
||||
|
||||
ReleaseGlobalLock();
|
||||
}
|
||||
|
||||
bool remove(TWorkItem*& item)
|
||||
{
|
||||
GetGlobalLock();
|
||||
|
||||
if (worklist.empty())
|
||||
return false;
|
||||
item = worklist.front();
|
||||
worklist.pop_front();
|
||||
|
||||
ReleaseGlobalLock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
return (int)worklist.size();
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return worklist.empty();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::list<TWorkItem*> worklist;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // WORKLIST_H_INCLUDED
|
|
@ -0,0 +1,344 @@
|
|||
//
|
||||
//Copyright (C) 2015 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../SPIRV/SPVRemapper.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef unsigned int SpvWord;
|
||||
|
||||
// Poor man's basename: given a complete path, return file portion.
|
||||
// E.g:
|
||||
// Linux: /foo/bar/test -> test
|
||||
// Win: c:\foo\bar\test -> test
|
||||
// It's not very efficient, but that doesn't matter for our minimal-duty use.
|
||||
// Using boost::filesystem would be better in many ways, but want to avoid that dependency.
|
||||
|
||||
// OS dependent path separator (avoiding boost::filesystem dependency)
|
||||
#if defined(_WIN32)
|
||||
char path_sep_char() { return '\\'; }
|
||||
#else
|
||||
char path_sep_char() { return '/'; }
|
||||
#endif
|
||||
|
||||
std::string basename(const std::string filename)
|
||||
{
|
||||
const size_t sepLoc = filename.find_last_of(path_sep_char());
|
||||
|
||||
return (sepLoc == filename.npos) ? filename : filename.substr(sepLoc+1);
|
||||
}
|
||||
|
||||
void errHandler(const std::string& str) {
|
||||
std::cout << str << std::endl;
|
||||
exit(5);
|
||||
}
|
||||
|
||||
void logHandler(const std::string& str) {
|
||||
std::cout << str << std::endl;
|
||||
}
|
||||
|
||||
// Read word stream from disk
|
||||
void read(std::vector<SpvWord>& spv, const std::string& inFilename, int verbosity)
|
||||
{
|
||||
std::ifstream fp;
|
||||
|
||||
if (verbosity > 0)
|
||||
logHandler(std::string(" reading: ") + inFilename);
|
||||
|
||||
spv.clear();
|
||||
fp.open(inFilename, std::fstream::in | std::fstream::binary);
|
||||
|
||||
if (fp.fail())
|
||||
errHandler("error opening file for read: ");
|
||||
|
||||
// Reserve space (for efficiency, not for correctness)
|
||||
fp.seekg(0, fp.end);
|
||||
spv.reserve(size_t(fp.tellg()) / sizeof(SpvWord));
|
||||
fp.seekg(0, fp.beg);
|
||||
|
||||
while (!fp.eof()) {
|
||||
SpvWord inWord;
|
||||
fp.read((char *)&inWord, sizeof(inWord));
|
||||
|
||||
if (!fp.eof()) {
|
||||
spv.push_back(inWord);
|
||||
if (fp.fail())
|
||||
errHandler(std::string("error reading file: ") + inFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write(std::vector<SpvWord>& spv, const std::string& outFile, int verbosity)
|
||||
{
|
||||
if (outFile.empty())
|
||||
errHandler("missing output filename.");
|
||||
|
||||
std::ofstream fp;
|
||||
|
||||
if (verbosity > 0)
|
||||
logHandler(std::string(" writing: ") + outFile);
|
||||
|
||||
fp.open(outFile, std::fstream::out | std::fstream::binary);
|
||||
|
||||
if (fp.fail())
|
||||
errHandler(std::string("error opening file for write: ") + outFile);
|
||||
|
||||
for (auto it = spv.cbegin(); it != spv.cend(); ++it) {
|
||||
SpvWord word = *it;
|
||||
fp.write((char *)&word, sizeof(word));
|
||||
if (fp.fail())
|
||||
errHandler(std::string("error writing file: ") + outFile);
|
||||
}
|
||||
|
||||
// file is closed by destructor
|
||||
}
|
||||
|
||||
// Print helpful usage message to stdout, and exit
|
||||
void usage(const char* const name, const char* const msg = 0)
|
||||
{
|
||||
if (msg)
|
||||
std::cout << msg << std::endl << std::endl;
|
||||
|
||||
std::cout << "Usage: " << std::endl;
|
||||
|
||||
std::cout << " " << basename(name)
|
||||
<< " [-v[v[...]] | --verbose [int]]"
|
||||
<< " [--map (all|types|names|funcs)]"
|
||||
<< " [--dce (all|types|funcs)]"
|
||||
<< " [--opt (all|loadstore)]"
|
||||
<< " [--strip-all | --strip all | -s]"
|
||||
<< " [--do-everything]"
|
||||
<< " --input | -i file1 [file2...] --output|-o DESTDIR"
|
||||
<< std::endl;
|
||||
|
||||
std::cout << " " << basename(name) << " [--version | -V]" << std::endl;
|
||||
std::cout << " " << basename(name) << " [--help | -?]" << std::endl;
|
||||
|
||||
exit(5);
|
||||
}
|
||||
|
||||
// grind through each SPIR in turn
|
||||
void execute(const std::vector<std::string>& inputFile, const std::string& outputDir,
|
||||
int opts, int verbosity)
|
||||
{
|
||||
for (auto it = inputFile.cbegin(); it != inputFile.cend(); ++it) {
|
||||
const std::string &filename = *it;
|
||||
std::vector<SpvWord> spv;
|
||||
read(spv, filename, verbosity);
|
||||
spv::spirvbin_t(verbosity).remap(spv, opts);
|
||||
|
||||
const std::string outfile = outputDir + path_sep_char() + basename(filename);
|
||||
|
||||
write(spv, outfile, verbosity);
|
||||
}
|
||||
|
||||
if (verbosity > 0)
|
||||
std::cout << "Done: " << inputFile.size() << " file(s) processed" << std::endl;
|
||||
}
|
||||
|
||||
// Parse command line options
|
||||
void parseCmdLine(int argc, char** argv, std::vector<std::string>& inputFile,
|
||||
std::string& outputDir,
|
||||
int& options,
|
||||
int& verbosity)
|
||||
{
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
verbosity = 0;
|
||||
options = spv::spirvbin_t::NONE;
|
||||
|
||||
// Parse command line.
|
||||
// boost::program_options would be quite a bit nicer, but we don't want to
|
||||
// introduce a dependency on boost.
|
||||
for (int a=1; a<argc; ) {
|
||||
const std::string arg = argv[a];
|
||||
|
||||
if (arg == "--output" || arg == "-o") {
|
||||
// Output directory
|
||||
if (++a >= argc)
|
||||
usage(argv[0], "--output requires an argument");
|
||||
if (!outputDir.empty())
|
||||
usage(argv[0], "--output can be provided only once");
|
||||
|
||||
outputDir = argv[a++];
|
||||
|
||||
// Remove trailing directory separator characters
|
||||
while (!outputDir.empty() && outputDir.back() == path_sep_char())
|
||||
outputDir.pop_back();
|
||||
|
||||
}
|
||||
else if (arg == "-vv") { verbosity = 2; ++a; } // verbosity shortcuts
|
||||
else if (arg == "-vvv") { verbosity = 3; ++a; } // ...
|
||||
else if (arg == "-vvvv") { verbosity = 4; ++a; } // ...
|
||||
else if (arg == "-vvvvv") { verbosity = 5; ++a; } // ...
|
||||
|
||||
else if (arg == "--verbose" || arg == "-v") {
|
||||
++a;
|
||||
verbosity = 1;
|
||||
|
||||
if (a < argc) {
|
||||
char* end_ptr = 0;
|
||||
int verb = ::strtol(argv[a], &end_ptr, 10);
|
||||
// If we have not read to the end of the string or
|
||||
// the string contained no elements, then we do not want to
|
||||
// store the value.
|
||||
if (*end_ptr == '\0' && end_ptr != argv[a]) {
|
||||
verbosity = verb;
|
||||
++a;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (arg == "--version" || arg == "-V") {
|
||||
std::cout << basename(argv[0]) << " version 0.97 " << __DATE__ << " " << __TIME__ << std::endl;
|
||||
exit(0);
|
||||
} else if (arg == "--input" || arg == "-i") {
|
||||
// Collect input files
|
||||
for (++a; a < argc && argv[a][0] != '-'; ++a)
|
||||
inputFile.push_back(argv[a]);
|
||||
} else if (arg == "--do-everything") {
|
||||
++a;
|
||||
options = options | spv::spirvbin_t::DO_EVERYTHING;
|
||||
} else if (arg == "--strip-all" || arg == "-s") {
|
||||
++a;
|
||||
options = options | spv::spirvbin_t::STRIP;
|
||||
} else if (arg == "--strip") {
|
||||
++a;
|
||||
if (strncmp(argv[a], "all", 3) == 0) {
|
||||
options = options | spv::spirvbin_t::STRIP;
|
||||
++a;
|
||||
}
|
||||
} else if (arg == "--dce") {
|
||||
// Parse comma (or colon, etc) separated list of things to dce
|
||||
++a;
|
||||
for (const char* c = argv[a]; *c; ++c) {
|
||||
if (strncmp(c, "all", 3) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_ALL);
|
||||
c += 3;
|
||||
} else if (strncmp(c, "*", 1) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_ALL);
|
||||
c += 1;
|
||||
} else if (strncmp(c, "funcs", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_FUNCS);
|
||||
c += 5;
|
||||
} else if (strncmp(c, "types", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::DCE_TYPES);
|
||||
c += 5;
|
||||
}
|
||||
}
|
||||
++a;
|
||||
} else if (arg == "--map") {
|
||||
// Parse comma (or colon, etc) separated list of things to map
|
||||
++a;
|
||||
for (const char* c = argv[a]; *c; ++c) {
|
||||
if (strncmp(c, "all", 3) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_ALL);
|
||||
c += 3;
|
||||
} else if (strncmp(c, "*", 1) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_ALL);
|
||||
c += 1;
|
||||
} else if (strncmp(c, "types", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_TYPES);
|
||||
c += 5;
|
||||
} else if (strncmp(c, "names", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_NAMES);
|
||||
c += 5;
|
||||
} else if (strncmp(c, "funcs", 5) == 0) {
|
||||
options = (options | spv::spirvbin_t::MAP_FUNCS);
|
||||
c += 5;
|
||||
}
|
||||
}
|
||||
++a;
|
||||
} else if (arg == "--opt") {
|
||||
++a;
|
||||
for (const char* c = argv[a]; *c; ++c) {
|
||||
if (strncmp(c, "all", 3) == 0) {
|
||||
options = (options | spv::spirvbin_t::OPT_ALL);
|
||||
c += 3;
|
||||
} else if (strncmp(c, "*", 1) == 0) {
|
||||
options = (options | spv::spirvbin_t::OPT_ALL);
|
||||
c += 1;
|
||||
} else if (strncmp(c, "loadstore", 9) == 0) {
|
||||
options = (options | spv::spirvbin_t::OPT_LOADSTORE);
|
||||
c += 9;
|
||||
}
|
||||
}
|
||||
++a;
|
||||
} else if (arg == "--help" || arg == "-?") {
|
||||
usage(argv[0]);
|
||||
} else {
|
||||
usage(argv[0], "Unknown command line option");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::vector<std::string> inputFile;
|
||||
std::string outputDir;
|
||||
int opts;
|
||||
int verbosity;
|
||||
|
||||
#ifdef use_cpp11
|
||||
// handle errors by exiting
|
||||
spv::spirvbin_t::registerErrorHandler(errHandler);
|
||||
|
||||
// Log messages to std::cout
|
||||
spv::spirvbin_t::registerLogHandler(logHandler);
|
||||
#endif
|
||||
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
parseCmdLine(argc, argv, inputFile, outputDir, opts, verbosity);
|
||||
|
||||
if (outputDir.empty())
|
||||
usage(argv[0], "Output directory required");
|
||||
|
||||
std::string errmsg;
|
||||
|
||||
// Main operations: read, remap, and write.
|
||||
execute(inputFile, outputDir, opts, verbosity);
|
||||
|
||||
// If we get here, everything went OK! Nothing more to be done.
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D178061B-84D3-44F9-BEED-EFD18D9033F0}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\Source\VSProps\Base.props" />
|
||||
<Import Project="..\..\Source\VSProps\ClDisableAllWarnings.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile />
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="glslang\GenericCodeGen\CodeGen.cpp" />
|
||||
<ClCompile Include="glslang\GenericCodeGen\Link.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\Constant.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\glslang_tab.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\InfoSink.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\Initialize.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\Intermediate.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\intermOut.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\IntermTraverse.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\limits.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\linkValidate.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\parseConst.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\ParseHelper.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\PoolAlloc.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\Pp.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpAtom.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpContext.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpMemory.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpScanner.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpSymbols.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpTokens.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\propagateNoContraction.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\reflection.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\RemoveTree.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\Scan.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\ShaderLang.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\SymbolTable.cpp" />
|
||||
<ClCompile Include="glslang\MachineIndependent\Versions.cpp" />
|
||||
<ClCompile Include="glslang\OSDependent\Windows\ossource.cpp" />
|
||||
<ClCompile Include="hlsl\hlslGrammar.cpp" />
|
||||
<ClCompile Include="hlsl\hlslOpMap.cpp" />
|
||||
<ClCompile Include="hlsl\hlslParseables.cpp" />
|
||||
<ClCompile Include="hlsl\hlslParseHelper.cpp" />
|
||||
<ClCompile Include="hlsl\hlslScanContext.cpp" />
|
||||
<ClCompile Include="hlsl\hlslTokenStream.cpp" />
|
||||
<ClCompile Include="OGLCompilersDLL\InitializeDll.cpp" />
|
||||
<ClCompile Include="SPIRV\disassemble.cpp" />
|
||||
<ClCompile Include="SPIRV\doc.cpp" />
|
||||
<ClCompile Include="SPIRV\GlslangToSpv.cpp" />
|
||||
<ClCompile Include="SPIRV\InReadableOrder.cpp" />
|
||||
<ClCompile Include="SPIRV\Logger.cpp" />
|
||||
<ClCompile Include="SPIRV\SpvBuilder.cpp" />
|
||||
<ClCompile Include="SPIRV\SPVRemapper.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="glslang\Include\arrays.h" />
|
||||
<ClInclude Include="glslang\Include\BaseTypes.h" />
|
||||
<ClInclude Include="glslang\Include\Common.h" />
|
||||
<ClInclude Include="glslang\Include\ConstantUnion.h" />
|
||||
<ClInclude Include="glslang\Include\InfoSink.h" />
|
||||
<ClInclude Include="glslang\Include\InitializeGlobals.h" />
|
||||
<ClInclude Include="glslang\Include\intermediate.h" />
|
||||
<ClInclude Include="glslang\Include\PoolAlloc.h" />
|
||||
<ClInclude Include="glslang\Include\ResourceLimits.h" />
|
||||
<ClInclude Include="glslang\Include\revision.h" />
|
||||
<ClInclude Include="glslang\Include\ShHandle.h" />
|
||||
<ClInclude Include="glslang\Include\Types.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\glslang_tab.cpp.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\gl_types.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\Initialize.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\localintermediate.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\ParseHelper.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\parseVersions.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpContext.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpTokens.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\propagateNoContraction.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\reflection.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\RemoveTree.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\Scan.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\ScanContext.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\SymbolTable.h" />
|
||||
<ClInclude Include="glslang\MachineIndependent\Versions.h" />
|
||||
<ClInclude Include="glslang\OSDependent\osinclude.h" />
|
||||
<ClInclude Include="glslang\Public\ShaderLang.h" />
|
||||
<ClInclude Include="hlsl\hlslGrammar.h" />
|
||||
<ClInclude Include="hlsl\hlslOpMap.h" />
|
||||
<ClInclude Include="hlsl\hlslParseables.h" />
|
||||
<ClInclude Include="hlsl\hlslParseHelper.h" />
|
||||
<ClInclude Include="hlsl\hlslScanContext.h" />
|
||||
<ClInclude Include="hlsl\hlslTokens.h" />
|
||||
<ClInclude Include="hlsl\hlslTokenStream.h" />
|
||||
<ClInclude Include="OGLCompilersDLL\InitializeDll.h" />
|
||||
<ClInclude Include="SPIRV\disassemble.h" />
|
||||
<ClInclude Include="SPIRV\doc.h" />
|
||||
<ClInclude Include="SPIRV\GLSL.std.450.h" />
|
||||
<ClInclude Include="SPIRV\GlslangToSpv.h" />
|
||||
<ClInclude Include="SPIRV\Logger.h" />
|
||||
<ClInclude Include="SPIRV\spirv.hpp" />
|
||||
<ClInclude Include="SPIRV\SpvBuilder.h" />
|
||||
<ClInclude Include="SPIRV\spvIR.h" />
|
||||
<ClInclude Include="SPIRV\SPVRemapper.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="glslang\MachineIndependent\glslang.y" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,314 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="glslang\GenericCodeGen\Link.cpp">
|
||||
<Filter>glslang\GenericCodeGen</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\GenericCodeGen\CodeGen.cpp">
|
||||
<Filter>glslang\GenericCodeGen</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpMemory.cpp">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpScanner.cpp">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpSymbols.cpp">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpTokens.cpp">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\Pp.cpp">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpAtom.cpp">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\preprocessor\PpContext.cpp">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\linkValidate.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\parseConst.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\ParseHelper.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\PoolAlloc.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\propagateNoContraction.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\reflection.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\RemoveTree.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\Scan.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\ShaderLang.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\SymbolTable.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\Versions.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\Constant.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\glslang_tab.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\InfoSink.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\Initialize.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\Intermediate.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\intermOut.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\IntermTraverse.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\MachineIndependent\limits.cpp">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="glslang\OSDependent\Windows\ossource.cpp">
|
||||
<Filter>glslang\OSDependant\Windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPIRV\disassemble.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPIRV\doc.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPIRV\GlslangToSpv.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPIRV\InReadableOrder.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPIRV\Logger.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPIRV\SpvBuilder.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPIRV\SPVRemapper.cpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OGLCompilersDLL\InitializeDll.cpp">
|
||||
<Filter>OGLCompilersDLL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hlsl\hlslGrammar.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hlsl\hlslOpMap.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hlsl\hlslParseHelper.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hlsl\hlslScanContext.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hlsl\hlslTokenStream.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hlsl\hlslParseables.cpp">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="glslang\Include\ResourceLimits.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\revision.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\ShHandle.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\Types.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\arrays.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\BaseTypes.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\Common.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\ConstantUnion.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\InfoSink.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\InitializeGlobals.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\intermediate.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Include\PoolAlloc.h">
|
||||
<Filter>glslang\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpTokens.h">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\preprocessor\PpContext.h">
|
||||
<Filter>glslang\MachineIndependant\preprocessor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\localintermediate.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\ParseHelper.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\parseVersions.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\propagateNoContraction.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\reflection.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\RemoveTree.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\Scan.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\ScanContext.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\SymbolTable.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\Versions.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\gl_types.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\glslang_tab.cpp.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\MachineIndependent\Initialize.h">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\OSDependent\osinclude.h">
|
||||
<Filter>glslang\OSDependant</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="glslang\Public\ShaderLang.h">
|
||||
<Filter>glslang\Public</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\disassemble.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\doc.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\GLSL.std.450.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\GlslangToSpv.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\Logger.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\spirv.hpp">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\SpvBuilder.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\spvIR.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPIRV\SPVRemapper.h">
|
||||
<Filter>SPIRV</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="OGLCompilersDLL\InitializeDll.h">
|
||||
<Filter>OGLCompilersDLL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hlsl\hlslGrammar.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hlsl\hlslOpMap.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hlsl\hlslParseHelper.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hlsl\hlslScanContext.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hlsl\hlslTokens.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hlsl\hlslTokenStream.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hlsl\hlslParseables.h">
|
||||
<Filter>hlsl</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="glslang">
|
||||
<UniqueIdentifier>{db97e1d9-0167-4edb-aafa-014e7665f3c5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="glslang\GenericCodeGen">
|
||||
<UniqueIdentifier>{ae01ec32-293d-4e09-8aea-332c674ef241}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="glslang\Include">
|
||||
<UniqueIdentifier>{db69a576-d7c3-481d-a797-2354bef22bd5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="glslang\MachineIndependant">
|
||||
<UniqueIdentifier>{b7e827ac-1697-4e77-abe6-52150f596ce5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="glslang\MachineIndependant\preprocessor">
|
||||
<UniqueIdentifier>{a200048e-0cb6-4956-8fad-bb52028afac8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="glslang\OSDependant">
|
||||
<UniqueIdentifier>{a0f753df-15b7-4e16-8c6d-8daf3a1e66e5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="glslang\OSDependant\Windows">
|
||||
<UniqueIdentifier>{6f437e9d-50ed-4718-bebf-04f160e566fc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="glslang\Public">
|
||||
<UniqueIdentifier>{5e2647de-0d48-444a-8952-faec9336aa04}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="SPIRV">
|
||||
<UniqueIdentifier>{7039de2e-63ef-409d-a895-3c0dd307e201}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="hlsl">
|
||||
<UniqueIdentifier>{e465129b-44ff-46e1-b876-76c529f3a945}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="OGLCompilersDLL">
|
||||
<UniqueIdentifier>{8d950cfc-7fb5-4612-b23c-f4d569404955}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="glslang\MachineIndependent\glslang.y">
|
||||
<Filter>glslang\MachineIndependant</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,91 @@
|
|||
if(WIN32)
|
||||
add_subdirectory(OSDependent/Windows)
|
||||
elseif(UNIX)
|
||||
add_subdirectory(OSDependent/Unix)
|
||||
else(WIN32)
|
||||
message("unknown platform")
|
||||
endif(WIN32)
|
||||
|
||||
set(SOURCES
|
||||
MachineIndependent/glslang.y
|
||||
MachineIndependent/glslang_tab.cpp
|
||||
MachineIndependent/Constant.cpp
|
||||
MachineIndependent/InfoSink.cpp
|
||||
MachineIndependent/Initialize.cpp
|
||||
MachineIndependent/IntermTraverse.cpp
|
||||
MachineIndependent/Intermediate.cpp
|
||||
MachineIndependent/ParseHelper.cpp
|
||||
MachineIndependent/PoolAlloc.cpp
|
||||
MachineIndependent/RemoveTree.cpp
|
||||
MachineIndependent/Scan.cpp
|
||||
MachineIndependent/ShaderLang.cpp
|
||||
MachineIndependent/SymbolTable.cpp
|
||||
MachineIndependent/Versions.cpp
|
||||
MachineIndependent/intermOut.cpp
|
||||
MachineIndependent/limits.cpp
|
||||
MachineIndependent/linkValidate.cpp
|
||||
MachineIndependent/parseConst.cpp
|
||||
MachineIndependent/reflection.cpp
|
||||
MachineIndependent/preprocessor/Pp.cpp
|
||||
MachineIndependent/preprocessor/PpAtom.cpp
|
||||
MachineIndependent/preprocessor/PpContext.cpp
|
||||
MachineIndependent/preprocessor/PpMemory.cpp
|
||||
MachineIndependent/preprocessor/PpScanner.cpp
|
||||
MachineIndependent/preprocessor/PpSymbols.cpp
|
||||
MachineIndependent/preprocessor/PpTokens.cpp
|
||||
MachineIndependent/propagateNoContraction.cpp
|
||||
GenericCodeGen/CodeGen.cpp
|
||||
GenericCodeGen/Link.cpp)
|
||||
|
||||
set(HEADERS
|
||||
Public/ShaderLang.h
|
||||
Include/arrays.h
|
||||
Include/BaseTypes.h
|
||||
Include/Common.h
|
||||
Include/ConstantUnion.h
|
||||
Include/InfoSink.h
|
||||
Include/InitializeGlobals.h
|
||||
Include/intermediate.h
|
||||
Include/PoolAlloc.h
|
||||
Include/ResourceLimits.h
|
||||
Include/revision.h
|
||||
Include/ShHandle.h
|
||||
Include/Types.h
|
||||
MachineIndependent/glslang_tab.cpp.h
|
||||
MachineIndependent/gl_types.h
|
||||
MachineIndependent/Initialize.h
|
||||
MachineIndependent/localintermediate.h
|
||||
MachineIndependent/ParseHelper.h
|
||||
MachineIndependent/reflection.h
|
||||
MachineIndependent/RemoveTree.h
|
||||
MachineIndependent/Scan.h
|
||||
MachineIndependent/ScanContext.h
|
||||
MachineIndependent/SymbolTable.h
|
||||
MachineIndependent/Versions.h
|
||||
MachineIndependent/parseVersions.h
|
||||
MachineIndependent/propagateNoContraction.h
|
||||
MachineIndependent/preprocessor/PpContext.h
|
||||
MachineIndependent/preprocessor/PpTokens.h)
|
||||
|
||||
# This might be useful for making grammar changes:
|
||||
#
|
||||
# find_package(BISON)
|
||||
# add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp.h
|
||||
# COMMAND ${BISON_EXECUTABLE} --defines=${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp.h -t ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang.y -o ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp
|
||||
# MAIN_DEPENDENCY MachineIndependent/glslang.y
|
||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
# set(BISON_GLSLParser_OUTPUT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/MachineIndependent/glslang_tab.cpp)
|
||||
|
||||
add_library(glslang STATIC ${BISON_GLSLParser_OUTPUT_SOURCE} ${SOURCES} ${HEADERS})
|
||||
set_property(TARGET glslang PROPERTY FOLDER glslang)
|
||||
|
||||
if(WIN32)
|
||||
source_group("Public" REGULAR_EXPRESSION "Public/*")
|
||||
source_group("MachineIndependent" REGULAR_EXPRESSION "MachineIndependent/[^/]*")
|
||||
source_group("Include" REGULAR_EXPRESSION "Include/[^/]*")
|
||||
source_group("GenericCodeGen" REGULAR_EXPRESSION "GenericCodeGen/*")
|
||||
source_group("MachineIndependent\\Preprocessor" REGULAR_EXPRESSION "MachineIndependent/preprocessor/*")
|
||||
endif(WIN32)
|
||||
|
||||
install(TARGETS glslang
|
||||
ARCHIVE DESTINATION lib)
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/ShHandle.h"
|
||||
#include "../MachineIndependent/Versions.h"
|
||||
|
||||
//
|
||||
// Here is where real machine specific high-level data would be defined.
|
||||
//
|
||||
class TGenericCompiler : public TCompiler {
|
||||
public:
|
||||
TGenericCompiler(EShLanguage l, int dOptions) : TCompiler(l, infoSink), debugOptions(dOptions) { }
|
||||
virtual bool compile(TIntermNode* root, int version = 0, EProfile profile = ENoProfile);
|
||||
TInfoSink infoSink;
|
||||
int debugOptions;
|
||||
};
|
||||
|
||||
//
|
||||
// This function must be provided to create the actual
|
||||
// compile object used by higher level code. It returns
|
||||
// a subclass of TCompiler.
|
||||
//
|
||||
TCompiler* ConstructCompiler(EShLanguage language, int debugOptions)
|
||||
{
|
||||
return new TGenericCompiler(language, debugOptions);
|
||||
}
|
||||
|
||||
//
|
||||
// Delete the compiler made by ConstructCompiler
|
||||
//
|
||||
void DeleteCompiler(TCompiler* compiler)
|
||||
{
|
||||
delete compiler;
|
||||
}
|
||||
|
||||
//
|
||||
// Generate code from the given parse tree
|
||||
//
|
||||
bool TGenericCompiler::compile(TIntermNode* /*root*/, int /*version*/, EProfile /*profile*/)
|
||||
{
|
||||
haveValidObjectCode = true;
|
||||
|
||||
return haveValidObjectCode;
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// The top level algorithms for linking multiple
|
||||
// shaders together.
|
||||
//
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/ShHandle.h"
|
||||
|
||||
//
|
||||
// Actual link object, derived from the shader handle base classes.
|
||||
//
|
||||
class TGenericLinker : public TLinker {
|
||||
public:
|
||||
TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { }
|
||||
bool link(TCompilerList&, TUniformMap*) { return true; }
|
||||
void getAttributeBindings(ShBindingTable const **) const { }
|
||||
TInfoSink infoSink;
|
||||
int debugOptions;
|
||||
};
|
||||
|
||||
//
|
||||
// The internal view of a uniform/float object exchanged with the driver.
|
||||
//
|
||||
class TUniformLinkedMap : public TUniformMap {
|
||||
public:
|
||||
TUniformLinkedMap() { }
|
||||
virtual int getLocation(const char*) { return 0; }
|
||||
};
|
||||
|
||||
TShHandleBase* ConstructLinker(EShExecutable executable, int debugOptions)
|
||||
{
|
||||
return new TGenericLinker(executable, debugOptions);
|
||||
}
|
||||
|
||||
void DeleteLinker(TShHandleBase* linker)
|
||||
{
|
||||
delete linker;
|
||||
}
|
||||
|
||||
TUniformMap* ConstructUniformMap()
|
||||
{
|
||||
return new TUniformLinkedMap();
|
||||
}
|
||||
|
||||
void DeleteUniformMap(TUniformMap* map)
|
||||
{
|
||||
delete map;
|
||||
}
|
||||
|
||||
TShHandleBase* ConstructBindings()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeleteBindingList(TShHandleBase* bindingList)
|
||||
{
|
||||
delete bindingList;
|
||||
}
|
|
@ -0,0 +1,315 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _BASICTYPES_INCLUDED_
|
||||
#define _BASICTYPES_INCLUDED_
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Basic type. Arrays, vectors, sampler details, etc., are orthogonal to this.
|
||||
//
|
||||
enum TBasicType {
|
||||
EbtVoid,
|
||||
EbtFloat,
|
||||
EbtDouble,
|
||||
EbtInt,
|
||||
EbtUint,
|
||||
EbtInt64,
|
||||
EbtUint64,
|
||||
EbtBool,
|
||||
EbtAtomicUint,
|
||||
EbtSampler,
|
||||
EbtStruct,
|
||||
EbtBlock,
|
||||
EbtNumTypes
|
||||
};
|
||||
|
||||
//
|
||||
// Storage qualifiers. Should align with different kinds of storage or
|
||||
// resource or GLSL storage qualifier. Expansion is deprecated.
|
||||
//
|
||||
// N.B.: You probably DON'T want to add anything here, but rather just add it
|
||||
// to the built-in variables. See the comment above TBuiltInVariable.
|
||||
//
|
||||
// A new built-in variable will normally be an existing qualifier, like 'in', 'out', etc.
|
||||
// DO NOT follow the design pattern of, say EvqInstanceId, etc.
|
||||
//
|
||||
enum TStorageQualifier {
|
||||
EvqTemporary, // For temporaries (within a function), read/write
|
||||
EvqGlobal, // For globals read/write
|
||||
EvqConst, // User-defined constant values, will be semantically constant and constant folded
|
||||
EvqVaryingIn, // pipeline input, read only, also supercategory for all built-ins not included in this enum (see TBuiltInVariable)
|
||||
EvqVaryingOut, // pipeline output, read/write, also supercategory for all built-ins not included in this enum (see TBuiltInVariable)
|
||||
EvqUniform, // read only, shared with app
|
||||
EvqBuffer, // read/write, shared with app
|
||||
EvqShared, // compute shader's read/write 'shared' qualifier
|
||||
|
||||
// parameters
|
||||
EvqIn, // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter
|
||||
EvqOut, // also, for 'out' in the grammar before we know if it's a pipeline output or an 'out' parameter
|
||||
EvqInOut,
|
||||
EvqConstReadOnly, // input; also other read-only types having neither a constant value nor constant-value semantics
|
||||
|
||||
// built-ins read by vertex shader
|
||||
EvqVertexId,
|
||||
EvqInstanceId,
|
||||
|
||||
// built-ins written by vertex shader
|
||||
EvqPosition,
|
||||
EvqPointSize,
|
||||
EvqClipVertex,
|
||||
|
||||
// built-ins read by fragment shader
|
||||
EvqFace,
|
||||
EvqFragCoord,
|
||||
EvqPointCoord,
|
||||
|
||||
// built-ins written by fragment shader
|
||||
EvqFragColor,
|
||||
EvqFragDepth,
|
||||
|
||||
// end of list
|
||||
EvqLast
|
||||
};
|
||||
|
||||
//
|
||||
// Subcategories of the TStorageQualifier, simply to give a direct mapping
|
||||
// between built-in variable names and an numerical value (the enum).
|
||||
//
|
||||
// For backward compatibility, there is some redundancy between the
|
||||
// TStorageQualifier and these. Existing members should both be maintained accurately.
|
||||
// However, any new built-in variable (and any existing non-redundant one)
|
||||
// must follow the pattern that the specific built-in is here, and only its
|
||||
// general qualifier is in TStorageQualifier.
|
||||
//
|
||||
// Something like gl_Position, which is sometimes 'in' and sometimes 'out'
|
||||
// shows up as two different built-in variables in a single stage, but
|
||||
// only has a single enum in TBuiltInVariable, so both the
|
||||
// TStorageQualifier and the TBuitinVariable are needed to distinguish
|
||||
// between them.
|
||||
//
|
||||
enum TBuiltInVariable {
|
||||
EbvNone,
|
||||
EbvNumWorkGroups,
|
||||
EbvWorkGroupSize,
|
||||
EbvWorkGroupId,
|
||||
EbvLocalInvocationId,
|
||||
EbvGlobalInvocationId,
|
||||
EbvLocalInvocationIndex,
|
||||
EbvSubGroupSize,
|
||||
EbvSubGroupInvocation,
|
||||
EbvSubGroupEqMask,
|
||||
EbvSubGroupGeMask,
|
||||
EbvSubGroupGtMask,
|
||||
EbvSubGroupLeMask,
|
||||
EbvSubGroupLtMask,
|
||||
EbvVertexId,
|
||||
EbvInstanceId,
|
||||
EbvVertexIndex,
|
||||
EbvInstanceIndex,
|
||||
EbvBaseVertex,
|
||||
EbvBaseInstance,
|
||||
EbvDrawId,
|
||||
EbvPosition,
|
||||
EbvPointSize,
|
||||
EbvClipVertex,
|
||||
EbvClipDistance,
|
||||
EbvCullDistance,
|
||||
EbvNormal,
|
||||
EbvVertex,
|
||||
EbvMultiTexCoord0,
|
||||
EbvMultiTexCoord1,
|
||||
EbvMultiTexCoord2,
|
||||
EbvMultiTexCoord3,
|
||||
EbvMultiTexCoord4,
|
||||
EbvMultiTexCoord5,
|
||||
EbvMultiTexCoord6,
|
||||
EbvMultiTexCoord7,
|
||||
EbvFrontColor,
|
||||
EbvBackColor,
|
||||
EbvFrontSecondaryColor,
|
||||
EbvBackSecondaryColor,
|
||||
EbvTexCoord,
|
||||
EbvFogFragCoord,
|
||||
EbvInvocationId,
|
||||
EbvPrimitiveId,
|
||||
EbvLayer,
|
||||
EbvViewportIndex,
|
||||
EbvPatchVertices,
|
||||
EbvTessLevelOuter,
|
||||
EbvTessLevelInner,
|
||||
EbvBoundingBox,
|
||||
EbvTessCoord,
|
||||
EbvColor,
|
||||
EbvSecondaryColor,
|
||||
EbvFace,
|
||||
EbvFragCoord,
|
||||
EbvPointCoord,
|
||||
EbvFragColor,
|
||||
EbvFragData,
|
||||
EbvFragDepth,
|
||||
EbvSampleId,
|
||||
EbvSamplePosition,
|
||||
EbvSampleMask,
|
||||
EbvHelperInvocation,
|
||||
|
||||
EbvLast
|
||||
};
|
||||
|
||||
// These will show up in error messages
|
||||
__inline const char* GetStorageQualifierString(TStorageQualifier q)
|
||||
{
|
||||
switch (q) {
|
||||
case EvqTemporary: return "temp"; break;
|
||||
case EvqGlobal: return "global"; break;
|
||||
case EvqConst: return "const"; break;
|
||||
case EvqConstReadOnly: return "const (read only)"; break;
|
||||
case EvqVaryingIn: return "in"; break;
|
||||
case EvqVaryingOut: return "out"; break;
|
||||
case EvqUniform: return "uniform"; break;
|
||||
case EvqBuffer: return "buffer"; break;
|
||||
case EvqShared: return "shared"; break;
|
||||
case EvqIn: return "in"; break;
|
||||
case EvqOut: return "out"; break;
|
||||
case EvqInOut: return "inout"; break;
|
||||
case EvqVertexId: return "gl_VertexId"; break;
|
||||
case EvqInstanceId: return "gl_InstanceId"; break;
|
||||
case EvqPosition: return "gl_Position"; break;
|
||||
case EvqPointSize: return "gl_PointSize"; break;
|
||||
case EvqClipVertex: return "gl_ClipVertex"; break;
|
||||
case EvqFace: return "gl_FrontFacing"; break;
|
||||
case EvqFragCoord: return "gl_FragCoord"; break;
|
||||
case EvqPointCoord: return "gl_PointCoord"; break;
|
||||
case EvqFragColor: return "fragColor"; break;
|
||||
case EvqFragDepth: return "gl_FragDepth"; break;
|
||||
default: return "unknown qualifier";
|
||||
}
|
||||
}
|
||||
|
||||
__inline const char* GetBuiltInVariableString(TBuiltInVariable v)
|
||||
{
|
||||
switch (v) {
|
||||
case EbvNone: return "";
|
||||
case EbvNumWorkGroups: return "NumWorkGroups";
|
||||
case EbvWorkGroupSize: return "WorkGroupSize";
|
||||
case EbvWorkGroupId: return "WorkGroupID";
|
||||
case EbvLocalInvocationId: return "LocalInvocationID";
|
||||
case EbvGlobalInvocationId: return "GlobalInvocationID";
|
||||
case EbvLocalInvocationIndex: return "LocalInvocationIndex";
|
||||
case EbvSubGroupSize: return "SubGroupSize";
|
||||
case EbvSubGroupInvocation: return "SubGroupInvocation";
|
||||
case EbvSubGroupEqMask: return "SubGroupEqMask";
|
||||
case EbvSubGroupGeMask: return "SubGroupGeMask";
|
||||
case EbvSubGroupGtMask: return "SubGroupGtMask";
|
||||
case EbvSubGroupLeMask: return "SubGroupLeMask";
|
||||
case EbvSubGroupLtMask: return "SubGroupLtMask";
|
||||
case EbvVertexId: return "VertexId";
|
||||
case EbvInstanceId: return "InstanceId";
|
||||
case EbvVertexIndex: return "VertexIndex";
|
||||
case EbvInstanceIndex: return "InstanceIndex";
|
||||
case EbvBaseVertex: return "BaseVertex";
|
||||
case EbvBaseInstance: return "BaseInstance";
|
||||
case EbvDrawId: return "DrawId";
|
||||
case EbvPosition: return "Position";
|
||||
case EbvPointSize: return "PointSize";
|
||||
case EbvClipVertex: return "ClipVertex";
|
||||
case EbvClipDistance: return "ClipDistance";
|
||||
case EbvCullDistance: return "CullDistance";
|
||||
case EbvNormal: return "Normal";
|
||||
case EbvVertex: return "Vertex";
|
||||
case EbvMultiTexCoord0: return "MultiTexCoord0";
|
||||
case EbvMultiTexCoord1: return "MultiTexCoord1";
|
||||
case EbvMultiTexCoord2: return "MultiTexCoord2";
|
||||
case EbvMultiTexCoord3: return "MultiTexCoord3";
|
||||
case EbvMultiTexCoord4: return "MultiTexCoord4";
|
||||
case EbvMultiTexCoord5: return "MultiTexCoord5";
|
||||
case EbvMultiTexCoord6: return "MultiTexCoord6";
|
||||
case EbvMultiTexCoord7: return "MultiTexCoord7";
|
||||
case EbvFrontColor: return "FrontColor";
|
||||
case EbvBackColor: return "BackColor";
|
||||
case EbvFrontSecondaryColor: return "FrontSecondaryColor";
|
||||
case EbvBackSecondaryColor: return "BackSecondaryColor";
|
||||
case EbvTexCoord: return "TexCoord";
|
||||
case EbvFogFragCoord: return "FogFragCoord";
|
||||
case EbvInvocationId: return "InvocationID";
|
||||
case EbvPrimitiveId: return "PrimitiveID";
|
||||
case EbvLayer: return "Layer";
|
||||
case EbvViewportIndex: return "ViewportIndex";
|
||||
case EbvPatchVertices: return "PatchVertices";
|
||||
case EbvTessLevelOuter: return "TessLevelOuter";
|
||||
case EbvTessLevelInner: return "TessLevelInner";
|
||||
case EbvBoundingBox: return "BoundingBox";
|
||||
case EbvTessCoord: return "TessCoord";
|
||||
case EbvColor: return "Color";
|
||||
case EbvSecondaryColor: return "SecondaryColor";
|
||||
case EbvFace: return "Face";
|
||||
case EbvFragCoord: return "FragCoord";
|
||||
case EbvPointCoord: return "PointCoord";
|
||||
case EbvFragColor: return "FragColor";
|
||||
case EbvFragData: return "FragData";
|
||||
case EbvFragDepth: return "FragDepth";
|
||||
case EbvSampleId: return "SampleId";
|
||||
case EbvSamplePosition: return "SamplePosition";
|
||||
case EbvSampleMask: return "SampleMaskIn";
|
||||
case EbvHelperInvocation: return "HelperInvocation";
|
||||
default: return "unknown built-in variable";
|
||||
}
|
||||
}
|
||||
|
||||
// In this enum, order matters; users can assume higher precision is a bigger value
|
||||
// and EpqNone is 0.
|
||||
enum TPrecisionQualifier {
|
||||
EpqNone = 0,
|
||||
EpqLow,
|
||||
EpqMedium,
|
||||
EpqHigh
|
||||
};
|
||||
|
||||
__inline const char* GetPrecisionQualifierString(TPrecisionQualifier p)
|
||||
{
|
||||
switch(p) {
|
||||
case EpqNone: return ""; break;
|
||||
case EpqLow: return "lowp"; break;
|
||||
case EpqMedium: return "mediump"; break;
|
||||
case EpqHigh: return "highp"; break;
|
||||
default: return "unknown precision qualifier";
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _BASICTYPES_INCLUDED_
|
|
@ -0,0 +1,257 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _COMMON_INCLUDED_
|
||||
#define _COMMON_INCLUDED_
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) || defined MINGW_HAS_SECURE_API
|
||||
#include <basetsd.h>
|
||||
#define snprintf sprintf_s
|
||||
#define safe_vsprintf(buf,max,format,args) vsnprintf_s((buf), (max), (max), (format), (args))
|
||||
#elif defined (solaris)
|
||||
#define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args))
|
||||
#include <sys/int_types.h>
|
||||
#define UINT_PTR uintptr_t
|
||||
#else
|
||||
#define safe_vsprintf(buf,max,format,args) vsnprintf((buf), (max), (format), (args))
|
||||
#include <stdint.h>
|
||||
#define UINT_PTR uintptr_t
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || _MSC_VER < 1700
|
||||
#include <sstream>
|
||||
namespace std {
|
||||
template<typename T>
|
||||
std::string to_string(const T& val) {
|
||||
std::ostringstream os;
|
||||
os << val;
|
||||
return os.str();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1700
|
||||
inline long long int strtoll (const char* str, char** endptr, int base)
|
||||
{
|
||||
return _strtoi64(str, endptr, base);
|
||||
}
|
||||
inline long long int atoll (const char* str)
|
||||
{
|
||||
return strtoll(str, NULL, 10);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* windows only pragma */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4786) // Don't warn about too long identifiers
|
||||
#pragma warning(disable : 4514) // unused inline method
|
||||
#pragma warning(disable : 4201) // nameless union
|
||||
#endif
|
||||
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "PoolAlloc.h"
|
||||
|
||||
//
|
||||
// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
|
||||
//
|
||||
#define POOL_ALLOCATOR_NEW_DELETE(A) \
|
||||
void* operator new(size_t s) { return (A).allocate(s); } \
|
||||
void* operator new(size_t, void *_Where) { return (_Where); } \
|
||||
void operator delete(void*) { } \
|
||||
void operator delete(void *, void *) { } \
|
||||
void* operator new[](size_t s) { return (A).allocate(s); } \
|
||||
void* operator new[](size_t, void *_Where) { return (_Where); } \
|
||||
void operator delete[](void*) { } \
|
||||
void operator delete[](void *, void *) { }
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Pool version of string.
|
||||
//
|
||||
typedef pool_allocator<char> TStringAllocator;
|
||||
typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString;
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
// Repackage the std::hash for use by unordered map/set with a TString key.
|
||||
namespace std {
|
||||
|
||||
template<> struct hash<glslang::TString> {
|
||||
std::size_t operator()(const glslang::TString& s) const
|
||||
{
|
||||
const unsigned _FNV_offset_basis = 2166136261U;
|
||||
const unsigned _FNV_prime = 16777619U;
|
||||
unsigned _Val = _FNV_offset_basis;
|
||||
size_t _Count = s.size();
|
||||
const char* _First = s.c_str();
|
||||
for (size_t _Next = 0; _Next < _Count; ++_Next)
|
||||
{
|
||||
_Val ^= (unsigned)_First[_Next];
|
||||
_Val *= _FNV_prime;
|
||||
}
|
||||
|
||||
return _Val;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace glslang {
|
||||
|
||||
inline TString* NewPoolTString(const char* s)
|
||||
{
|
||||
void* memory = GetThreadPoolAllocator().allocate(sizeof(TString));
|
||||
return new(memory) TString(s);
|
||||
}
|
||||
|
||||
template<class T> inline T* NewPoolObject(T)
|
||||
{
|
||||
return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
|
||||
}
|
||||
|
||||
template<class T> inline T* NewPoolObject(T, int instances)
|
||||
{
|
||||
return new(GetThreadPoolAllocator().allocate(instances * sizeof(T))) T[instances];
|
||||
}
|
||||
|
||||
//
|
||||
// Pool allocator versions of vectors, lists, and maps
|
||||
//
|
||||
template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
|
||||
typedef typename std::vector<T, pool_allocator<T> >::size_type size_type;
|
||||
TVector() : std::vector<T, pool_allocator<T> >() {}
|
||||
TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {}
|
||||
TVector(size_type i) : std::vector<T, pool_allocator<T> >(i) {}
|
||||
TVector(size_type i, const T& val) : std::vector<T, pool_allocator<T> >(i, val) {}
|
||||
};
|
||||
|
||||
template <class T> class TList : public std::list<T, pool_allocator<T> > {
|
||||
};
|
||||
|
||||
template <class K, class D, class CMP = std::less<K> >
|
||||
class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<K const, D> > > {
|
||||
};
|
||||
|
||||
template <class K, class D, class HASH = std::hash<K>, class PRED = std::equal_to<K> >
|
||||
class TUnorderedMap : public std::unordered_map<K, D, HASH, PRED, pool_allocator<std::pair<K const, D> > > {
|
||||
};
|
||||
|
||||
//
|
||||
// Persistent string memory. Should only be used for strings that survive
|
||||
// across compiles/links.
|
||||
//
|
||||
typedef std::basic_string<char> TPersistString;
|
||||
|
||||
//
|
||||
// templatized min and max functions.
|
||||
//
|
||||
template <class T> T Min(const T a, const T b) { return a < b ? a : b; }
|
||||
template <class T> T Max(const T a, const T b) { return a > b ? a : b; }
|
||||
|
||||
//
|
||||
// Create a TString object from an integer.
|
||||
//
|
||||
inline const TString String(const int i, const int base = 10)
|
||||
{
|
||||
char text[16]; // 32 bit ints are at most 10 digits in base 10
|
||||
|
||||
#if defined _MSC_VER || defined MINGW_HAS_SECURE_API
|
||||
_itoa_s(i, text, sizeof(text), base);
|
||||
#else
|
||||
// we assume base 10 for all cases
|
||||
snprintf(text, sizeof(text), "%d", i);
|
||||
#endif
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
struct TSourceLoc {
|
||||
void init() { name = nullptr; string = 0; line = 0; column = 0; }
|
||||
// Returns the name if it exists. Otherwise, returns the string number.
|
||||
std::string getStringNameOrNum(bool quoteStringName = true) const
|
||||
{
|
||||
if (name != nullptr)
|
||||
return quoteStringName ? ("\"" + std::string(name) + "\"") : name;
|
||||
return std::to_string((long long)string);
|
||||
}
|
||||
const char* name; // descriptive name for this string
|
||||
int string;
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
typedef TMap<TString, TString> TPragmaTable;
|
||||
|
||||
const int MaxTokenLength = 1024;
|
||||
|
||||
template <class T> bool IsPow2(T powerOf2)
|
||||
{
|
||||
if (powerOf2 <= 0)
|
||||
return false;
|
||||
|
||||
return (powerOf2 & (powerOf2 - 1)) == 0;
|
||||
}
|
||||
|
||||
// Round number up to a multiple of the given powerOf2, which is not
|
||||
// a power, just a number that must be a power of 2.
|
||||
template <class T> void RoundToPow2(T& number, int powerOf2)
|
||||
{
|
||||
assert(IsPow2(powerOf2));
|
||||
number = (number + powerOf2 - 1) & ~(powerOf2 - 1);
|
||||
}
|
||||
|
||||
template <class T> bool IsMultipleOfPow2(T number, int powerOf2)
|
||||
{
|
||||
assert(IsPow2(powerOf2));
|
||||
return ! (number & (powerOf2 - 1));
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _COMMON_INCLUDED_
|
|
@ -0,0 +1,617 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _CONSTANT_UNION_INCLUDED_
|
||||
#define _CONSTANT_UNION_INCLUDED_
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TConstUnion {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
|
||||
TConstUnion() : iConst(0), type(EbtInt) { }
|
||||
|
||||
void setIConst(int i)
|
||||
{
|
||||
iConst = i;
|
||||
type = EbtInt;
|
||||
}
|
||||
|
||||
void setUConst(unsigned int u)
|
||||
{
|
||||
uConst = u;
|
||||
type = EbtUint;
|
||||
}
|
||||
|
||||
void setI64Const(long long i64)
|
||||
{
|
||||
i64Const = i64;
|
||||
type = EbtInt64;
|
||||
}
|
||||
|
||||
void setU64Const(unsigned long long u64)
|
||||
{
|
||||
u64Const = u64;
|
||||
type = EbtUint64;
|
||||
}
|
||||
|
||||
void setDConst(double d)
|
||||
{
|
||||
dConst = d;
|
||||
type = EbtDouble;
|
||||
}
|
||||
|
||||
void setBConst(bool b)
|
||||
{
|
||||
bConst = b;
|
||||
type = EbtBool;
|
||||
}
|
||||
|
||||
int getIConst() const { return iConst; }
|
||||
unsigned int getUConst() const { return uConst; }
|
||||
long long getI64Const() const { return i64Const; }
|
||||
unsigned long long getU64Const() const { return u64Const; }
|
||||
double getDConst() const { return dConst; }
|
||||
bool getBConst() const { return bConst; }
|
||||
|
||||
bool operator==(const int i) const
|
||||
{
|
||||
if (i == iConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const unsigned int u) const
|
||||
{
|
||||
if (u == uConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const long long i64) const
|
||||
{
|
||||
if (i64 == i64Const)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const unsigned long long u64) const
|
||||
{
|
||||
if (u64 == u64Const)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const double d) const
|
||||
{
|
||||
if (d == dConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const bool b) const
|
||||
{
|
||||
if (b == bConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const TConstUnion& constant) const
|
||||
{
|
||||
if (constant.type != type)
|
||||
return false;
|
||||
|
||||
switch (type) {
|
||||
case EbtInt:
|
||||
if (constant.iConst == iConst)
|
||||
return true;
|
||||
|
||||
break;
|
||||
case EbtUint:
|
||||
if (constant.uConst == uConst)
|
||||
return true;
|
||||
|
||||
break;
|
||||
case EbtInt64:
|
||||
if (constant.i64Const == i64Const)
|
||||
return true;
|
||||
|
||||
break;
|
||||
case EbtUint64:
|
||||
if (constant.u64Const == u64Const)
|
||||
return true;
|
||||
|
||||
break;
|
||||
case EbtDouble:
|
||||
if (constant.dConst == dConst)
|
||||
return true;
|
||||
|
||||
break;
|
||||
case EbtBool:
|
||||
if (constant.bConst == bConst)
|
||||
return true;
|
||||
|
||||
break;
|
||||
default:
|
||||
assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const int i) const
|
||||
{
|
||||
return !operator==(i);
|
||||
}
|
||||
|
||||
bool operator!=(const unsigned int u) const
|
||||
{
|
||||
return !operator==(u);
|
||||
}
|
||||
|
||||
bool operator!=(const long long i) const
|
||||
{
|
||||
return !operator==(i);
|
||||
}
|
||||
|
||||
bool operator!=(const unsigned long long u) const
|
||||
{
|
||||
return !operator==(u);
|
||||
}
|
||||
|
||||
bool operator!=(const float f) const
|
||||
{
|
||||
return !operator==(f);
|
||||
}
|
||||
|
||||
bool operator!=(const bool b) const
|
||||
{
|
||||
return !operator==(b);
|
||||
}
|
||||
|
||||
bool operator!=(const TConstUnion& constant) const
|
||||
{
|
||||
return !operator==(constant);
|
||||
}
|
||||
|
||||
bool operator>(const TConstUnion& constant) const
|
||||
{
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt:
|
||||
if (iConst > constant.iConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtUint:
|
||||
if (uConst > constant.uConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtInt64:
|
||||
if (i64Const > constant.i64Const)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtUint64:
|
||||
if (u64Const > constant.u64Const)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtDouble:
|
||||
if (dConst > constant.dConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
assert(false && "Default missing");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator<(const TConstUnion& constant) const
|
||||
{
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt:
|
||||
if (iConst < constant.iConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtUint:
|
||||
if (uConst < constant.uConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtInt64:
|
||||
if (i64Const < constant.i64Const)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtUint64:
|
||||
if (u64Const < constant.u64Const)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case EbtDouble:
|
||||
if (dConst < constant.dConst)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
assert(false && "Default missing");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TConstUnion operator+(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const + constant.i64Const); break;
|
||||
case EbtUint: returnValue.setUConst(uConst + constant.uConst); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const + constant.u64Const); break;
|
||||
case EbtDouble: returnValue.setDConst(dConst + constant.dConst); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator-(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const - constant.i64Const); break;
|
||||
case EbtUint: returnValue.setUConst(uConst - constant.uConst); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const - constant.u64Const); break;
|
||||
case EbtDouble: returnValue.setDConst(dConst - constant.dConst); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator*(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const * constant.i64Const); break;
|
||||
case EbtUint: returnValue.setUConst(uConst * constant.uConst); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const * constant.u64Const); break;
|
||||
case EbtDouble: returnValue.setDConst(dConst * constant.dConst); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator%(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const % constant.i64Const); break;
|
||||
case EbtUint: returnValue.setUConst(uConst % constant.uConst); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const % constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator>>(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
switch (type) {
|
||||
case EbtInt:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
|
||||
case EbtUint: returnValue.setIConst(iConst >> constant.uConst); break;
|
||||
case EbtInt64: returnValue.setIConst(iConst >> constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setIConst(iConst >> constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
case EbtUint:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setUConst(uConst >> constant.iConst); break;
|
||||
case EbtUint: returnValue.setUConst(uConst >> constant.uConst); break;
|
||||
case EbtInt64: returnValue.setUConst(uConst >> constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setUConst(uConst >> constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
case EbtInt64:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setI64Const(i64Const >> constant.iConst); break;
|
||||
case EbtUint: returnValue.setI64Const(i64Const >> constant.uConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const >> constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setI64Const(i64Const >> constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
case EbtUint64:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setU64Const(u64Const >> constant.iConst); break;
|
||||
case EbtUint: returnValue.setU64Const(u64Const >> constant.uConst); break;
|
||||
case EbtInt64: returnValue.setU64Const(u64Const >> constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const >> constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator<<(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
switch (type) {
|
||||
case EbtInt:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
|
||||
case EbtUint: returnValue.setIConst(iConst << constant.uConst); break;
|
||||
case EbtInt64: returnValue.setIConst(iConst << constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setIConst(iConst << constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
case EbtUint:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setUConst(uConst << constant.iConst); break;
|
||||
case EbtUint: returnValue.setUConst(uConst << constant.uConst); break;
|
||||
case EbtInt64: returnValue.setUConst(uConst << constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setUConst(uConst << constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
case EbtInt64:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setI64Const(i64Const << constant.iConst); break;
|
||||
case EbtUint: returnValue.setI64Const(i64Const << constant.uConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const << constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setI64Const(i64Const << constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
case EbtUint64:
|
||||
switch (constant.type) {
|
||||
case EbtInt: returnValue.setU64Const(u64Const << constant.iConst); break;
|
||||
case EbtUint: returnValue.setU64Const(u64Const << constant.uConst); break;
|
||||
case EbtInt64: returnValue.setU64Const(u64Const << constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const << constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator&(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
|
||||
case EbtUint: returnValue.setUConst(uConst & constant.uConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const & constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const & constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator|(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
|
||||
case EbtUint: returnValue.setUConst(uConst | constant.uConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const | constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const | constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator^(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
|
||||
case EbtUint: returnValue.setUConst(uConst ^ constant.uConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(i64Const ^ constant.i64Const); break;
|
||||
case EbtUint64: returnValue.setU64Const(u64Const ^ constant.u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator~() const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
switch (type) {
|
||||
case EbtInt: returnValue.setIConst(~iConst); break;
|
||||
case EbtUint: returnValue.setUConst(~uConst); break;
|
||||
case EbtInt64: returnValue.setI64Const(~i64Const); break;
|
||||
case EbtUint64: returnValue.setU64Const(~u64Const); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator&&(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TConstUnion operator||(const TConstUnion& constant) const
|
||||
{
|
||||
TConstUnion returnValue;
|
||||
assert(type == constant.type);
|
||||
switch (type) {
|
||||
case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
TBasicType getType() const { return type; }
|
||||
|
||||
private:
|
||||
union {
|
||||
int iConst; // used for ivec, scalar ints
|
||||
unsigned int uConst; // used for uvec, scalar uints
|
||||
long long i64Const; // used for i64vec, scalar int64s
|
||||
unsigned long long u64Const; // used for u64vec, scalar uint64s
|
||||
bool bConst; // used for bvec, scalar bools
|
||||
double dConst; // used for vec, dvec, mat, dmat, scalar floats and doubles
|
||||
};
|
||||
|
||||
TBasicType type;
|
||||
};
|
||||
|
||||
// Encapsulate having a pointer to an array of TConstUnion,
|
||||
// which only needs to be allocated if it's size is going to be
|
||||
// bigger than 0.
|
||||
//
|
||||
// One convenience is being able to use [] to go inside the array, instead
|
||||
// of C++ assuming it as an array of pointers to vectors.
|
||||
//
|
||||
// General usage is that the size is known up front, and it is
|
||||
// created once with the proper size.
|
||||
//
|
||||
class TConstUnionArray {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
|
||||
TConstUnionArray() : unionArray(nullptr) { }
|
||||
virtual ~TConstUnionArray() { }
|
||||
|
||||
explicit TConstUnionArray(int size)
|
||||
{
|
||||
if (size == 0)
|
||||
unionArray = nullptr;
|
||||
else
|
||||
unionArray = new TConstUnionVector(size);
|
||||
}
|
||||
TConstUnionArray(const TConstUnionArray& a) : unionArray(a.unionArray) { }
|
||||
TConstUnionArray(const TConstUnionArray& a, int start, int size)
|
||||
{
|
||||
unionArray = new TConstUnionVector(size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
(*unionArray)[i] = a[start + i];
|
||||
}
|
||||
|
||||
// Use this constructor for a smear operation
|
||||
TConstUnionArray(int size, const TConstUnion& val)
|
||||
{
|
||||
unionArray = new TConstUnionVector(size, val);
|
||||
}
|
||||
|
||||
int size() const { return unionArray ? (int)unionArray->size() : 0; }
|
||||
TConstUnion& operator[](size_t index) { return (*unionArray)[index]; }
|
||||
const TConstUnion& operator[](size_t index) const { return (*unionArray)[index]; }
|
||||
bool operator==(const TConstUnionArray& rhs) const
|
||||
{
|
||||
// this includes the case that both are unallocated
|
||||
if (unionArray == rhs.unionArray)
|
||||
return true;
|
||||
|
||||
if (! unionArray || ! rhs.unionArray)
|
||||
return false;
|
||||
|
||||
if (! unionArray || ! rhs.unionArray)
|
||||
return false;
|
||||
|
||||
return *unionArray == *rhs.unionArray;
|
||||
}
|
||||
bool operator!=(const TConstUnionArray& rhs) const { return ! operator==(rhs); }
|
||||
|
||||
double dot(const TConstUnionArray& rhs)
|
||||
{
|
||||
assert(rhs.unionArray->size() == unionArray->size());
|
||||
double sum = 0.0;
|
||||
|
||||
for (size_t comp = 0; comp < unionArray->size(); ++comp)
|
||||
sum += (*this)[comp].getDConst() * rhs[comp].getDConst();
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
bool empty() const { return unionArray == nullptr; }
|
||||
|
||||
protected:
|
||||
typedef TVector<TConstUnion> TConstUnionVector;
|
||||
TConstUnionVector* unionArray;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _CONSTANT_UNION_INCLUDED_
|
|
@ -0,0 +1,145 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _INFOSINK_INCLUDED_
|
||||
#define _INFOSINK_INCLUDED_
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// TPrefixType is used to centralize how info log messages start.
|
||||
// See below.
|
||||
//
|
||||
enum TPrefixType {
|
||||
EPrefixNone,
|
||||
EPrefixWarning,
|
||||
EPrefixError,
|
||||
EPrefixInternalError,
|
||||
EPrefixUnimplemented,
|
||||
EPrefixNote
|
||||
};
|
||||
|
||||
enum TOutputStream {
|
||||
ENull = 0,
|
||||
EDebugger = 0x01,
|
||||
EStdOut = 0x02,
|
||||
EString = 0x04,
|
||||
};
|
||||
//
|
||||
// Encapsulate info logs for all objects that have them.
|
||||
//
|
||||
// The methods are a general set of tools for getting a variety of
|
||||
// messages and types inserted into the log.
|
||||
//
|
||||
class TInfoSinkBase {
|
||||
public:
|
||||
TInfoSinkBase() : outputStream(4) {}
|
||||
void erase() { sink.erase(); }
|
||||
TInfoSinkBase& operator<<(const TPersistString& t) { append(t); return *this; }
|
||||
TInfoSinkBase& operator<<(char c) { append(1, c); return *this; }
|
||||
TInfoSinkBase& operator<<(const char* s) { append(s); return *this; }
|
||||
TInfoSinkBase& operator<<(int n) { append(String(n)); return *this; }
|
||||
TInfoSinkBase& operator<<(unsigned int n) { append(String(n)); return *this; }
|
||||
TInfoSinkBase& operator<<(long unsigned int n) { append(String(n)); return *this; }
|
||||
TInfoSinkBase& operator<<(float n) { const int size = 40; char buf[size];
|
||||
snprintf(buf, size, (fabs(n) > 1e-8 && fabs(n) < 1e8) || n == 0.0f ? "%f" : "%g", n);
|
||||
append(buf);
|
||||
return *this; }
|
||||
TInfoSinkBase& operator+(const TPersistString& t) { append(t); return *this; }
|
||||
TInfoSinkBase& operator+(const TString& t) { append(t); return *this; }
|
||||
TInfoSinkBase& operator<<(const TString& t) { append(t); return *this; }
|
||||
TInfoSinkBase& operator+(const char* s) { append(s); return *this; }
|
||||
const char* c_str() const { return sink.c_str(); }
|
||||
void prefix(TPrefixType message) {
|
||||
switch(message) {
|
||||
case EPrefixNone: break;
|
||||
case EPrefixWarning: append("WARNING: "); break;
|
||||
case EPrefixError: append("ERROR: "); break;
|
||||
case EPrefixInternalError: append("INTERNAL ERROR: "); break;
|
||||
case EPrefixUnimplemented: append("UNIMPLEMENTED: "); break;
|
||||
case EPrefixNote: append("NOTE: "); break;
|
||||
default: append("UNKNOWN ERROR: "); break;
|
||||
}
|
||||
}
|
||||
void location(const TSourceLoc& loc) {
|
||||
const int maxSize = 24;
|
||||
char locText[maxSize];
|
||||
snprintf(locText, maxSize, ":%d", loc.line);
|
||||
append(loc.getStringNameOrNum(false).c_str());
|
||||
append(locText);
|
||||
append(": ");
|
||||
}
|
||||
void message(TPrefixType message, const char* s) {
|
||||
prefix(message);
|
||||
append(s);
|
||||
append("\n");
|
||||
}
|
||||
void message(TPrefixType message, const char* s, const TSourceLoc& loc) {
|
||||
prefix(message);
|
||||
location(loc);
|
||||
append(s);
|
||||
append("\n");
|
||||
}
|
||||
|
||||
void setOutputStream(int output = 4)
|
||||
{
|
||||
outputStream = output;
|
||||
}
|
||||
|
||||
protected:
|
||||
void append(const char* s);
|
||||
|
||||
void append(int count, char c);
|
||||
void append(const TPersistString& t);
|
||||
void append(const TString& t);
|
||||
|
||||
void checkMem(size_t growth) { if (sink.capacity() < sink.size() + growth + 2)
|
||||
sink.reserve(sink.capacity() + sink.capacity() / 2); }
|
||||
void appendToStream(const char* s);
|
||||
TPersistString sink;
|
||||
int outputStream;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
class TInfoSink {
|
||||
public:
|
||||
glslang::TInfoSinkBase info;
|
||||
glslang::TInfoSinkBase debug;
|
||||
};
|
||||
|
||||
#endif // _INFOSINK_INCLUDED_
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef __INITIALIZE_GLOBALS_INCLUDED_
|
||||
#define __INITIALIZE_GLOBALS_INCLUDED_
|
||||
|
||||
namespace glslang {
|
||||
|
||||
void InitializeMemoryPools();
|
||||
void FreeGlobalPools();
|
||||
bool InitializePoolIndex();
|
||||
void FreePoolIndex();
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // __INITIALIZE_GLOBALS_INCLUDED_
|
|
@ -0,0 +1,325 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _POOLALLOC_INCLUDED_
|
||||
#define _POOLALLOC_INCLUDED_
|
||||
|
||||
#ifdef _DEBUG
|
||||
# define GUARD_BLOCKS // define to enable guard block sanity checking
|
||||
#endif
|
||||
|
||||
//
|
||||
// This header defines an allocator that can be used to efficiently
|
||||
// allocate a large number of small requests for heap memory, with the
|
||||
// intention that they are not individually deallocated, but rather
|
||||
// collectively deallocated at one time.
|
||||
//
|
||||
// This simultaneously
|
||||
//
|
||||
// * Makes each individual allocation much more efficient; the
|
||||
// typical allocation is trivial.
|
||||
// * Completely avoids the cost of doing individual deallocation.
|
||||
// * Saves the trouble of tracking down and plugging a large class of leaks.
|
||||
//
|
||||
// Individual classes can use this allocator by supplying their own
|
||||
// new and delete methods.
|
||||
//
|
||||
// STL containers can use this allocator by using the pool_allocator
|
||||
// class as the allocator (second) template argument.
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// If we are using guard blocks, we must track each indivual
|
||||
// allocation. If we aren't using guard blocks, these
|
||||
// never get instantiated, so won't have any impact.
|
||||
//
|
||||
|
||||
class TAllocation {
|
||||
public:
|
||||
TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) :
|
||||
size(size), mem(mem), prevAlloc(prev) {
|
||||
// Allocations are bracketed:
|
||||
// [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
|
||||
// This would be cleaner with if (guardBlockSize)..., but that
|
||||
// makes the compiler print warnings about 0 length memsets,
|
||||
// even with the if() protecting them.
|
||||
# ifdef GUARD_BLOCKS
|
||||
memset(preGuard(), guardBlockBeginVal, guardBlockSize);
|
||||
memset(data(), userDataFill, size);
|
||||
memset(postGuard(), guardBlockEndVal, guardBlockSize);
|
||||
# endif
|
||||
}
|
||||
|
||||
void check() const {
|
||||
checkGuardBlock(preGuard(), guardBlockBeginVal, "before");
|
||||
checkGuardBlock(postGuard(), guardBlockEndVal, "after");
|
||||
}
|
||||
|
||||
void checkAllocList() const;
|
||||
|
||||
// Return total size needed to accommodate user buffer of 'size',
|
||||
// plus our tracking data.
|
||||
inline static size_t allocationSize(size_t size) {
|
||||
return size + 2 * guardBlockSize + headerSize();
|
||||
}
|
||||
|
||||
// Offset from surrounding buffer to get to user data buffer.
|
||||
inline static unsigned char* offsetAllocation(unsigned char* m) {
|
||||
return m + guardBlockSize + headerSize();
|
||||
}
|
||||
|
||||
private:
|
||||
void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const;
|
||||
|
||||
// Find offsets to pre and post guard blocks, and user data buffer
|
||||
unsigned char* preGuard() const { return mem + headerSize(); }
|
||||
unsigned char* data() const { return preGuard() + guardBlockSize; }
|
||||
unsigned char* postGuard() const { return data() + size; }
|
||||
|
||||
size_t size; // size of the user data area
|
||||
unsigned char* mem; // beginning of our allocation (pts to header)
|
||||
TAllocation* prevAlloc; // prior allocation in the chain
|
||||
|
||||
const static unsigned char guardBlockBeginVal;
|
||||
const static unsigned char guardBlockEndVal;
|
||||
const static unsigned char userDataFill;
|
||||
|
||||
const static size_t guardBlockSize;
|
||||
# ifdef GUARD_BLOCKS
|
||||
inline static size_t headerSize() { return sizeof(TAllocation); }
|
||||
# else
|
||||
inline static size_t headerSize() { return 0; }
|
||||
# endif
|
||||
};
|
||||
|
||||
//
|
||||
// There are several stacks. One is to track the pushing and popping
|
||||
// of the user, and not yet implemented. The others are simply a
|
||||
// repositories of free pages or used pages.
|
||||
//
|
||||
// Page stacks are linked together with a simple header at the beginning
|
||||
// of each allocation obtained from the underlying OS. Multi-page allocations
|
||||
// are returned to the OS. Individual page allocations are kept for future
|
||||
// re-use.
|
||||
//
|
||||
// The "page size" used is not, nor must it match, the underlying OS
|
||||
// page size. But, having it be about that size or equal to a set of
|
||||
// pages is likely most optimal.
|
||||
//
|
||||
class TPoolAllocator {
|
||||
public:
|
||||
TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
|
||||
|
||||
//
|
||||
// Don't call the destructor just to free up the memory, call pop()
|
||||
//
|
||||
~TPoolAllocator();
|
||||
|
||||
//
|
||||
// Call push() to establish a new place to pop memory too. Does not
|
||||
// have to be called to get things started.
|
||||
//
|
||||
void push();
|
||||
|
||||
//
|
||||
// Call pop() to free all memory allocated since the last call to push(),
|
||||
// or if no last call to push, frees all memory since first allocation.
|
||||
//
|
||||
void pop();
|
||||
|
||||
//
|
||||
// Call popAll() to free all memory allocated.
|
||||
//
|
||||
void popAll();
|
||||
|
||||
//
|
||||
// Call allocate() to actually acquire memory. Returns 0 if no memory
|
||||
// available, otherwise a properly aligned pointer to 'numBytes' of memory.
|
||||
//
|
||||
void* allocate(size_t numBytes);
|
||||
|
||||
//
|
||||
// There is no deallocate. The point of this class is that
|
||||
// deallocation can be skipped by the user of it, as the model
|
||||
// of use is to simultaneously deallocate everything at once
|
||||
// by calling pop(), and to not have to solve memory leak problems.
|
||||
//
|
||||
|
||||
protected:
|
||||
friend struct tHeader;
|
||||
|
||||
struct tHeader {
|
||||
tHeader(tHeader* nextPage, size_t pageCount) :
|
||||
#ifdef GUARD_BLOCKS
|
||||
lastAllocation(0),
|
||||
#endif
|
||||
nextPage(nextPage), pageCount(pageCount) { }
|
||||
|
||||
~tHeader() {
|
||||
#ifdef GUARD_BLOCKS
|
||||
if (lastAllocation)
|
||||
lastAllocation->checkAllocList();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GUARD_BLOCKS
|
||||
TAllocation* lastAllocation;
|
||||
#endif
|
||||
tHeader* nextPage;
|
||||
size_t pageCount;
|
||||
};
|
||||
|
||||
struct tAllocState {
|
||||
size_t offset;
|
||||
tHeader* page;
|
||||
};
|
||||
typedef std::vector<tAllocState> tAllocStack;
|
||||
|
||||
// Track allocations if and only if we're using guard blocks
|
||||
#ifndef GUARD_BLOCKS
|
||||
void* initializeAllocation(tHeader*, unsigned char* memory, size_t) {
|
||||
#else
|
||||
void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) {
|
||||
new(memory) TAllocation(numBytes, memory, block->lastAllocation);
|
||||
block->lastAllocation = reinterpret_cast<TAllocation*>(memory);
|
||||
#endif
|
||||
|
||||
// This is optimized entirely away if GUARD_BLOCKS is not defined.
|
||||
return TAllocation::offsetAllocation(memory);
|
||||
}
|
||||
|
||||
size_t pageSize; // granularity of allocation from the OS
|
||||
size_t alignment; // all returned allocations will be aligned at
|
||||
// this granularity, which will be a power of 2
|
||||
size_t alignmentMask;
|
||||
size_t headerSkip; // amount of memory to skip to make room for the
|
||||
// header (basically, size of header, rounded
|
||||
// up to make it aligned
|
||||
size_t currentPageOffset; // next offset in top of inUseList to allocate from
|
||||
tHeader* freeList; // list of popped memory
|
||||
tHeader* inUseList; // list of all memory currently being used
|
||||
tAllocStack stack; // stack of where to allocate from, to partition pool
|
||||
|
||||
int numCalls; // just an interesting statistic
|
||||
size_t totalBytes; // just an interesting statistic
|
||||
private:
|
||||
TPoolAllocator& operator=(const TPoolAllocator&); // don't allow assignment operator
|
||||
TPoolAllocator(const TPoolAllocator&); // don't allow default copy constructor
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// There could potentially be many pools with pops happening at
|
||||
// different times. But a simple use is to have a global pop
|
||||
// with everyone using the same global allocator.
|
||||
//
|
||||
typedef TPoolAllocator* PoolAllocatorPointer;
|
||||
extern TPoolAllocator& GetThreadPoolAllocator();
|
||||
|
||||
struct TThreadMemoryPools
|
||||
{
|
||||
TPoolAllocator* threadPoolAllocator;
|
||||
};
|
||||
|
||||
void SetThreadPoolAllocator(TPoolAllocator& poolAllocator);
|
||||
|
||||
//
|
||||
// This STL compatible allocator is intended to be used as the allocator
|
||||
// parameter to templatized STL containers, like vector and map.
|
||||
//
|
||||
// It will use the pools for allocation, and not
|
||||
// do any deallocation, but will still do destruction.
|
||||
//
|
||||
template<class T>
|
||||
class pool_allocator {
|
||||
public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef T *pointer;
|
||||
typedef const T *const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T value_type;
|
||||
template<class Other>
|
||||
struct rebind {
|
||||
typedef pool_allocator<Other> other;
|
||||
};
|
||||
pointer address(reference x) const { return &x; }
|
||||
const_pointer address(const_reference x) const { return &x; }
|
||||
|
||||
pool_allocator() : allocator(GetThreadPoolAllocator()) { }
|
||||
pool_allocator(TPoolAllocator& a) : allocator(a) { }
|
||||
pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
|
||||
|
||||
template<class Other>
|
||||
pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
|
||||
pointer allocate(size_type n, const void*) {
|
||||
return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T))); }
|
||||
|
||||
void deallocate(void*, size_type) { }
|
||||
void deallocate(pointer, size_type) { }
|
||||
|
||||
pointer _Charalloc(size_t n) {
|
||||
return reinterpret_cast<pointer>(getAllocator().allocate(n)); }
|
||||
|
||||
void construct(pointer p, const T& val) { new ((void *)p) T(val); }
|
||||
void destroy(pointer p) { p->T::~T(); }
|
||||
|
||||
bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
|
||||
bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
|
||||
|
||||
size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
|
||||
size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
|
||||
|
||||
void setAllocator(TPoolAllocator* a) { allocator = *a; }
|
||||
TPoolAllocator& getAllocator() const { return allocator; }
|
||||
|
||||
protected:
|
||||
pool_allocator& operator=(const pool_allocator&) { return *this; }
|
||||
TPoolAllocator& allocator;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _POOLALLOC_INCLUDED_
|
|
@ -0,0 +1,140 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _RESOURCE_LIMITS_INCLUDED_
|
||||
#define _RESOURCE_LIMITS_INCLUDED_
|
||||
|
||||
struct TLimits {
|
||||
bool nonInductiveForLoops;
|
||||
bool whileLoops;
|
||||
bool doWhileLoops;
|
||||
bool generalUniformIndexing;
|
||||
bool generalAttributeMatrixVectorIndexing;
|
||||
bool generalVaryingIndexing;
|
||||
bool generalSamplerIndexing;
|
||||
bool generalVariableIndexing;
|
||||
bool generalConstantMatrixVectorIndexing;
|
||||
};
|
||||
|
||||
struct TBuiltInResource {
|
||||
int maxLights;
|
||||
int maxClipPlanes;
|
||||
int maxTextureUnits;
|
||||
int maxTextureCoords;
|
||||
int maxVertexAttribs;
|
||||
int maxVertexUniformComponents;
|
||||
int maxVaryingFloats;
|
||||
int maxVertexTextureImageUnits;
|
||||
int maxCombinedTextureImageUnits;
|
||||
int maxTextureImageUnits;
|
||||
int maxFragmentUniformComponents;
|
||||
int maxDrawBuffers;
|
||||
int maxVertexUniformVectors;
|
||||
int maxVaryingVectors;
|
||||
int maxFragmentUniformVectors;
|
||||
int maxVertexOutputVectors;
|
||||
int maxFragmentInputVectors;
|
||||
int minProgramTexelOffset;
|
||||
int maxProgramTexelOffset;
|
||||
int maxClipDistances;
|
||||
int maxComputeWorkGroupCountX;
|
||||
int maxComputeWorkGroupCountY;
|
||||
int maxComputeWorkGroupCountZ;
|
||||
int maxComputeWorkGroupSizeX;
|
||||
int maxComputeWorkGroupSizeY;
|
||||
int maxComputeWorkGroupSizeZ;
|
||||
int maxComputeUniformComponents;
|
||||
int maxComputeTextureImageUnits;
|
||||
int maxComputeImageUniforms;
|
||||
int maxComputeAtomicCounters;
|
||||
int maxComputeAtomicCounterBuffers;
|
||||
int maxVaryingComponents;
|
||||
int maxVertexOutputComponents;
|
||||
int maxGeometryInputComponents;
|
||||
int maxGeometryOutputComponents;
|
||||
int maxFragmentInputComponents;
|
||||
int maxImageUnits;
|
||||
int maxCombinedImageUnitsAndFragmentOutputs;
|
||||
int maxCombinedShaderOutputResources;
|
||||
int maxImageSamples;
|
||||
int maxVertexImageUniforms;
|
||||
int maxTessControlImageUniforms;
|
||||
int maxTessEvaluationImageUniforms;
|
||||
int maxGeometryImageUniforms;
|
||||
int maxFragmentImageUniforms;
|
||||
int maxCombinedImageUniforms;
|
||||
int maxGeometryTextureImageUnits;
|
||||
int maxGeometryOutputVertices;
|
||||
int maxGeometryTotalOutputComponents;
|
||||
int maxGeometryUniformComponents;
|
||||
int maxGeometryVaryingComponents;
|
||||
int maxTessControlInputComponents;
|
||||
int maxTessControlOutputComponents;
|
||||
int maxTessControlTextureImageUnits;
|
||||
int maxTessControlUniformComponents;
|
||||
int maxTessControlTotalOutputComponents;
|
||||
int maxTessEvaluationInputComponents;
|
||||
int maxTessEvaluationOutputComponents;
|
||||
int maxTessEvaluationTextureImageUnits;
|
||||
int maxTessEvaluationUniformComponents;
|
||||
int maxTessPatchComponents;
|
||||
int maxPatchVertices;
|
||||
int maxTessGenLevel;
|
||||
int maxViewports;
|
||||
int maxVertexAtomicCounters;
|
||||
int maxTessControlAtomicCounters;
|
||||
int maxTessEvaluationAtomicCounters;
|
||||
int maxGeometryAtomicCounters;
|
||||
int maxFragmentAtomicCounters;
|
||||
int maxCombinedAtomicCounters;
|
||||
int maxAtomicCounterBindings;
|
||||
int maxVertexAtomicCounterBuffers;
|
||||
int maxTessControlAtomicCounterBuffers;
|
||||
int maxTessEvaluationAtomicCounterBuffers;
|
||||
int maxGeometryAtomicCounterBuffers;
|
||||
int maxFragmentAtomicCounterBuffers;
|
||||
int maxCombinedAtomicCounterBuffers;
|
||||
int maxAtomicCounterBufferSize;
|
||||
int maxTransformFeedbackBuffers;
|
||||
int maxTransformFeedbackInterleavedComponents;
|
||||
int maxCullDistances;
|
||||
int maxCombinedClipAndCullDistances;
|
||||
int maxSamples;
|
||||
|
||||
TLimits limits;
|
||||
};
|
||||
|
||||
#endif // _RESOURCE_LIMITS_INCLUDED_
|
|
@ -0,0 +1,174 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _SHHANDLE_INCLUDED_
|
||||
#define _SHHANDLE_INCLUDED_
|
||||
|
||||
//
|
||||
// Machine independent part of the compiler private objects
|
||||
// sent as ShHandle to the driver.
|
||||
//
|
||||
// This should not be included by driver code.
|
||||
//
|
||||
|
||||
|
||||
#define SH_EXPORTING
|
||||
#include "../Public/ShaderLang.h"
|
||||
#include "../MachineIndependent/Versions.h"
|
||||
#include "InfoSink.h"
|
||||
|
||||
class TCompiler;
|
||||
class TLinker;
|
||||
class TUniformMap;
|
||||
|
||||
//
|
||||
// The base class used to back handles returned to the driver.
|
||||
//
|
||||
class TShHandleBase {
|
||||
public:
|
||||
TShHandleBase() { }
|
||||
virtual ~TShHandleBase() { }
|
||||
virtual TCompiler* getAsCompiler() { return 0; }
|
||||
virtual TLinker* getAsLinker() { return 0; }
|
||||
virtual TUniformMap* getAsUniformMap() { return 0; }
|
||||
};
|
||||
|
||||
//
|
||||
// The base class for the machine dependent linker to derive from
|
||||
// for managing where uniforms live.
|
||||
//
|
||||
class TUniformMap : public TShHandleBase {
|
||||
public:
|
||||
TUniformMap() { }
|
||||
virtual ~TUniformMap() { }
|
||||
virtual TUniformMap* getAsUniformMap() { return this; }
|
||||
virtual int getLocation(const char* name) = 0;
|
||||
virtual TInfoSink& getInfoSink() { return infoSink; }
|
||||
TInfoSink infoSink;
|
||||
};
|
||||
|
||||
class TIntermNode;
|
||||
|
||||
//
|
||||
// The base class for the machine dependent compiler to derive from
|
||||
// for managing object code from the compile.
|
||||
//
|
||||
class TCompiler : public TShHandleBase {
|
||||
public:
|
||||
TCompiler(EShLanguage l, TInfoSink& sink) : infoSink(sink) , language(l), haveValidObjectCode(false) { }
|
||||
virtual ~TCompiler() { }
|
||||
EShLanguage getLanguage() { return language; }
|
||||
virtual TInfoSink& getInfoSink() { return infoSink; }
|
||||
|
||||
virtual bool compile(TIntermNode* root, int version = 0, EProfile profile = ENoProfile) = 0;
|
||||
|
||||
virtual TCompiler* getAsCompiler() { return this; }
|
||||
virtual bool linkable() { return haveValidObjectCode; }
|
||||
|
||||
TInfoSink& infoSink;
|
||||
protected:
|
||||
TCompiler& operator=(TCompiler&);
|
||||
|
||||
EShLanguage language;
|
||||
bool haveValidObjectCode;
|
||||
};
|
||||
|
||||
//
|
||||
// Link operations are based on a list of compile results...
|
||||
//
|
||||
typedef glslang::TVector<TCompiler*> TCompilerList;
|
||||
typedef glslang::TVector<TShHandleBase*> THandleList;
|
||||
|
||||
//
|
||||
// The base class for the machine dependent linker to derive from
|
||||
// to manage the resulting executable.
|
||||
//
|
||||
|
||||
class TLinker : public TShHandleBase {
|
||||
public:
|
||||
TLinker(EShExecutable e, TInfoSink& iSink) :
|
||||
infoSink(iSink),
|
||||
executable(e),
|
||||
haveReturnableObjectCode(false),
|
||||
appAttributeBindings(0),
|
||||
fixedAttributeBindings(0),
|
||||
excludedAttributes(0),
|
||||
excludedCount(0),
|
||||
uniformBindings(0) { }
|
||||
virtual TLinker* getAsLinker() { return this; }
|
||||
virtual ~TLinker() { }
|
||||
virtual bool link(TCompilerList&, TUniformMap*) = 0;
|
||||
virtual bool link(THandleList&) { return false; }
|
||||
virtual void setAppAttributeBindings(const ShBindingTable* t) { appAttributeBindings = t; }
|
||||
virtual void setFixedAttributeBindings(const ShBindingTable* t) { fixedAttributeBindings = t; }
|
||||
virtual void getAttributeBindings(ShBindingTable const **t) const = 0;
|
||||
virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; }
|
||||
virtual ShBindingTable* getUniformBindings() const { return uniformBindings; }
|
||||
virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here
|
||||
virtual TInfoSink& getInfoSink() { return infoSink; }
|
||||
TInfoSink& infoSink;
|
||||
protected:
|
||||
TLinker& operator=(TLinker&);
|
||||
EShExecutable executable;
|
||||
bool haveReturnableObjectCode; // true when objectCode is acceptable to send to driver
|
||||
|
||||
const ShBindingTable* appAttributeBindings;
|
||||
const ShBindingTable* fixedAttributeBindings;
|
||||
const int* excludedAttributes;
|
||||
int excludedCount;
|
||||
ShBindingTable* uniformBindings; // created by the linker
|
||||
};
|
||||
|
||||
//
|
||||
// This is the interface between the machine independent code
|
||||
// and the machine dependent code.
|
||||
//
|
||||
// The machine dependent code should derive from the classes
|
||||
// above. Then Construct*() and Delete*() will create and
|
||||
// destroy the machine dependent objects, which contain the
|
||||
// above machine independent information.
|
||||
//
|
||||
TCompiler* ConstructCompiler(EShLanguage, int);
|
||||
|
||||
TShHandleBase* ConstructLinker(EShExecutable, int);
|
||||
TShHandleBase* ConstructBindings();
|
||||
void DeleteLinker(TShHandleBase*);
|
||||
void DeleteBindingList(TShHandleBase* bindingList);
|
||||
|
||||
TUniformMap* ConstructUniformMap();
|
||||
void DeleteCompiler(TCompiler*);
|
||||
|
||||
void DeleteUniformMap(TUniformMap*);
|
||||
|
||||
#endif // _SHHANDLE_INCLUDED_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,318 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// Implement types for tracking GLSL arrays, arrays of arrays, etc.
|
||||
//
|
||||
|
||||
#ifndef _ARRAYS_INCLUDED
|
||||
#define _ARRAYS_INCLUDED
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// This is used to mean there is no size yet (unsized), it is waiting to get a size from somewhere else.
|
||||
const int UnsizedArraySize = 0;
|
||||
|
||||
class TIntermTyped;
|
||||
extern bool SameSpecializationConstants(TIntermTyped*, TIntermTyped*);
|
||||
|
||||
// Specialization constants need both a nominal size and a node that defines
|
||||
// the specialization constant being used. Array types are the same when their
|
||||
// size and specialization constant nodes are the same.
|
||||
struct TArraySize {
|
||||
unsigned int size;
|
||||
TIntermTyped* node; // nullptr means no specialization constant node
|
||||
bool operator==(const TArraySize& rhs) const
|
||||
{
|
||||
if (size != rhs.size)
|
||||
return false;
|
||||
if (node == nullptr || rhs.node == nullptr)
|
||||
return node == rhs.node;
|
||||
|
||||
return SameSpecializationConstants(node, rhs.node);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// TSmallArrayVector is used as the container for the set of sizes in TArraySizes.
|
||||
// It has generic-container semantics, while TArraySizes has array-of-array semantics.
|
||||
// That is, TSmallArrayVector should be more focused on mechanism and TArraySizes on policy.
|
||||
//
|
||||
struct TSmallArrayVector {
|
||||
//
|
||||
// TODO: memory: TSmallArrayVector is intended to be smaller.
|
||||
// Almost all arrays could be handled by two sizes each fitting
|
||||
// in 16 bits, needing a real vector only in the cases where there
|
||||
// are more than 3 sizes or a size needing more than 16 bits.
|
||||
//
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
|
||||
TSmallArrayVector() : sizes(nullptr) { }
|
||||
virtual ~TSmallArrayVector() { dealloc(); }
|
||||
|
||||
// For breaking into two non-shared copies, independently modifiable.
|
||||
TSmallArrayVector& operator=(const TSmallArrayVector& from)
|
||||
{
|
||||
if (from.sizes == nullptr)
|
||||
sizes = nullptr;
|
||||
else {
|
||||
alloc();
|
||||
*sizes = *from.sizes;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
if (sizes == nullptr)
|
||||
return 0;
|
||||
return (int)sizes->size();
|
||||
}
|
||||
|
||||
unsigned int frontSize() const
|
||||
{
|
||||
assert(sizes != nullptr && sizes->size() > 0);
|
||||
return sizes->front().size;
|
||||
}
|
||||
|
||||
TIntermTyped* frontNode() const
|
||||
{
|
||||
assert(sizes != nullptr && sizes->size() > 0);
|
||||
return sizes->front().node;
|
||||
}
|
||||
|
||||
void changeFront(unsigned int s)
|
||||
{
|
||||
assert(sizes != nullptr);
|
||||
// this should only happen for implicitly sized arrays, not specialization constants
|
||||
assert(sizes->front().node == nullptr);
|
||||
sizes->front().size = s;
|
||||
}
|
||||
|
||||
void push_back(unsigned int e, TIntermTyped* n)
|
||||
{
|
||||
alloc();
|
||||
TArraySize pair = { e, n };
|
||||
sizes->push_back(pair);
|
||||
}
|
||||
|
||||
void push_front(const TSmallArrayVector& newDims)
|
||||
{
|
||||
alloc();
|
||||
sizes->insert(sizes->begin(), newDims.sizes->begin(), newDims.sizes->end());
|
||||
}
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
assert(sizes != nullptr && sizes->size() > 0);
|
||||
if (sizes->size() == 1)
|
||||
dealloc();
|
||||
else
|
||||
sizes->erase(sizes->begin());
|
||||
}
|
||||
|
||||
// 'this' should currently not be holding anything, and copyNonFront
|
||||
// will make it hold a copy of all but the first element of rhs.
|
||||
// (This would be useful for making a type that is dereferenced by
|
||||
// one dimension.)
|
||||
void copyNonFront(const TSmallArrayVector& rhs)
|
||||
{
|
||||
assert(sizes == nullptr);
|
||||
if (rhs.size() > 1) {
|
||||
alloc();
|
||||
sizes->insert(sizes->begin(), rhs.sizes->begin() + 1, rhs.sizes->end());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getDimSize(int i) const
|
||||
{
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i].size;
|
||||
}
|
||||
|
||||
void setDimSize(int i, unsigned int size) const
|
||||
{
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
assert((*sizes)[i].node == nullptr);
|
||||
(*sizes)[i].size = size;
|
||||
}
|
||||
|
||||
TIntermTyped* getDimNode(int i) const
|
||||
{
|
||||
assert(sizes != nullptr && (int)sizes->size() > i);
|
||||
return (*sizes)[i].node;
|
||||
}
|
||||
|
||||
bool operator==(const TSmallArrayVector& rhs) const
|
||||
{
|
||||
if (sizes == nullptr && rhs.sizes == nullptr)
|
||||
return true;
|
||||
if (sizes == nullptr || rhs.sizes == nullptr)
|
||||
return false;
|
||||
return *sizes == *rhs.sizes;
|
||||
}
|
||||
bool operator!=(const TSmallArrayVector& rhs) const { return ! operator==(rhs); }
|
||||
|
||||
protected:
|
||||
TSmallArrayVector(const TSmallArrayVector&);
|
||||
|
||||
void alloc()
|
||||
{
|
||||
if (sizes == nullptr)
|
||||
sizes = new TVector<TArraySize>;
|
||||
}
|
||||
void dealloc()
|
||||
{
|
||||
delete sizes;
|
||||
sizes = nullptr;
|
||||
}
|
||||
|
||||
TVector<TArraySize>* sizes; // will either hold such a pointer, or in the future, hold the two array sizes
|
||||
};
|
||||
|
||||
//
|
||||
// Represent an array, or array of arrays, to arbitrary depth. This is not
|
||||
// done through a hierarchy of types in a type tree, rather all contiguous arrayness
|
||||
// in the type hierarchy is localized into this single cumulative object.
|
||||
//
|
||||
// The arrayness in TTtype is a pointer, so that it can be non-allocated and zero
|
||||
// for the vast majority of types that are non-array types.
|
||||
//
|
||||
// Order Policy: these are all identical:
|
||||
// - left to right order within a contiguous set of ...[..][..][..]... in the source language
|
||||
// - index order 0, 1, 2, ... within the 'sizes' member below
|
||||
// - outer-most to inner-most
|
||||
//
|
||||
struct TArraySizes {
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
|
||||
TArraySizes() : implicitArraySize(1) { }
|
||||
|
||||
// For breaking into two non-shared copies, independently modifiable.
|
||||
TArraySizes& operator=(const TArraySizes& from)
|
||||
{
|
||||
implicitArraySize = from.implicitArraySize;
|
||||
sizes = from.sizes;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// translate from array-of-array semantics to container semantics
|
||||
int getNumDims() const { return sizes.size(); }
|
||||
int getDimSize(int dim) const { return sizes.getDimSize(dim); }
|
||||
TIntermTyped* getDimNode(int dim) const { return sizes.getDimNode(dim); }
|
||||
void setDimSize(int dim, int size) { sizes.setDimSize(dim, size); }
|
||||
int getOuterSize() const { return sizes.frontSize(); }
|
||||
TIntermTyped* getOuterNode() const { return sizes.frontNode(); }
|
||||
int getCumulativeSize() const
|
||||
{
|
||||
int size = 1;
|
||||
for (int d = 0; d < sizes.size(); ++d) {
|
||||
// this only makes sense in paths that have a known array size
|
||||
assert(sizes.getDimSize(d) != UnsizedArraySize);
|
||||
size *= sizes.getDimSize(d);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
void addInnerSize() { addInnerSize((unsigned)UnsizedArraySize); }
|
||||
void addInnerSize(int s) { addInnerSize((unsigned)s, nullptr); }
|
||||
void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); }
|
||||
void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); }
|
||||
void changeOuterSize(int s) { sizes.changeFront((unsigned)s); }
|
||||
int getImplicitSize() const { return (int)implicitArraySize; }
|
||||
void setImplicitSize(int s) { implicitArraySize = s; }
|
||||
bool isInnerImplicit() const
|
||||
{
|
||||
for (int d = 1; d < sizes.size(); ++d) {
|
||||
if (sizes.getDimSize(d) == (unsigned)UnsizedArraySize)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool isImplicit() const { return getOuterSize() == UnsizedArraySize || isInnerImplicit(); }
|
||||
void addOuterSizes(const TArraySizes& s) { sizes.push_front(s.sizes); }
|
||||
void dereference() { sizes.pop_front(); }
|
||||
void copyDereferenced(const TArraySizes& rhs)
|
||||
{
|
||||
assert(sizes.size() == 0);
|
||||
if (rhs.sizes.size() > 1)
|
||||
sizes.copyNonFront(rhs.sizes);
|
||||
}
|
||||
|
||||
bool sameInnerArrayness(const TArraySizes& rhs) const
|
||||
{
|
||||
if (sizes.size() != rhs.sizes.size())
|
||||
return false;
|
||||
|
||||
for (int d = 1; d < sizes.size(); ++d) {
|
||||
if (sizes.getDimSize(d) != rhs.sizes.getDimSize(d) ||
|
||||
sizes.getDimNode(d) != rhs.sizes.getDimNode(d))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if any of the dimensions of the array is sized with a node
|
||||
// instead of a front-end compile-time constant.
|
||||
bool containsNode()
|
||||
{
|
||||
for (int d = 0; d < sizes.size(); ++d) {
|
||||
if (sizes.getDimNode(d) != nullptr)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const TArraySizes& rhs) { return sizes == rhs.sizes; }
|
||||
bool operator!=(const TArraySizes& rhs) { return sizes != rhs.sizes; }
|
||||
|
||||
protected:
|
||||
TSmallArrayVector sizes;
|
||||
|
||||
TArraySizes(const TArraySizes&);
|
||||
|
||||
// for tracking maximum referenced index, before an explicit size is given
|
||||
// applies only to the outer-most dimension
|
||||
int implicitArraySize;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _ARRAYS_INCLUDED_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
// This header is generated by the make-revision script.
|
||||
// For the version, it uses the latest git tag followed by the number of commits.
|
||||
// For the date, it uses the current date (when then script is run).
|
||||
|
||||
#define GLSLANG_REVISION "SPIRV99.947"
|
||||
#define GLSLANG_DATE "15-Feb-2016"
|
|
@ -0,0 +1,13 @@
|
|||
// The file revision.h should be updated to the latest version, somehow, on
|
||||
// check-in, if glslang has changed.
|
||||
//
|
||||
// revision.template is the source for revision.h when using SubWCRev as the
|
||||
// method of updating revision.h. You don't have to do it this way, the
|
||||
// requirement is only that revision.h gets updated.
|
||||
//
|
||||
// revision.h is under source control so that not all consumers of glslang
|
||||
// source have to figure out how to create revision.h just to get a build
|
||||
// going. However, if it is not updated, it can be a version behind.
|
||||
|
||||
#define GLSLANG_REVISION "$WCREV$"
|
||||
#define GLSLANG_DATE "$WCDATE$"
|
|
@ -0,0 +1,983 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "localintermediate.h"
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace glslang;
|
||||
|
||||
typedef union {
|
||||
double d;
|
||||
int i[2];
|
||||
} DoubleIntUnion;
|
||||
|
||||
// Some helper functions
|
||||
|
||||
bool isNan(double x)
|
||||
{
|
||||
DoubleIntUnion u;
|
||||
// tough to find a platform independent library function, do it directly
|
||||
u.d = x;
|
||||
int bitPatternL = u.i[0];
|
||||
int bitPatternH = u.i[1];
|
||||
return (bitPatternH & 0x7ff80000) == 0x7ff80000 &&
|
||||
((bitPatternH & 0xFFFFF) != 0 || bitPatternL != 0);
|
||||
}
|
||||
|
||||
bool isInf(double x)
|
||||
{
|
||||
DoubleIntUnion u;
|
||||
// tough to find a platform independent library function, do it directly
|
||||
u.d = x;
|
||||
int bitPatternL = u.i[0];
|
||||
int bitPatternH = u.i[1];
|
||||
return (bitPatternH & 0x7ff00000) == 0x7ff00000 &&
|
||||
(bitPatternH & 0xFFFFF) == 0 && bitPatternL == 0;
|
||||
}
|
||||
|
||||
const double pi = 3.1415926535897932384626433832795;
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// The fold functions see if an operation on a constant can be done in place,
|
||||
// without generating run-time code.
|
||||
//
|
||||
// Returns the node to keep using, which may or may not be the node passed in.
|
||||
//
|
||||
// Note: As of version 1.2, all constant operations must be folded. It is
|
||||
// not opportunistic, but rather a semantic requirement.
|
||||
//
|
||||
|
||||
//
|
||||
// Do folding between a pair of nodes.
|
||||
// 'this' is the left-hand operand and 'rightConstantNode' is the right-hand operand.
|
||||
//
|
||||
// Returns a new node representing the result.
|
||||
//
|
||||
TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* rightConstantNode) const
|
||||
{
|
||||
// For most cases, the return type matches the argument type, so set that
|
||||
// up and just code to exceptions below.
|
||||
TType returnType;
|
||||
returnType.shallowCopy(getType());
|
||||
|
||||
//
|
||||
// A pair of nodes is to be folded together
|
||||
//
|
||||
|
||||
const TIntermConstantUnion *rightNode = rightConstantNode->getAsConstantUnion();
|
||||
TConstUnionArray leftUnionArray = getConstArray();
|
||||
TConstUnionArray rightUnionArray = rightNode->getConstArray();
|
||||
|
||||
// Figure out the size of the result
|
||||
int newComps;
|
||||
int constComps;
|
||||
switch(op) {
|
||||
case EOpMatrixTimesMatrix:
|
||||
newComps = rightNode->getMatrixCols() * getMatrixRows();
|
||||
break;
|
||||
case EOpMatrixTimesVector:
|
||||
newComps = getMatrixRows();
|
||||
break;
|
||||
case EOpVectorTimesMatrix:
|
||||
newComps = rightNode->getMatrixCols();
|
||||
break;
|
||||
default:
|
||||
newComps = getType().computeNumComponents();
|
||||
constComps = rightConstantNode->getType().computeNumComponents();
|
||||
if (constComps == 1 && newComps > 1) {
|
||||
// for a case like vec4 f = vec4(2,3,4,5) + 1.2;
|
||||
TConstUnionArray smearedArray(newComps, rightNode->getConstArray()[0]);
|
||||
rightUnionArray = smearedArray;
|
||||
} else if (constComps > 1 && newComps == 1) {
|
||||
// for a case like vec4 f = 1.2 + vec4(2,3,4,5);
|
||||
newComps = constComps;
|
||||
rightUnionArray = rightNode->getConstArray();
|
||||
TConstUnionArray smearedArray(newComps, getConstArray()[0]);
|
||||
leftUnionArray = smearedArray;
|
||||
returnType.shallowCopy(rightNode->getType());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
TConstUnionArray newConstArray(newComps);
|
||||
TType constBool(EbtBool, EvqConst);
|
||||
|
||||
switch(op) {
|
||||
case EOpAdd:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] + rightUnionArray[i];
|
||||
break;
|
||||
case EOpSub:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] - rightUnionArray[i];
|
||||
break;
|
||||
|
||||
case EOpMul:
|
||||
case EOpVectorTimesScalar:
|
||||
case EOpMatrixTimesScalar:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] * rightUnionArray[i];
|
||||
break;
|
||||
case EOpMatrixTimesMatrix:
|
||||
for (int row = 0; row < getMatrixRows(); row++) {
|
||||
for (int column = 0; column < rightNode->getMatrixCols(); column++) {
|
||||
double sum = 0.0f;
|
||||
for (int i = 0; i < rightNode->getMatrixRows(); i++)
|
||||
sum += leftUnionArray[i * getMatrixRows() + row].getDConst() * rightUnionArray[column * rightNode->getMatrixRows() + i].getDConst();
|
||||
newConstArray[column * getMatrixRows() + row].setDConst(sum);
|
||||
}
|
||||
}
|
||||
returnType.shallowCopy(TType(getType().getBasicType(), EvqConst, 0, rightNode->getMatrixCols(), getMatrixRows()));
|
||||
break;
|
||||
case EOpDiv:
|
||||
for (int i = 0; i < newComps; i++) {
|
||||
switch (getType().getBasicType()) {
|
||||
case EbtDouble:
|
||||
case EbtFloat:
|
||||
newConstArray[i].setDConst(leftUnionArray[i].getDConst() / rightUnionArray[i].getDConst());
|
||||
break;
|
||||
|
||||
case EbtInt:
|
||||
if (rightUnionArray[i] == 0)
|
||||
newConstArray[i].setIConst(0x7FFFFFFF);
|
||||
else if (rightUnionArray[i].getIConst() == -1 && leftUnionArray[i].getIConst() == (int)0x80000000)
|
||||
newConstArray[i].setIConst(0x80000000);
|
||||
else
|
||||
newConstArray[i].setIConst(leftUnionArray[i].getIConst() / rightUnionArray[i].getIConst());
|
||||
break;
|
||||
|
||||
case EbtUint:
|
||||
if (rightUnionArray[i] == 0) {
|
||||
newConstArray[i].setUConst(0xFFFFFFFF);
|
||||
} else
|
||||
newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst());
|
||||
break;
|
||||
|
||||
case EbtInt64:
|
||||
if (rightUnionArray[i] == 0)
|
||||
newConstArray[i].setI64Const(0x7FFFFFFFFFFFFFFFll);
|
||||
else if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == (long long)0x8000000000000000)
|
||||
newConstArray[i].setI64Const(0x8000000000000000);
|
||||
else
|
||||
newConstArray[i].setI64Const(leftUnionArray[i].getI64Const() / rightUnionArray[i].getI64Const());
|
||||
break;
|
||||
|
||||
case EbtUint64:
|
||||
if (rightUnionArray[i] == 0) {
|
||||
newConstArray[i].setU64Const(0xFFFFFFFFFFFFFFFFull);
|
||||
} else
|
||||
newConstArray[i].setU64Const(leftUnionArray[i].getU64Const() / rightUnionArray[i].getU64Const());
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EOpMatrixTimesVector:
|
||||
for (int i = 0; i < getMatrixRows(); i++) {
|
||||
double sum = 0.0f;
|
||||
for (int j = 0; j < rightNode->getVectorSize(); j++) {
|
||||
sum += leftUnionArray[j*getMatrixRows() + i].getDConst() * rightUnionArray[j].getDConst();
|
||||
}
|
||||
newConstArray[i].setDConst(sum);
|
||||
}
|
||||
|
||||
returnType.shallowCopy(TType(getBasicType(), EvqConst, getMatrixRows()));
|
||||
break;
|
||||
|
||||
case EOpVectorTimesMatrix:
|
||||
for (int i = 0; i < rightNode->getMatrixCols(); i++) {
|
||||
double sum = 0.0f;
|
||||
for (int j = 0; j < getVectorSize(); j++)
|
||||
sum += leftUnionArray[j].getDConst() * rightUnionArray[i*rightNode->getMatrixRows() + j].getDConst();
|
||||
newConstArray[i].setDConst(sum);
|
||||
}
|
||||
|
||||
returnType.shallowCopy(TType(getBasicType(), EvqConst, rightNode->getMatrixCols()));
|
||||
break;
|
||||
|
||||
case EOpMod:
|
||||
for (int i = 0; i < newComps; i++) {
|
||||
if (rightUnionArray[i] == 0)
|
||||
newConstArray[i] = leftUnionArray[i];
|
||||
else
|
||||
newConstArray[i] = leftUnionArray[i] % rightUnionArray[i];
|
||||
}
|
||||
break;
|
||||
|
||||
case EOpRightShift:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] >> rightUnionArray[i];
|
||||
break;
|
||||
|
||||
case EOpLeftShift:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] << rightUnionArray[i];
|
||||
break;
|
||||
|
||||
case EOpAnd:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] & rightUnionArray[i];
|
||||
break;
|
||||
case EOpInclusiveOr:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] | rightUnionArray[i];
|
||||
break;
|
||||
case EOpExclusiveOr:
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] ^ rightUnionArray[i];
|
||||
break;
|
||||
|
||||
case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] && rightUnionArray[i];
|
||||
break;
|
||||
|
||||
case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
|
||||
for (int i = 0; i < newComps; i++)
|
||||
newConstArray[i] = leftUnionArray[i] || rightUnionArray[i];
|
||||
break;
|
||||
|
||||
case EOpLogicalXor:
|
||||
for (int i = 0; i < newComps; i++) {
|
||||
switch (getType().getBasicType()) {
|
||||
case EbtBool: newConstArray[i].setBConst((leftUnionArray[i] == rightUnionArray[i]) ? false : true); break;
|
||||
default: assert(false && "Default missing");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EOpLessThan:
|
||||
newConstArray[0].setBConst(leftUnionArray[0] < rightUnionArray[0]);
|
||||
returnType.shallowCopy(constBool);
|
||||
break;
|
||||
case EOpGreaterThan:
|
||||
newConstArray[0].setBConst(leftUnionArray[0] > rightUnionArray[0]);
|
||||
returnType.shallowCopy(constBool);
|
||||
break;
|
||||
case EOpLessThanEqual:
|
||||
newConstArray[0].setBConst(! (leftUnionArray[0] > rightUnionArray[0]));
|
||||
returnType.shallowCopy(constBool);
|
||||
break;
|
||||
case EOpGreaterThanEqual:
|
||||
newConstArray[0].setBConst(! (leftUnionArray[0] < rightUnionArray[0]));
|
||||
returnType.shallowCopy(constBool);
|
||||
break;
|
||||
case EOpEqual:
|
||||
newConstArray[0].setBConst(rightNode->getConstArray() == leftUnionArray);
|
||||
returnType.shallowCopy(constBool);
|
||||
break;
|
||||
case EOpNotEqual:
|
||||
newConstArray[0].setBConst(rightNode->getConstArray() != leftUnionArray);
|
||||
returnType.shallowCopy(constBool);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
|
||||
newNode->setLoc(getLoc());
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
//
|
||||
// Do single unary node folding
|
||||
//
|
||||
// Returns a new node representing the result.
|
||||
//
|
||||
TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) const
|
||||
{
|
||||
// First, size the result, which is mostly the same as the argument's size,
|
||||
// but not always, and classify what is componentwise.
|
||||
// Also, eliminate cases that can't be compile-time constant.
|
||||
int resultSize;
|
||||
bool componentWise = true;
|
||||
|
||||
int objectSize = getType().computeNumComponents();
|
||||
switch (op) {
|
||||
case EOpDeterminant:
|
||||
case EOpAny:
|
||||
case EOpAll:
|
||||
case EOpLength:
|
||||
componentWise = false;
|
||||
resultSize = 1;
|
||||
break;
|
||||
|
||||
case EOpEmitStreamVertex:
|
||||
case EOpEndStreamPrimitive:
|
||||
// These don't actually fold
|
||||
return 0;
|
||||
|
||||
case EOpPackSnorm2x16:
|
||||
case EOpPackUnorm2x16:
|
||||
case EOpPackHalf2x16:
|
||||
componentWise = false;
|
||||
resultSize = 1;
|
||||
break;
|
||||
|
||||
case EOpUnpackSnorm2x16:
|
||||
case EOpUnpackUnorm2x16:
|
||||
case EOpUnpackHalf2x16:
|
||||
componentWise = false;
|
||||
resultSize = 2;
|
||||
break;
|
||||
|
||||
case EOpNormalize:
|
||||
componentWise = false;
|
||||
resultSize = objectSize;
|
||||
break;
|
||||
|
||||
default:
|
||||
resultSize = objectSize;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set up for processing
|
||||
TConstUnionArray newConstArray(resultSize);
|
||||
const TConstUnionArray& unionArray = getConstArray();
|
||||
|
||||
// Process non-component-wise operations
|
||||
switch (op) {
|
||||
case EOpLength:
|
||||
case EOpNormalize:
|
||||
{
|
||||
double sum = 0;
|
||||
for (int i = 0; i < objectSize; i++)
|
||||
sum += unionArray[i].getDConst() * unionArray[i].getDConst();
|
||||
double length = sqrt(sum);
|
||||
if (op == EOpLength)
|
||||
newConstArray[0].setDConst(length);
|
||||
else {
|
||||
for (int i = 0; i < objectSize; i++)
|
||||
newConstArray[i].setDConst(unionArray[i].getDConst() / length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EOpAny:
|
||||
{
|
||||
bool result = false;
|
||||
for (int i = 0; i < objectSize; i++) {
|
||||
if (unionArray[i].getBConst())
|
||||
result = true;
|
||||
}
|
||||
newConstArray[0].setBConst(result);
|
||||
break;
|
||||
}
|
||||
case EOpAll:
|
||||
{
|
||||
bool result = true;
|
||||
for (int i = 0; i < objectSize; i++) {
|
||||
if (! unionArray[i].getBConst())
|
||||
result = false;
|
||||
}
|
||||
newConstArray[0].setBConst(result);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
|
||||
|
||||
case EOpPackSnorm2x16:
|
||||
case EOpPackUnorm2x16:
|
||||
case EOpPackHalf2x16:
|
||||
|
||||
case EOpUnpackSnorm2x16:
|
||||
case EOpUnpackUnorm2x16:
|
||||
case EOpUnpackHalf2x16:
|
||||
|
||||
case EOpDeterminant:
|
||||
case EOpMatrixInverse:
|
||||
case EOpTranspose:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
assert(componentWise);
|
||||
break;
|
||||
}
|
||||
|
||||
// Turn off the componentwise loop
|
||||
if (! componentWise)
|
||||
objectSize = 0;
|
||||
|
||||
// Process component-wise operations
|
||||
for (int i = 0; i < objectSize; i++) {
|
||||
switch (op) {
|
||||
case EOpNegative:
|
||||
switch (getType().getBasicType()) {
|
||||
case EbtDouble:
|
||||
case EbtFloat: newConstArray[i].setDConst(-unionArray[i].getDConst()); break;
|
||||
case EbtInt: newConstArray[i].setIConst(-unionArray[i].getIConst()); break;
|
||||
case EbtUint: newConstArray[i].setUConst(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getUConst()))); break;
|
||||
case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break;
|
||||
case EbtUint64: newConstArray[i].setU64Const(static_cast<unsigned int>(-static_cast<int>(unionArray[i].getU64Const()))); break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case EOpLogicalNot:
|
||||
case EOpVectorLogicalNot:
|
||||
switch (getType().getBasicType()) {
|
||||
case EbtBool: newConstArray[i].setBConst(!unionArray[i].getBConst()); break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case EOpBitwiseNot:
|
||||
newConstArray[i] = ~unionArray[i];
|
||||
break;
|
||||
case EOpRadians:
|
||||
newConstArray[i].setDConst(unionArray[i].getDConst() * pi / 180.0);
|
||||
break;
|
||||
case EOpDegrees:
|
||||
newConstArray[i].setDConst(unionArray[i].getDConst() * 180.0 / pi);
|
||||
break;
|
||||
case EOpSin:
|
||||
newConstArray[i].setDConst(sin(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpCos:
|
||||
newConstArray[i].setDConst(cos(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpTan:
|
||||
newConstArray[i].setDConst(tan(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpAsin:
|
||||
newConstArray[i].setDConst(asin(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpAcos:
|
||||
newConstArray[i].setDConst(acos(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpAtan:
|
||||
newConstArray[i].setDConst(atan(unionArray[i].getDConst()));
|
||||
break;
|
||||
|
||||
case EOpDPdx:
|
||||
case EOpDPdy:
|
||||
case EOpFwidth:
|
||||
case EOpDPdxFine:
|
||||
case EOpDPdyFine:
|
||||
case EOpFwidthFine:
|
||||
case EOpDPdxCoarse:
|
||||
case EOpDPdyCoarse:
|
||||
case EOpFwidthCoarse:
|
||||
// The derivatives are all mandated to create a constant 0.
|
||||
newConstArray[i].setDConst(0.0);
|
||||
break;
|
||||
|
||||
case EOpExp:
|
||||
newConstArray[i].setDConst(exp(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpLog:
|
||||
newConstArray[i].setDConst(log(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpExp2:
|
||||
{
|
||||
const double inv_log2_e = 0.69314718055994530941723212145818;
|
||||
newConstArray[i].setDConst(exp(unionArray[i].getDConst() * inv_log2_e));
|
||||
break;
|
||||
}
|
||||
case EOpLog2:
|
||||
{
|
||||
const double log2_e = 1.4426950408889634073599246810019;
|
||||
newConstArray[i].setDConst(log2_e * log(unionArray[i].getDConst()));
|
||||
break;
|
||||
}
|
||||
case EOpSqrt:
|
||||
newConstArray[i].setDConst(sqrt(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpInverseSqrt:
|
||||
newConstArray[i].setDConst(1.0 / sqrt(unionArray[i].getDConst()));
|
||||
break;
|
||||
|
||||
case EOpAbs:
|
||||
if (unionArray[i].getType() == EbtDouble)
|
||||
newConstArray[i].setDConst(fabs(unionArray[i].getDConst()));
|
||||
else if (unionArray[i].getType() == EbtInt)
|
||||
newConstArray[i].setIConst(abs(unionArray[i].getIConst()));
|
||||
else
|
||||
newConstArray[i] = unionArray[i];
|
||||
break;
|
||||
case EOpSign:
|
||||
#define SIGN(X) (X == 0 ? 0 : (X < 0 ? -1 : 1))
|
||||
if (unionArray[i].getType() == EbtDouble)
|
||||
newConstArray[i].setDConst(SIGN(unionArray[i].getDConst()));
|
||||
else
|
||||
newConstArray[i].setIConst(SIGN(unionArray[i].getIConst()));
|
||||
break;
|
||||
case EOpFloor:
|
||||
newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpTrunc:
|
||||
if (unionArray[i].getDConst() > 0)
|
||||
newConstArray[i].setDConst(floor(unionArray[i].getDConst()));
|
||||
else
|
||||
newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpRound:
|
||||
newConstArray[i].setDConst(floor(0.5 + unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpRoundEven:
|
||||
{
|
||||
double flr = floor(unionArray[i].getDConst());
|
||||
bool even = flr / 2.0 == floor(flr / 2.0);
|
||||
double rounded = even ? ceil(unionArray[i].getDConst() - 0.5) : floor(unionArray[i].getDConst() + 0.5);
|
||||
newConstArray[i].setDConst(rounded);
|
||||
break;
|
||||
}
|
||||
case EOpCeil:
|
||||
newConstArray[i].setDConst(ceil(unionArray[i].getDConst()));
|
||||
break;
|
||||
case EOpFract:
|
||||
{
|
||||
double x = unionArray[i].getDConst();
|
||||
newConstArray[i].setDConst(x - floor(x));
|
||||
break;
|
||||
}
|
||||
|
||||
case EOpIsNan:
|
||||
{
|
||||
newConstArray[i].setBConst(isNan(unionArray[i].getDConst()));
|
||||
break;
|
||||
}
|
||||
case EOpIsInf:
|
||||
{
|
||||
newConstArray[i].setBConst(isInf(unionArray[i].getDConst()));
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out
|
||||
|
||||
case EOpSinh:
|
||||
case EOpCosh:
|
||||
case EOpTanh:
|
||||
case EOpAsinh:
|
||||
case EOpAcosh:
|
||||
case EOpAtanh:
|
||||
|
||||
case EOpFloatBitsToInt:
|
||||
case EOpFloatBitsToUint:
|
||||
case EOpIntBitsToFloat:
|
||||
case EOpUintBitsToFloat:
|
||||
case EOpDoubleBitsToInt64:
|
||||
case EOpDoubleBitsToUint64:
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType);
|
||||
newNode->getWritableType().getQualifier().storage = EvqConst;
|
||||
newNode->setLoc(getLoc());
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
//
|
||||
// Do constant folding for an aggregate node that has all its children
|
||||
// as constants and an operator that requires constant folding.
|
||||
//
|
||||
TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode)
|
||||
{
|
||||
if (! areAllChildConst(aggrNode))
|
||||
return aggrNode;
|
||||
|
||||
if (aggrNode->isConstructor())
|
||||
return foldConstructor(aggrNode);
|
||||
|
||||
TIntermSequence& children = aggrNode->getSequence();
|
||||
|
||||
// First, see if this is an operation to constant fold, kick out if not,
|
||||
// see what size the result is if so.
|
||||
|
||||
bool componentwise = false; // will also say componentwise if a scalar argument gets repeated to make per-component results
|
||||
int objectSize;
|
||||
switch (aggrNode->getOp()) {
|
||||
case EOpAtan:
|
||||
case EOpPow:
|
||||
case EOpMin:
|
||||
case EOpMax:
|
||||
case EOpMix:
|
||||
case EOpClamp:
|
||||
case EOpLessThan:
|
||||
case EOpGreaterThan:
|
||||
case EOpLessThanEqual:
|
||||
case EOpGreaterThanEqual:
|
||||
case EOpVectorEqual:
|
||||
case EOpVectorNotEqual:
|
||||
componentwise = true;
|
||||
objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
|
||||
break;
|
||||
case EOpCross:
|
||||
case EOpReflect:
|
||||
case EOpRefract:
|
||||
case EOpFaceForward:
|
||||
objectSize = children[0]->getAsConstantUnion()->getType().computeNumComponents();
|
||||
break;
|
||||
case EOpDistance:
|
||||
case EOpDot:
|
||||
objectSize = 1;
|
||||
break;
|
||||
case EOpOuterProduct:
|
||||
objectSize = children[0]->getAsTyped()->getType().getVectorSize() *
|
||||
children[1]->getAsTyped()->getType().getVectorSize();
|
||||
break;
|
||||
case EOpStep:
|
||||
componentwise = true;
|
||||
objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
|
||||
children[1]->getAsTyped()->getType().getVectorSize());
|
||||
break;
|
||||
case EOpSmoothStep:
|
||||
componentwise = true;
|
||||
objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(),
|
||||
children[2]->getAsTyped()->getType().getVectorSize());
|
||||
break;
|
||||
default:
|
||||
return aggrNode;
|
||||
}
|
||||
TConstUnionArray newConstArray(objectSize);
|
||||
|
||||
TVector<TConstUnionArray> childConstUnions;
|
||||
for (unsigned int arg = 0; arg < children.size(); ++arg)
|
||||
childConstUnions.push_back(children[arg]->getAsConstantUnion()->getConstArray());
|
||||
|
||||
// Second, do the actual folding
|
||||
|
||||
bool isFloatingPoint = children[0]->getAsTyped()->getBasicType() == EbtFloat ||
|
||||
children[0]->getAsTyped()->getBasicType() == EbtDouble;
|
||||
bool isSigned = children[0]->getAsTyped()->getBasicType() == EbtInt ||
|
||||
children[0]->getAsTyped()->getBasicType() == EbtInt64;
|
||||
bool isInt64 = children[0]->getAsTyped()->getBasicType() == EbtInt64 ||
|
||||
children[0]->getAsTyped()->getBasicType() == EbtUint64;
|
||||
if (componentwise) {
|
||||
for (int comp = 0; comp < objectSize; comp++) {
|
||||
|
||||
// some arguments are scalars instead of matching vectors; simulate a smear
|
||||
int arg0comp = std::min(comp, children[0]->getAsTyped()->getType().getVectorSize() - 1);
|
||||
int arg1comp = 0;
|
||||
if (children.size() > 1)
|
||||
arg1comp = std::min(comp, children[1]->getAsTyped()->getType().getVectorSize() - 1);
|
||||
int arg2comp = 0;
|
||||
if (children.size() > 2)
|
||||
arg2comp = std::min(comp, children[2]->getAsTyped()->getType().getVectorSize() - 1);
|
||||
|
||||
switch (aggrNode->getOp()) {
|
||||
case EOpAtan:
|
||||
newConstArray[comp].setDConst(atan2(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
|
||||
break;
|
||||
case EOpPow:
|
||||
newConstArray[comp].setDConst(pow(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
|
||||
break;
|
||||
case EOpMin:
|
||||
if (isFloatingPoint)
|
||||
newConstArray[comp].setDConst(std::min(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
|
||||
else if (isSigned) {
|
||||
if (isInt64)
|
||||
newConstArray[comp].setI64Const(std::min(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
|
||||
else
|
||||
newConstArray[comp].setIConst(std::min(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
|
||||
} else {
|
||||
if (isInt64)
|
||||
newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
|
||||
else
|
||||
newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
|
||||
}
|
||||
break;
|
||||
case EOpMax:
|
||||
if (isFloatingPoint)
|
||||
newConstArray[comp].setDConst(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()));
|
||||
else if (isSigned) {
|
||||
if (isInt64)
|
||||
newConstArray[comp].setI64Const(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()));
|
||||
else
|
||||
newConstArray[comp].setIConst(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()));
|
||||
} else {
|
||||
if (isInt64)
|
||||
newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()));
|
||||
else
|
||||
newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()));
|
||||
}
|
||||
break;
|
||||
case EOpClamp:
|
||||
if (isFloatingPoint)
|
||||
newConstArray[comp].setDConst(std::min(std::max(childConstUnions[0][arg0comp].getDConst(), childConstUnions[1][arg1comp].getDConst()),
|
||||
childConstUnions[2][arg2comp].getDConst()));
|
||||
else if (isSigned) {
|
||||
if (isInt64)
|
||||
newConstArray[comp].setI64Const(std::min(std::max(childConstUnions[0][arg0comp].getI64Const(), childConstUnions[1][arg1comp].getI64Const()),
|
||||
childConstUnions[2][arg2comp].getI64Const()));
|
||||
else
|
||||
newConstArray[comp].setIConst(std::min(std::max(childConstUnions[0][arg0comp].getIConst(), childConstUnions[1][arg1comp].getIConst()),
|
||||
childConstUnions[2][arg2comp].getIConst()));
|
||||
} else {
|
||||
if (isInt64)
|
||||
newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()),
|
||||
childConstUnions[2][arg2comp].getU64Const()));
|
||||
else
|
||||
newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()),
|
||||
childConstUnions[2][arg2comp].getUConst()));
|
||||
}
|
||||
break;
|
||||
case EOpLessThan:
|
||||
newConstArray[comp].setBConst(childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]);
|
||||
break;
|
||||
case EOpGreaterThan:
|
||||
newConstArray[comp].setBConst(childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]);
|
||||
break;
|
||||
case EOpLessThanEqual:
|
||||
newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] > childConstUnions[1][arg1comp]));
|
||||
break;
|
||||
case EOpGreaterThanEqual:
|
||||
newConstArray[comp].setBConst(! (childConstUnions[0][arg0comp] < childConstUnions[1][arg1comp]));
|
||||
break;
|
||||
case EOpVectorEqual:
|
||||
newConstArray[comp].setBConst(childConstUnions[0][arg0comp] == childConstUnions[1][arg1comp]);
|
||||
break;
|
||||
case EOpVectorNotEqual:
|
||||
newConstArray[comp].setBConst(childConstUnions[0][arg0comp] != childConstUnions[1][arg1comp]);
|
||||
break;
|
||||
case EOpMix:
|
||||
if (children[2]->getAsTyped()->getBasicType() == EbtBool)
|
||||
newConstArray[comp].setDConst(childConstUnions[2][arg2comp].getBConst() ? childConstUnions[1][arg1comp].getDConst() :
|
||||
childConstUnions[0][arg0comp].getDConst());
|
||||
else
|
||||
newConstArray[comp].setDConst(childConstUnions[0][arg0comp].getDConst() * (1.0 - childConstUnions[2][arg2comp].getDConst()) +
|
||||
childConstUnions[1][arg1comp].getDConst() * childConstUnions[2][arg2comp].getDConst());
|
||||
break;
|
||||
case EOpStep:
|
||||
newConstArray[comp].setDConst(childConstUnions[1][arg1comp].getDConst() < childConstUnions[0][arg0comp].getDConst() ? 0.0 : 1.0);
|
||||
break;
|
||||
case EOpSmoothStep:
|
||||
{
|
||||
double t = (childConstUnions[2][arg2comp].getDConst() - childConstUnions[0][arg0comp].getDConst()) /
|
||||
(childConstUnions[1][arg1comp].getDConst() - childConstUnions[0][arg0comp].getDConst());
|
||||
if (t < 0.0)
|
||||
t = 0.0;
|
||||
if (t > 1.0)
|
||||
t = 1.0;
|
||||
newConstArray[comp].setDConst(t * t * (3.0 - 2.0 * t));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return aggrNode;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Non-componentwise...
|
||||
|
||||
int numComps = children[0]->getAsConstantUnion()->getType().computeNumComponents();
|
||||
double dot;
|
||||
|
||||
switch (aggrNode->getOp()) {
|
||||
case EOpDistance:
|
||||
{
|
||||
double sum = 0.0;
|
||||
for (int comp = 0; comp < numComps; ++comp) {
|
||||
double diff = childConstUnions[1][comp].getDConst() - childConstUnions[0][comp].getDConst();
|
||||
sum += diff * diff;
|
||||
}
|
||||
newConstArray[0].setDConst(sqrt(sum));
|
||||
break;
|
||||
}
|
||||
case EOpDot:
|
||||
newConstArray[0].setDConst(childConstUnions[0].dot(childConstUnions[1]));
|
||||
break;
|
||||
case EOpCross:
|
||||
newConstArray[0] = childConstUnions[0][1] * childConstUnions[1][2] - childConstUnions[0][2] * childConstUnions[1][1];
|
||||
newConstArray[1] = childConstUnions[0][2] * childConstUnions[1][0] - childConstUnions[0][0] * childConstUnions[1][2];
|
||||
newConstArray[2] = childConstUnions[0][0] * childConstUnions[1][1] - childConstUnions[0][1] * childConstUnions[1][0];
|
||||
break;
|
||||
case EOpFaceForward:
|
||||
// If dot(Nref, I) < 0 return N, otherwise return –N: Arguments are (N, I, Nref).
|
||||
dot = childConstUnions[1].dot(childConstUnions[2]);
|
||||
for (int comp = 0; comp < numComps; ++comp) {
|
||||
if (dot < 0.0)
|
||||
newConstArray[comp] = childConstUnions[0][comp];
|
||||
else
|
||||
newConstArray[comp].setDConst(-childConstUnions[0][comp].getDConst());
|
||||
}
|
||||
break;
|
||||
case EOpReflect:
|
||||
// I - 2 * dot(N, I) * N: Arguments are (I, N).
|
||||
dot = childConstUnions[0].dot(childConstUnions[1]);
|
||||
dot *= 2.0;
|
||||
for (int comp = 0; comp < numComps; ++comp)
|
||||
newConstArray[comp].setDConst(childConstUnions[0][comp].getDConst() - dot * childConstUnions[1][comp].getDConst());
|
||||
break;
|
||||
case EOpRefract:
|
||||
{
|
||||
// Arguments are (I, N, eta).
|
||||
// k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
|
||||
// if (k < 0.0)
|
||||
// return dvec(0.0)
|
||||
// else
|
||||
// return eta * I - (eta * dot(N, I) + sqrt(k)) * N
|
||||
dot = childConstUnions[0].dot(childConstUnions[1]);
|
||||
double eta = childConstUnions[2][0].getDConst();
|
||||
double k = 1.0 - eta * eta * (1.0 - dot * dot);
|
||||
if (k < 0.0) {
|
||||
for (int comp = 0; comp < numComps; ++comp)
|
||||
newConstArray[comp].setDConst(0.0);
|
||||
} else {
|
||||
for (int comp = 0; comp < numComps; ++comp)
|
||||
newConstArray[comp].setDConst(eta * childConstUnions[0][comp].getDConst() - (eta * dot + sqrt(k)) * childConstUnions[1][comp].getDConst());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EOpOuterProduct:
|
||||
{
|
||||
int numRows = numComps;
|
||||
int numCols = children[1]->getAsConstantUnion()->getType().computeNumComponents();
|
||||
for (int row = 0; row < numRows; ++row)
|
||||
for (int col = 0; col < numCols; ++col)
|
||||
newConstArray[col * numRows + row] = childConstUnions[0][row] * childConstUnions[1][col];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return aggrNode;
|
||||
}
|
||||
}
|
||||
|
||||
TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, aggrNode->getType());
|
||||
newNode->getWritableType().getQualifier().storage = EvqConst;
|
||||
newNode->setLoc(aggrNode->getLoc());
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
bool TIntermediate::areAllChildConst(TIntermAggregate* aggrNode)
|
||||
{
|
||||
bool allConstant = true;
|
||||
|
||||
// check if all the child nodes are constants so that they can be inserted into
|
||||
// the parent node
|
||||
if (aggrNode) {
|
||||
TIntermSequence& childSequenceVector = aggrNode->getSequence();
|
||||
for (TIntermSequence::iterator p = childSequenceVector.begin();
|
||||
p != childSequenceVector.end(); p++) {
|
||||
if (!(*p)->getAsTyped()->getAsConstantUnion())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return allConstant;
|
||||
}
|
||||
|
||||
TIntermTyped* TIntermediate::foldConstructor(TIntermAggregate* aggrNode)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
TConstUnionArray unionArray(aggrNode->getType().computeNumComponents());
|
||||
if (aggrNode->getSequence().size() == 1)
|
||||
error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType(), true);
|
||||
else
|
||||
error = parseConstTree(aggrNode, unionArray, aggrNode->getOp(), aggrNode->getType());
|
||||
|
||||
if (error)
|
||||
return aggrNode;
|
||||
|
||||
return addConstantUnion(unionArray, aggrNode->getType(), aggrNode->getLoc());
|
||||
}
|
||||
|
||||
//
|
||||
// Constant folding of a bracket (array-style) dereference or struct-like dot
|
||||
// dereference. Can handle anything except a multi-character swizzle, though
|
||||
// all swizzles may go to foldSwizzle().
|
||||
//
|
||||
TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, const TSourceLoc& loc)
|
||||
{
|
||||
TType dereferencedType(node->getType(), index);
|
||||
dereferencedType.getQualifier().storage = EvqConst;
|
||||
TIntermTyped* result = 0;
|
||||
int size = dereferencedType.computeNumComponents();
|
||||
|
||||
// arrays, vectors, matrices, all use simple multiplicative math
|
||||
// while structures need to add up heterogeneous members
|
||||
int start;
|
||||
if (node->isArray() || ! node->isStruct())
|
||||
start = size * index;
|
||||
else {
|
||||
// it is a structure
|
||||
assert(node->isStruct());
|
||||
start = 0;
|
||||
for (int i = 0; i < index; ++i)
|
||||
start += (*node->getType().getStruct())[i].type->computeNumComponents();
|
||||
}
|
||||
|
||||
result = addConstantUnion(TConstUnionArray(node->getAsConstantUnion()->getConstArray(), start, size), node->getType(), loc);
|
||||
|
||||
if (result == 0)
|
||||
result = node;
|
||||
else
|
||||
result->setType(dereferencedType);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Make a constant vector node or constant scalar node, representing a given
|
||||
// constant vector and constant swizzle into it.
|
||||
//
|
||||
TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc& loc)
|
||||
{
|
||||
const TConstUnionArray& unionArray = node->getAsConstantUnion()->getConstArray();
|
||||
TConstUnionArray constArray(fields.num);
|
||||
|
||||
for (int i = 0; i < fields.num; i++)
|
||||
constArray[i] = unionArray[fields.offsets[i]];
|
||||
|
||||
TIntermTyped* result = addConstantUnion(constArray, node->getType(), loc);
|
||||
|
||||
if (result == 0)
|
||||
result = node;
|
||||
else
|
||||
result->setType(TType(node->getBasicType(), EvqConst, fields.num));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "../Include/InfoSink.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
void TInfoSinkBase::append(const char* s)
|
||||
{
|
||||
if (outputStream & EString) {
|
||||
checkMem(strlen(s));
|
||||
sink.append(s);
|
||||
}
|
||||
|
||||
//#ifdef _WIN32
|
||||
// if (outputStream & EDebugger)
|
||||
// OutputDebugString(s);
|
||||
//#endif
|
||||
|
||||
if (outputStream & EStdOut)
|
||||
fprintf(stdout, "%s", s);
|
||||
}
|
||||
|
||||
void TInfoSinkBase::append(int count, char c)
|
||||
{
|
||||
if (outputStream & EString) {
|
||||
checkMem(count);
|
||||
sink.append(count, c);
|
||||
}
|
||||
|
||||
//#ifdef _WIN32
|
||||
// if (outputStream & EDebugger) {
|
||||
// char str[2];
|
||||
// str[0] = c;
|
||||
// str[1] = '\0';
|
||||
// OutputDebugString(str);
|
||||
// }
|
||||
//#endif
|
||||
|
||||
if (outputStream & EStdOut)
|
||||
fprintf(stdout, "%c", c);
|
||||
}
|
||||
|
||||
void TInfoSinkBase::append(const TPersistString& t)
|
||||
{
|
||||
if (outputStream & EString) {
|
||||
checkMem(t.size());
|
||||
sink.append(t);
|
||||
}
|
||||
|
||||
//#ifdef _WIN32
|
||||
// if (outputStream & EDebugger)
|
||||
// OutputDebugString(t.c_str());
|
||||
//#endif
|
||||
|
||||
if (outputStream & EStdOut)
|
||||
fprintf(stdout, "%s", t.c_str());
|
||||
}
|
||||
|
||||
void TInfoSinkBase::append(const TString& t)
|
||||
{
|
||||
if (outputStream & EString) {
|
||||
checkMem(t.size());
|
||||
sink.append(t.c_str());
|
||||
}
|
||||
|
||||
//#ifdef _WIN32
|
||||
// if (outputStream & EDebugger)
|
||||
// OutputDebugString(t.c_str());
|
||||
//#endif
|
||||
|
||||
if (outputStream & EStdOut)
|
||||
fprintf(stdout, "%s", t.c_str());
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013-2016 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _INITIALIZE_INCLUDED_
|
||||
#define _INITIALIZE_INCLUDED_
|
||||
|
||||
#include "../Include/ResourceLimits.h"
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/ShHandle.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Versions.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// This is made to hold parseable strings for almost all the built-in
|
||||
// functions and variables for one specific combination of version
|
||||
// and profile. (Some still need to be added programmatically.)
|
||||
// This is a base class for language-specific derivations, which
|
||||
// can be used for language independent builtins.
|
||||
//
|
||||
// The strings are organized by
|
||||
// commonBuiltins: intersection of all stages' built-ins, processed just once
|
||||
// stageBuiltins[]: anything a stage needs that's not in commonBuiltins
|
||||
//
|
||||
class TBuiltInParseables {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
TBuiltInParseables();
|
||||
virtual ~TBuiltInParseables();
|
||||
virtual void initialize(int version, EProfile, const SpvVersion& spvVersion) = 0;
|
||||
virtual void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage) = 0;
|
||||
virtual const TString& getCommonString() const { return commonBuiltins; }
|
||||
virtual const TString& getStageString(EShLanguage language) const { return stageBuiltins[language]; }
|
||||
|
||||
virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable) = 0;
|
||||
|
||||
virtual void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) = 0;
|
||||
|
||||
protected:
|
||||
TString commonBuiltins;
|
||||
TString stageBuiltins[EShLangCount];
|
||||
};
|
||||
|
||||
//
|
||||
// This is a GLSL specific derivation of TBuiltInParseables. To present a stable
|
||||
// interface and match other similar code, it is called TBuiltIns, rather
|
||||
// than TBuiltInParseablesGlsl.
|
||||
//
|
||||
class TBuiltIns : public TBuiltInParseables {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
TBuiltIns();
|
||||
virtual ~TBuiltIns();
|
||||
void initialize(int version, EProfile, const SpvVersion& spvVersion);
|
||||
void initialize(const TBuiltInResource& resources, int version, EProfile, const SpvVersion& spvVersion, EShLanguage);
|
||||
|
||||
void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable);
|
||||
|
||||
void identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources);
|
||||
|
||||
protected:
|
||||
void add2ndGenerationSamplingImaging(int version, EProfile profile, const SpvVersion& spvVersion);
|
||||
void addSubpassSampling(TSampler, TString& typeName, int version, EProfile profile);
|
||||
void addQueryFunctions(TSampler, TString& typeName, int version, EProfile profile);
|
||||
void addImageFunctions(TSampler, TString& typeName, int version, EProfile profile);
|
||||
void addSamplingFunctions(TSampler, TString& typeName, int version, EProfile profile);
|
||||
void addGatherFunctions(TSampler, TString& typeName, int version, EProfile profile);
|
||||
|
||||
// Helpers for making textual representations of the permutations
|
||||
// of texturing/imaging functions.
|
||||
const char* postfixes[5];
|
||||
const char* prefixes[EbtNumTypes];
|
||||
int dimMap[EsdNumDims];
|
||||
};
|
||||
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _INITIALIZE_INCLUDED_
|
|
@ -0,0 +1,302 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//Copyright (c) 2002-2010 The ANGLE Project Authors.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "../Include/intermediate.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Traverse the intermediate representation tree, and
|
||||
// call a node type specific function for each node.
|
||||
// Done recursively through the member function Traverse().
|
||||
// Node types can be skipped if their function to call is 0,
|
||||
// but their subtree will still be traversed.
|
||||
// Nodes with children can have their whole subtree skipped
|
||||
// if preVisit is turned on and the type specific function
|
||||
// returns false.
|
||||
//
|
||||
// preVisit, postVisit, and rightToLeft control what order
|
||||
// nodes are visited in.
|
||||
//
|
||||
|
||||
//
|
||||
// Traversal functions for terminals are straightforward....
|
||||
//
|
||||
void TIntermMethod::traverse(TIntermTraverser*)
|
||||
{
|
||||
// Tree should always resolve all methods as a non-method.
|
||||
}
|
||||
|
||||
void TIntermSymbol::traverse(TIntermTraverser *it)
|
||||
{
|
||||
it->visitSymbol(this);
|
||||
}
|
||||
|
||||
void TIntermConstantUnion::traverse(TIntermTraverser *it)
|
||||
{
|
||||
it->visitConstantUnion(this);
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse a binary node.
|
||||
//
|
||||
void TIntermBinary::traverse(TIntermTraverser *it)
|
||||
{
|
||||
bool visit = true;
|
||||
|
||||
//
|
||||
// visit the node before children if pre-visiting.
|
||||
//
|
||||
if (it->preVisit)
|
||||
visit = it->visitBinary(EvPreVisit, this);
|
||||
|
||||
//
|
||||
// Visit the children, in the right order.
|
||||
//
|
||||
if (visit) {
|
||||
it->incrementDepth(this);
|
||||
|
||||
if (it->rightToLeft) {
|
||||
if (right)
|
||||
right->traverse(it);
|
||||
|
||||
if (it->inVisit)
|
||||
visit = it->visitBinary(EvInVisit, this);
|
||||
|
||||
if (visit && left)
|
||||
left->traverse(it);
|
||||
} else {
|
||||
if (left)
|
||||
left->traverse(it);
|
||||
|
||||
if (it->inVisit)
|
||||
visit = it->visitBinary(EvInVisit, this);
|
||||
|
||||
if (visit && right)
|
||||
right->traverse(it);
|
||||
}
|
||||
|
||||
it->decrementDepth();
|
||||
}
|
||||
|
||||
//
|
||||
// Visit the node after the children, if requested and the traversal
|
||||
// hasn't been canceled yet.
|
||||
//
|
||||
if (visit && it->postVisit)
|
||||
it->visitBinary(EvPostVisit, this);
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse a unary node. Same comments in binary node apply here.
|
||||
//
|
||||
void TIntermUnary::traverse(TIntermTraverser *it)
|
||||
{
|
||||
bool visit = true;
|
||||
|
||||
if (it->preVisit)
|
||||
visit = it->visitUnary(EvPreVisit, this);
|
||||
|
||||
if (visit) {
|
||||
it->incrementDepth(this);
|
||||
operand->traverse(it);
|
||||
it->decrementDepth();
|
||||
}
|
||||
|
||||
if (visit && it->postVisit)
|
||||
it->visitUnary(EvPostVisit, this);
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse an aggregate node. Same comments in binary node apply here.
|
||||
//
|
||||
void TIntermAggregate::traverse(TIntermTraverser *it)
|
||||
{
|
||||
bool visit = true;
|
||||
|
||||
if (it->preVisit)
|
||||
visit = it->visitAggregate(EvPreVisit, this);
|
||||
|
||||
if (visit) {
|
||||
it->incrementDepth(this);
|
||||
|
||||
if (it->rightToLeft) {
|
||||
for (TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++) {
|
||||
(*sit)->traverse(it);
|
||||
|
||||
if (visit && it->inVisit) {
|
||||
if (*sit != sequence.front())
|
||||
visit = it->visitAggregate(EvInVisit, this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) {
|
||||
(*sit)->traverse(it);
|
||||
|
||||
if (visit && it->inVisit) {
|
||||
if (*sit != sequence.back())
|
||||
visit = it->visitAggregate(EvInVisit, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
it->decrementDepth();
|
||||
}
|
||||
|
||||
if (visit && it->postVisit)
|
||||
it->visitAggregate(EvPostVisit, this);
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse a selection node. Same comments in binary node apply here.
|
||||
//
|
||||
void TIntermSelection::traverse(TIntermTraverser *it)
|
||||
{
|
||||
bool visit = true;
|
||||
|
||||
if (it->preVisit)
|
||||
visit = it->visitSelection(EvPreVisit, this);
|
||||
|
||||
if (visit) {
|
||||
it->incrementDepth(this);
|
||||
if (it->rightToLeft) {
|
||||
if (falseBlock)
|
||||
falseBlock->traverse(it);
|
||||
if (trueBlock)
|
||||
trueBlock->traverse(it);
|
||||
condition->traverse(it);
|
||||
} else {
|
||||
condition->traverse(it);
|
||||
if (trueBlock)
|
||||
trueBlock->traverse(it);
|
||||
if (falseBlock)
|
||||
falseBlock->traverse(it);
|
||||
}
|
||||
it->decrementDepth();
|
||||
}
|
||||
|
||||
if (visit && it->postVisit)
|
||||
it->visitSelection(EvPostVisit, this);
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse a loop node. Same comments in binary node apply here.
|
||||
//
|
||||
void TIntermLoop::traverse(TIntermTraverser *it)
|
||||
{
|
||||
bool visit = true;
|
||||
|
||||
if (it->preVisit)
|
||||
visit = it->visitLoop(EvPreVisit, this);
|
||||
|
||||
if (visit) {
|
||||
it->incrementDepth(this);
|
||||
|
||||
if (it->rightToLeft) {
|
||||
if (terminal)
|
||||
terminal->traverse(it);
|
||||
|
||||
if (body)
|
||||
body->traverse(it);
|
||||
|
||||
if (test)
|
||||
test->traverse(it);
|
||||
} else {
|
||||
if (test)
|
||||
test->traverse(it);
|
||||
|
||||
if (body)
|
||||
body->traverse(it);
|
||||
|
||||
if (terminal)
|
||||
terminal->traverse(it);
|
||||
}
|
||||
|
||||
it->decrementDepth();
|
||||
}
|
||||
|
||||
if (visit && it->postVisit)
|
||||
it->visitLoop(EvPostVisit, this);
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse a branch node. Same comments in binary node apply here.
|
||||
//
|
||||
void TIntermBranch::traverse(TIntermTraverser *it)
|
||||
{
|
||||
bool visit = true;
|
||||
|
||||
if (it->preVisit)
|
||||
visit = it->visitBranch(EvPreVisit, this);
|
||||
|
||||
if (visit && expression) {
|
||||
it->incrementDepth(this);
|
||||
expression->traverse(it);
|
||||
it->decrementDepth();
|
||||
}
|
||||
|
||||
if (visit && it->postVisit)
|
||||
it->visitBranch(EvPostVisit, this);
|
||||
}
|
||||
|
||||
//
|
||||
// Traverse a switch node.
|
||||
//
|
||||
void TIntermSwitch::traverse(TIntermTraverser* it)
|
||||
{
|
||||
bool visit = true;
|
||||
|
||||
if (it->preVisit)
|
||||
visit = it->visitSwitch(EvPreVisit, this);
|
||||
|
||||
if (visit) {
|
||||
it->incrementDepth(this);
|
||||
if (it->rightToLeft) {
|
||||
body->traverse(it);
|
||||
condition->traverse(it);
|
||||
} else {
|
||||
condition->traverse(it);
|
||||
body->traverse(it);
|
||||
}
|
||||
it->decrementDepth();
|
||||
}
|
||||
|
||||
if (visit && it->postVisit)
|
||||
it->visitSwitch(EvPostVisit, this);
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,389 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// This header defines a two-level parse-helper hierarchy, derived from
|
||||
// TParseVersions:
|
||||
// - TParseContextBase: sharable across multiple parsers
|
||||
// - TParseContext: GLSL specific helper
|
||||
//
|
||||
|
||||
#ifndef _PARSER_HELPER_INCLUDED_
|
||||
#define _PARSER_HELPER_INCLUDED_
|
||||
|
||||
#include "parseVersions.h"
|
||||
#include "../Include/ShHandle.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "localintermediate.h"
|
||||
#include "Scan.h"
|
||||
#include <functional>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
struct TPragma {
|
||||
TPragma(bool o, bool d) : optimize(o), debug(d) { }
|
||||
bool optimize;
|
||||
bool debug;
|
||||
TPragmaTable pragmaTable;
|
||||
};
|
||||
|
||||
class TScanContext;
|
||||
class TPpContext;
|
||||
|
||||
typedef std::set<int> TIdSetType;
|
||||
|
||||
//
|
||||
// Sharable code (as well as what's in TParseVersions) across
|
||||
// parse helpers.
|
||||
//
|
||||
class TParseContextBase : public TParseVersions {
|
||||
public:
|
||||
TParseContextBase(TSymbolTable& symbolTable, TIntermediate& interm, int version,
|
||||
EProfile profile, const SpvVersion& spvVersion, EShLanguage language,
|
||||
TInfoSink& infoSink, bool forwardCompatible, EShMessages messages)
|
||||
: TParseVersions(interm, version, profile, spvVersion, language, infoSink, forwardCompatible, messages),
|
||||
symbolTable(symbolTable), tokensBeforeEOF(false),
|
||||
linkage(nullptr), scanContext(nullptr), ppContext(nullptr) { }
|
||||
virtual ~TParseContextBase() { }
|
||||
|
||||
virtual void setLimits(const TBuiltInResource&) = 0;
|
||||
|
||||
EShLanguage getLanguage() const { return language; }
|
||||
TIntermAggregate*& getLinkage() { return linkage; }
|
||||
void setScanContext(TScanContext* c) { scanContext = c; }
|
||||
TScanContext* getScanContext() const { return scanContext; }
|
||||
void setPpContext(TPpContext* c) { ppContext = c; }
|
||||
TPpContext* getPpContext() const { return ppContext; }
|
||||
|
||||
virtual void setLineCallback(const std::function<void(int, int, bool, int, const char*)>& func) { lineCallback = func; }
|
||||
virtual void setExtensionCallback(const std::function<void(int, const char*, const char*)>& func) { extensionCallback = func; }
|
||||
virtual void setVersionCallback(const std::function<void(int, int, const char*)>& func) { versionCallback = func; }
|
||||
virtual void setPragmaCallback(const std::function<void(int, const TVector<TString>&)>& func) { pragmaCallback = func; }
|
||||
virtual void setErrorCallback(const std::function<void(int, const char*)>& func) { errorCallback = func; }
|
||||
|
||||
virtual void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op) = 0;
|
||||
virtual bool lineContinuationCheck(const TSourceLoc&, bool endOfComment) = 0;
|
||||
virtual bool lineDirectiveShouldSetNextLine() const = 0;
|
||||
virtual void handlePragma(const TSourceLoc&, const TVector<TString>&) = 0;
|
||||
|
||||
virtual bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false) = 0;
|
||||
|
||||
virtual void notifyVersion(int line, int version, const char* type_string)
|
||||
{
|
||||
if (versionCallback)
|
||||
versionCallback(line, version, type_string);
|
||||
}
|
||||
virtual void notifyErrorDirective(int line, const char* error_message)
|
||||
{
|
||||
if (errorCallback)
|
||||
errorCallback(line, error_message);
|
||||
}
|
||||
virtual void notifyLineDirective(int curLineNo, int newLineNo, bool hasSource, int sourceNum, const char* sourceName)
|
||||
{
|
||||
if (lineCallback)
|
||||
lineCallback(curLineNo, newLineNo, hasSource, sourceNum, sourceName);
|
||||
}
|
||||
virtual void notifyExtensionDirective(int line, const char* extension, const char* behavior)
|
||||
{
|
||||
if (extensionCallback)
|
||||
extensionCallback(line, extension, behavior);
|
||||
}
|
||||
|
||||
TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile
|
||||
bool tokensBeforeEOF;
|
||||
|
||||
protected:
|
||||
TParseContextBase(TParseContextBase&);
|
||||
TParseContextBase& operator=(TParseContextBase&);
|
||||
|
||||
TIntermAggregate* linkage; // aggregate node of objects the linker may need, if not referenced by the rest of the AST
|
||||
TScanContext* scanContext;
|
||||
TPpContext* ppContext;
|
||||
|
||||
// These, if set, will be called when a line, pragma ... is preprocessed.
|
||||
// They will be called with any parameters to the original directive.
|
||||
std::function<void(int, int, bool, int, const char*)> lineCallback;
|
||||
std::function<void(int, const TVector<TString>&)> pragmaCallback;
|
||||
std::function<void(int, int, const char*)> versionCallback;
|
||||
std::function<void(int, const char*, const char*)> extensionCallback;
|
||||
std::function<void(int, const char*)> errorCallback;
|
||||
};
|
||||
|
||||
//
|
||||
// GLSL-specific parse helper. Should have GLSL in the name, but that's
|
||||
// too big of a change for comparing branches at the moment, and perhaps
|
||||
// impacts downstream consumers as well.
|
||||
//
|
||||
class TParseContext : public TParseContextBase {
|
||||
public:
|
||||
TParseContext(TSymbolTable&, TIntermediate&, bool parsingBuiltins, int version, EProfile, const SpvVersion& spvVersion, EShLanguage, TInfoSink&,
|
||||
bool forwardCompatible = false, EShMessages messages = EShMsgDefault);
|
||||
virtual ~TParseContext();
|
||||
|
||||
void setLimits(const TBuiltInResource&);
|
||||
bool parseShaderStrings(TPpContext&, TInputScanner& input, bool versionWillBeError = false);
|
||||
void parserError(const char* s); // for bison's yyerror
|
||||
|
||||
void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...);
|
||||
void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...);
|
||||
void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...);
|
||||
void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...);
|
||||
|
||||
void reservedErrorCheck(const TSourceLoc&, const TString&);
|
||||
void reservedPpErrorCheck(const TSourceLoc&, const char* name, const char* op);
|
||||
bool lineContinuationCheck(const TSourceLoc&, bool endOfComment);
|
||||
bool lineDirectiveShouldSetNextLine() const;
|
||||
bool builtInName(const TString&);
|
||||
|
||||
void handlePragma(const TSourceLoc&, const TVector<TString>&);
|
||||
TIntermTyped* handleVariable(const TSourceLoc&, TSymbol* symbol, const TString* string);
|
||||
TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
|
||||
void checkIndex(const TSourceLoc&, const TType&, int& index);
|
||||
void handleIndexLimits(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index);
|
||||
|
||||
void makeEditable(TSymbol*&);
|
||||
TVariable* getEditableVariable(const char* name);
|
||||
bool isIoResizeArray(const TType&) const;
|
||||
void fixIoArraySize(const TSourceLoc&, TType&);
|
||||
void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base);
|
||||
void checkIoArraysConsistency(const TSourceLoc&, bool tailOnly = false);
|
||||
int getIoArrayImplicitSize() const;
|
||||
void checkIoArrayConsistency(const TSourceLoc&, int requiredSize, const char* feature, TType&, const TString&);
|
||||
|
||||
TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
|
||||
TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
|
||||
TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
|
||||
void blockMemberExtensionCheck(const TSourceLoc&, const TIntermTyped* base, const TString& field);
|
||||
TFunction* handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
|
||||
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
|
||||
TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||
TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*);
|
||||
void checkLocation(const TSourceLoc&, TOperator);
|
||||
TIntermTyped* handleLengthMethod(const TSourceLoc&, TFunction*, TIntermNode*);
|
||||
void addInputArgumentConversions(const TFunction&, TIntermNode*&) const;
|
||||
TIntermTyped* addOutputArgumentConversions(const TFunction&, TIntermAggregate&) const;
|
||||
void builtInOpCheck(const TSourceLoc&, const TFunction&, TIntermOperator&);
|
||||
void nonOpBuiltInCheck(const TSourceLoc&, const TFunction&, TIntermAggregate&);
|
||||
TFunction* handleConstructorCall(const TSourceLoc&, const TPublicType&);
|
||||
|
||||
bool parseVectorFields(const TSourceLoc&, const TString&, int vecSize, TVectorFields&);
|
||||
void assignError(const TSourceLoc&, const char* op, TString left, TString right);
|
||||
void unaryOpError(const TSourceLoc&, const char* op, TString operand);
|
||||
void binaryOpError(const TSourceLoc&, const char* op, TString left, TString right);
|
||||
void variableCheck(TIntermTyped*& nodePtr);
|
||||
bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
|
||||
void rValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*);
|
||||
void constantValueCheck(TIntermTyped* node, const char* token);
|
||||
void integerCheck(const TIntermTyped* node, const char* token);
|
||||
void globalCheck(const TSourceLoc&, const char* token);
|
||||
bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&);
|
||||
bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&);
|
||||
void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&);
|
||||
bool arrayQualifierError(const TSourceLoc&, const TQualifier&);
|
||||
bool arrayError(const TSourceLoc&, const TType&);
|
||||
void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&);
|
||||
void structArrayCheck(const TSourceLoc&, const TType& structure);
|
||||
void arrayUnsizedCheck(const TSourceLoc&, const TQualifier&, const TArraySizes*, bool initializer, bool lastMember);
|
||||
void arrayOfArrayVersionCheck(const TSourceLoc&);
|
||||
void arrayDimCheck(const TSourceLoc&, const TArraySizes* sizes1, const TArraySizes* sizes2);
|
||||
void arrayDimCheck(const TSourceLoc&, const TType*, const TArraySizes*);
|
||||
void arrayDimMerge(TType& type, const TArraySizes* sizes);
|
||||
bool voidErrorCheck(const TSourceLoc&, const TString&, TBasicType);
|
||||
void boolCheck(const TSourceLoc&, const TIntermTyped*);
|
||||
void boolCheck(const TSourceLoc&, const TPublicType&);
|
||||
void samplerCheck(const TSourceLoc&, const TType&, const TString& identifier, TIntermTyped* initializer);
|
||||
void atomicUintCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
void transparentCheck(const TSourceLoc&, const TType&, const TString& identifier);
|
||||
void globalQualifierFixCheck(const TSourceLoc&, TQualifier&);
|
||||
void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&);
|
||||
bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType);
|
||||
void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force);
|
||||
void setDefaultPrecision(const TSourceLoc&, TPublicType&, TPrecisionQualifier);
|
||||
int computeSamplerTypeIndex(TSampler&);
|
||||
TPrecisionQualifier getDefaultPrecision(TPublicType&);
|
||||
void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&);
|
||||
void parameterTypeCheck(const TSourceLoc&, TStorageQualifier qualifier, const TType& type);
|
||||
bool containsFieldWithBasicType(const TType& type ,TBasicType basicType);
|
||||
TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&, bool& newDeclaration);
|
||||
void redeclareBuiltinBlock(const TSourceLoc&, TTypeList& typeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes);
|
||||
void paramCheckFix(const TSourceLoc&, const TStorageQualifier&, TType& type);
|
||||
void paramCheckFix(const TSourceLoc&, const TQualifier&, TType& type);
|
||||
void nestedBlockCheck(const TSourceLoc&);
|
||||
void nestedStructCheck(const TSourceLoc&);
|
||||
void arrayObjectCheck(const TSourceLoc&, const TType&, const char* op);
|
||||
void opaqueCheck(const TSourceLoc&, const TType&, const char* op);
|
||||
void specializationCheck(const TSourceLoc&, const TType&, const char* op);
|
||||
void structTypeCheck(const TSourceLoc&, TPublicType&);
|
||||
void inductiveLoopCheck(const TSourceLoc&, TIntermNode* init, TIntermLoop* loop);
|
||||
void arrayLimitCheck(const TSourceLoc&, const TString&, int size);
|
||||
void limitCheck(const TSourceLoc&, int value, const char* limit, const char* feature);
|
||||
|
||||
void inductiveLoopBodyCheck(TIntermNode*, int loopIndexId, TSymbolTable&);
|
||||
void constantIndexExpressionCheck(TIntermNode*);
|
||||
|
||||
void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&);
|
||||
void setLayoutQualifier(const TSourceLoc&, TPublicType&, TString&, const TIntermTyped*);
|
||||
void mergeObjectLayoutQualifiers(TQualifier& dest, const TQualifier& src, bool inheritOnly);
|
||||
void layoutObjectCheck(const TSourceLoc&, const TSymbol&);
|
||||
void layoutTypeCheck(const TSourceLoc&, const TType&);
|
||||
void layoutQualifierCheck(const TSourceLoc&, const TQualifier&);
|
||||
void checkNoShaderLayouts(const TSourceLoc&, const TShaderQualifiers&);
|
||||
void fixOffset(const TSourceLoc&, TSymbol&);
|
||||
|
||||
const TFunction* findFunction(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunctionExact(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunction120(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
|
||||
const TFunction* findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn);
|
||||
void declareTypeDefaults(const TSourceLoc&, const TPublicType&);
|
||||
TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0);
|
||||
TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&, TOperator);
|
||||
TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&);
|
||||
TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset);
|
||||
void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0);
|
||||
void blockStageIoCheck(const TSourceLoc&, const TQualifier&);
|
||||
void blockQualifierCheck(const TSourceLoc&, const TQualifier&, bool instanceName);
|
||||
void fixBlockLocations(const TSourceLoc&, TQualifier&, TTypeList&, bool memberWithLocation, bool memberWithoutLocation);
|
||||
void fixBlockXfbOffsets(TQualifier&, TTypeList&);
|
||||
void fixBlockUniformOffsets(TQualifier&, TTypeList&);
|
||||
void addQualifierToExisting(const TSourceLoc&, TQualifier, const TString& identifier);
|
||||
void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
|
||||
void invariantCheck(const TSourceLoc&, const TQualifier&);
|
||||
void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
|
||||
void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
|
||||
TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
|
||||
|
||||
void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
|
||||
|
||||
protected:
|
||||
void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);
|
||||
void inheritGlobalDefaults(TQualifier& dst) const;
|
||||
TVariable* makeInternalVariable(const char* name, const TType&) const;
|
||||
TVariable* declareNonArray(const TSourceLoc&, TString& identifier, TType&, bool& newDeclaration);
|
||||
void declareArray(const TSourceLoc&, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
|
||||
TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable);
|
||||
TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer);
|
||||
TOperator mapTypeToConstructorOp(const TType&) const;
|
||||
void finalErrorCheck();
|
||||
void outputMessage(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, TPrefixType prefix,
|
||||
va_list args);
|
||||
|
||||
public:
|
||||
//
|
||||
// Generally, bison productions, the scanner, and the PP need read/write access to these; just give them direct access
|
||||
//
|
||||
|
||||
// Current state of parsing
|
||||
struct TPragma contextPragma;
|
||||
int loopNestingLevel; // 0 if outside all loops
|
||||
int structNestingLevel; // 0 if outside blocks and structures
|
||||
int controlFlowNestingLevel; // 0 if outside all flow control
|
||||
int statementNestingLevel; // 0 if outside all flow control or compound statements
|
||||
TList<TIntermSequence*> switchSequenceStack; // case, node, case, case, node, ...; ensure only one node between cases; stack of them for nesting
|
||||
TList<int> switchLevel; // the statementNestingLevel the current switch statement is at, which must match the level of its case statements
|
||||
bool inMain; // if inside a function, true if the function is main
|
||||
bool postMainReturn; // if inside a function, true if the function is main and this is after a return statement
|
||||
const TType* currentFunctionType; // the return type of the function that's currently being parsed
|
||||
bool functionReturnsValue; // true if a non-void function has a return
|
||||
const TString* blockName;
|
||||
TQualifier currentBlockQualifier;
|
||||
TPrecisionQualifier defaultPrecision[EbtNumTypes];
|
||||
TBuiltInResource resources;
|
||||
TLimits& limits;
|
||||
|
||||
protected:
|
||||
TParseContext(TParseContext&);
|
||||
TParseContext& operator=(TParseContext&);
|
||||
|
||||
const bool parsingBuiltins; // true if parsing built-in symbols/functions
|
||||
static const int maxSamplerIndex = EsdNumDims * (EbtNumTypes * (2 * 2 * 2 * 2 * 2)); // see computeSamplerTypeIndex()
|
||||
TPrecisionQualifier defaultSamplerPrecision[maxSamplerIndex];
|
||||
bool afterEOF;
|
||||
TQualifier globalBufferDefaults;
|
||||
TQualifier globalUniformDefaults;
|
||||
TQualifier globalInputDefaults;
|
||||
TQualifier globalOutputDefaults;
|
||||
int* atomicUintOffsets; // to become an array of the right size to hold an offset per binding point
|
||||
TString currentCaller; // name of last function body entered (not valid when at global scope)
|
||||
TIdSetType inductiveLoopIds;
|
||||
bool anyIndexLimits;
|
||||
TVector<TIntermTyped*> needsIndexLimitationChecking;
|
||||
|
||||
//
|
||||
// Geometry shader input arrays:
|
||||
// - array sizing is based on input primitive and/or explicit size
|
||||
//
|
||||
// Tessellation control output arrays:
|
||||
// - array sizing is based on output layout(vertices=...) and/or explicit size
|
||||
//
|
||||
// Both:
|
||||
// - array sizing is retroactive
|
||||
// - built-in block redeclarations interact with this
|
||||
//
|
||||
// Design:
|
||||
// - use a per-context "resize-list", a list of symbols whose array sizes
|
||||
// can be fixed
|
||||
//
|
||||
// - the resize-list starts empty at beginning of user-shader compilation, it does
|
||||
// not have built-ins in it
|
||||
//
|
||||
// - on built-in array use: copyUp() symbol and add it to the resize-list
|
||||
//
|
||||
// - on user array declaration: add it to the resize-list
|
||||
//
|
||||
// - on block redeclaration: copyUp() symbol and add it to the resize-list
|
||||
// * note, that appropriately gives an error if redeclaring a block that
|
||||
// was already used and hence already copied-up
|
||||
//
|
||||
// - on seeing a layout declaration that sizes the array, fix everything in the
|
||||
// resize-list, giving errors for mismatch
|
||||
//
|
||||
// - on seeing an array size declaration, give errors on mismatch between it and previous
|
||||
// array-sizing declarations
|
||||
//
|
||||
TVector<TSymbol*> ioArraySymbolResizeList;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _PARSER_HELPER_INCLUDED_
|
|
@ -0,0 +1,347 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/PoolAlloc.h"
|
||||
|
||||
#include "../Include/InitializeGlobals.h"
|
||||
#include "../OSDependent/osinclude.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
OS_TLSIndex PoolIndex;
|
||||
|
||||
void InitializeMemoryPools()
|
||||
{
|
||||
TThreadMemoryPools* pools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
|
||||
if (pools)
|
||||
return;
|
||||
|
||||
TPoolAllocator *threadPoolAllocator = new TPoolAllocator();
|
||||
|
||||
TThreadMemoryPools* threadData = new TThreadMemoryPools();
|
||||
|
||||
threadData->threadPoolAllocator = threadPoolAllocator;
|
||||
|
||||
OS_SetTLSValue(PoolIndex, threadData);
|
||||
}
|
||||
|
||||
void FreeGlobalPools()
|
||||
{
|
||||
// Release the allocated memory for this thread.
|
||||
TThreadMemoryPools* globalPools = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
|
||||
if (! globalPools)
|
||||
return;
|
||||
|
||||
GetThreadPoolAllocator().popAll();
|
||||
delete &GetThreadPoolAllocator();
|
||||
delete globalPools;
|
||||
}
|
||||
|
||||
bool InitializePoolIndex()
|
||||
{
|
||||
// Allocate a TLS index.
|
||||
if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreePoolIndex()
|
||||
{
|
||||
// Release the TLS index.
|
||||
OS_FreeTLSIndex(PoolIndex);
|
||||
}
|
||||
|
||||
TPoolAllocator& GetThreadPoolAllocator()
|
||||
{
|
||||
TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
|
||||
|
||||
return *threadData->threadPoolAllocator;
|
||||
}
|
||||
|
||||
void SetThreadPoolAllocator(TPoolAllocator& poolAllocator)
|
||||
{
|
||||
TThreadMemoryPools* threadData = static_cast<TThreadMemoryPools*>(OS_GetTLSValue(PoolIndex));
|
||||
|
||||
threadData->threadPoolAllocator = &poolAllocator;
|
||||
}
|
||||
|
||||
//
|
||||
// Implement the functionality of the TPoolAllocator class, which
|
||||
// is documented in PoolAlloc.h.
|
||||
//
|
||||
TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
|
||||
pageSize(growthIncrement),
|
||||
alignment(allocationAlignment),
|
||||
freeList(0),
|
||||
inUseList(0),
|
||||
numCalls(0)
|
||||
{
|
||||
//
|
||||
// Don't allow page sizes we know are smaller than all common
|
||||
// OS page sizes.
|
||||
//
|
||||
if (pageSize < 4*1024)
|
||||
pageSize = 4*1024;
|
||||
|
||||
//
|
||||
// A large currentPageOffset indicates a new page needs to
|
||||
// be obtained to allocate memory.
|
||||
//
|
||||
currentPageOffset = pageSize;
|
||||
|
||||
//
|
||||
// Adjust alignment to be at least pointer aligned and
|
||||
// power of 2.
|
||||
//
|
||||
size_t minAlign = sizeof(void*);
|
||||
alignment &= ~(minAlign - 1);
|
||||
if (alignment < minAlign)
|
||||
alignment = minAlign;
|
||||
size_t a = 1;
|
||||
while (a < alignment)
|
||||
a <<= 1;
|
||||
alignment = a;
|
||||
alignmentMask = a - 1;
|
||||
|
||||
//
|
||||
// Align header skip
|
||||
//
|
||||
headerSkip = minAlign;
|
||||
if (headerSkip < sizeof(tHeader)) {
|
||||
headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
|
||||
}
|
||||
|
||||
push();
|
||||
}
|
||||
|
||||
TPoolAllocator::~TPoolAllocator()
|
||||
{
|
||||
while (inUseList) {
|
||||
tHeader* next = inUseList->nextPage;
|
||||
inUseList->~tHeader();
|
||||
delete [] reinterpret_cast<char*>(inUseList);
|
||||
inUseList = next;
|
||||
}
|
||||
|
||||
//
|
||||
// Always delete the free list memory - it can't be being
|
||||
// (correctly) referenced, whether the pool allocator was
|
||||
// global or not. We should not check the guard blocks
|
||||
// here, because we did it already when the block was
|
||||
// placed into the free list.
|
||||
//
|
||||
while (freeList) {
|
||||
tHeader* next = freeList->nextPage;
|
||||
delete [] reinterpret_cast<char*>(freeList);
|
||||
freeList = next;
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
|
||||
const unsigned char TAllocation::guardBlockEndVal = 0xfe;
|
||||
const unsigned char TAllocation::userDataFill = 0xcd;
|
||||
|
||||
# ifdef GUARD_BLOCKS
|
||||
const size_t TAllocation::guardBlockSize = 16;
|
||||
# else
|
||||
const size_t TAllocation::guardBlockSize = 0;
|
||||
# endif
|
||||
|
||||
//
|
||||
// Check a single guard block for damage
|
||||
//
|
||||
#ifdef GUARD_BLOCKS
|
||||
void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
|
||||
#else
|
||||
void TAllocation::checkGuardBlock(unsigned char*, unsigned char, const char*) const
|
||||
#endif
|
||||
{
|
||||
#ifdef GUARD_BLOCKS
|
||||
for (size_t x = 0; x < guardBlockSize; x++) {
|
||||
if (blockMem[x] != val) {
|
||||
const int maxSize = 80;
|
||||
char assertMsg[maxSize];
|
||||
|
||||
// We don't print the assert message. It's here just to be helpful.
|
||||
snprintf(assertMsg, maxSize, "PoolAlloc: Damage %s %zu byte allocation at 0x%p\n",
|
||||
locText, size, data());
|
||||
assert(0 && "PoolAlloc: Damage in guard block");
|
||||
}
|
||||
}
|
||||
#else
|
||||
assert(guardBlockSize == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void TPoolAllocator::push()
|
||||
{
|
||||
tAllocState state = { currentPageOffset, inUseList };
|
||||
|
||||
stack.push_back(state);
|
||||
|
||||
//
|
||||
// Indicate there is no current page to allocate from.
|
||||
//
|
||||
currentPageOffset = pageSize;
|
||||
}
|
||||
|
||||
//
|
||||
// Do a mass-deallocation of all the individual allocations
|
||||
// that have occurred since the last push(), or since the
|
||||
// last pop(), or since the object's creation.
|
||||
//
|
||||
// The deallocated pages are saved for future allocations.
|
||||
//
|
||||
void TPoolAllocator::pop()
|
||||
{
|
||||
if (stack.size() < 1)
|
||||
return;
|
||||
|
||||
tHeader* page = stack.back().page;
|
||||
currentPageOffset = stack.back().offset;
|
||||
|
||||
while (inUseList != page) {
|
||||
// invoke destructor to free allocation list
|
||||
inUseList->~tHeader();
|
||||
|
||||
tHeader* nextInUse = inUseList->nextPage;
|
||||
if (inUseList->pageCount > 1)
|
||||
delete [] reinterpret_cast<char*>(inUseList);
|
||||
else {
|
||||
inUseList->nextPage = freeList;
|
||||
freeList = inUseList;
|
||||
}
|
||||
inUseList = nextInUse;
|
||||
}
|
||||
|
||||
stack.pop_back();
|
||||
}
|
||||
|
||||
//
|
||||
// Do a mass-deallocation of all the individual allocations
|
||||
// that have occurred.
|
||||
//
|
||||
void TPoolAllocator::popAll()
|
||||
{
|
||||
while (stack.size() > 0)
|
||||
pop();
|
||||
}
|
||||
|
||||
void* TPoolAllocator::allocate(size_t numBytes)
|
||||
{
|
||||
// If we are using guard blocks, all allocations are bracketed by
|
||||
// them: [guardblock][allocation][guardblock]. numBytes is how
|
||||
// much memory the caller asked for. allocationSize is the total
|
||||
// size including guard blocks. In release build,
|
||||
// guardBlockSize=0 and this all gets optimized away.
|
||||
size_t allocationSize = TAllocation::allocationSize(numBytes);
|
||||
|
||||
//
|
||||
// Just keep some interesting statistics.
|
||||
//
|
||||
++numCalls;
|
||||
totalBytes += numBytes;
|
||||
|
||||
//
|
||||
// Do the allocation, most likely case first, for efficiency.
|
||||
// This step could be moved to be inline sometime.
|
||||
//
|
||||
if (currentPageOffset + allocationSize <= pageSize) {
|
||||
//
|
||||
// Safe to allocate from currentPageOffset.
|
||||
//
|
||||
unsigned char* memory = reinterpret_cast<unsigned char*>(inUseList) + currentPageOffset;
|
||||
currentPageOffset += allocationSize;
|
||||
currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
|
||||
|
||||
return initializeAllocation(inUseList, memory, numBytes);
|
||||
}
|
||||
|
||||
if (allocationSize + headerSkip > pageSize) {
|
||||
//
|
||||
// Do a multi-page allocation. Don't mix these with the others.
|
||||
// The OS is efficient and allocating and free-ing multiple pages.
|
||||
//
|
||||
size_t numBytesToAlloc = allocationSize + headerSkip;
|
||||
tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
|
||||
if (memory == 0)
|
||||
return 0;
|
||||
|
||||
// Use placement-new to initialize header
|
||||
new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
|
||||
inUseList = memory;
|
||||
|
||||
currentPageOffset = pageSize; // make next allocation come from a new page
|
||||
|
||||
// No guard blocks for multi-page allocations (yet)
|
||||
return reinterpret_cast<void*>(reinterpret_cast<UINT_PTR>(memory) + headerSkip);
|
||||
}
|
||||
|
||||
//
|
||||
// Need a simple page to allocate from.
|
||||
//
|
||||
tHeader* memory;
|
||||
if (freeList) {
|
||||
memory = freeList;
|
||||
freeList = freeList->nextPage;
|
||||
} else {
|
||||
memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
|
||||
if (memory == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Use placement-new to initialize header
|
||||
new(memory) tHeader(inUseList, 1);
|
||||
inUseList = memory;
|
||||
|
||||
unsigned char* ret = reinterpret_cast<unsigned char*>(inUseList) + headerSkip;
|
||||
currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
|
||||
|
||||
return initializeAllocation(inUseList, ret, numBytes);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Check all allocations in a list for damage by calling check on each.
|
||||
//
|
||||
void TAllocation::checkAllocList() const
|
||||
{
|
||||
for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
|
||||
alloc->check();
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "../Include/intermediate.h"
|
||||
#include "RemoveTree.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Code to recursively delete the intermediate tree.
|
||||
//
|
||||
struct TRemoveTraverser : TIntermTraverser {
|
||||
TRemoveTraverser() : TIntermTraverser(false, false, true, false) {}
|
||||
|
||||
virtual void visitSymbol(TIntermSymbol* node)
|
||||
{
|
||||
delete node;
|
||||
}
|
||||
|
||||
virtual bool visitBinary(TVisit /* visit*/ , TIntermBinary* node)
|
||||
{
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool visitUnary(TVisit /* visit */, TIntermUnary* node)
|
||||
{
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool visitAggregate(TVisit /* visit*/ , TIntermAggregate* node)
|
||||
{
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool visitSelection(TVisit /* visit*/ , TIntermSelection* node)
|
||||
{
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool visitSwitch(TVisit /* visit*/ , TIntermSwitch* node)
|
||||
{
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void visitConstantUnion(TIntermConstantUnion* node)
|
||||
{
|
||||
delete node;
|
||||
}
|
||||
|
||||
virtual bool visitLoop(TVisit /* visit*/ , TIntermLoop* node)
|
||||
{
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool visitBranch(TVisit /* visit*/ , TIntermBranch* node)
|
||||
{
|
||||
delete node;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Entry point.
|
||||
//
|
||||
void RemoveAllTreeNodes(TIntermNode* root)
|
||||
{
|
||||
TRemoveTraverser it;
|
||||
|
||||
root->traverse(&it);
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
namespace glslang {
|
||||
|
||||
void RemoveAllTreeNodes(TIntermNode*);
|
||||
|
||||
} // end namespace glslang
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,273 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifndef _GLSLANG_SCAN_INCLUDED_
|
||||
#define _GLSLANG_SCAN_INCLUDED_
|
||||
|
||||
#include "Versions.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// Use a global end-of-input character, so no translation is needed across
|
||||
// layers of encapsulation. Characters are all 8 bit, and positive, so there is
|
||||
// no aliasing of character 255 onto -1, for example.
|
||||
const int EndOfInput = -1;
|
||||
|
||||
//
|
||||
// A character scanner that seamlessly, on read-only strings, reads across an
|
||||
// array of strings without assuming null termination.
|
||||
//
|
||||
class TInputScanner {
|
||||
public:
|
||||
TInputScanner(int n, const char* const s[], size_t L[], const char* const* names = nullptr, int b = 0, int f = 0, bool single = false) :
|
||||
numSources(n),
|
||||
sources(reinterpret_cast<const unsigned char* const *>(s)), // up to this point, common usage is "char*", but now we need positive 8-bit characters
|
||||
lengths(L), currentSource(0), currentChar(0), stringBias(b), finale(f), singleLogical(single), endOfFileReached(false)
|
||||
{
|
||||
loc = new TSourceLoc[numSources];
|
||||
for (int i = 0; i < numSources; ++i) {
|
||||
loc[i].init();
|
||||
}
|
||||
if (names != nullptr) {
|
||||
for (int i = 0; i < numSources; ++i)
|
||||
loc[i].name = names[i];
|
||||
}
|
||||
loc[currentSource].string = -stringBias;
|
||||
loc[currentSource].line = 1;
|
||||
loc[currentSource].column = 0;
|
||||
logicalSourceLoc.string = 0;
|
||||
logicalSourceLoc.line = 1;
|
||||
logicalSourceLoc.column = 0;
|
||||
logicalSourceLoc.name = loc[0].name;
|
||||
}
|
||||
|
||||
virtual ~TInputScanner()
|
||||
{
|
||||
delete [] loc;
|
||||
}
|
||||
|
||||
// retrieve the next character and advance one character
|
||||
int get()
|
||||
{
|
||||
int ret = peek();
|
||||
if (ret == EndOfInput)
|
||||
return ret;
|
||||
++loc[currentSource].column;
|
||||
++logicalSourceLoc.column;
|
||||
if (ret == '\n') {
|
||||
++loc[currentSource].line;
|
||||
++logicalSourceLoc.line;
|
||||
logicalSourceLoc.column = 0;
|
||||
loc[currentSource].column = 0;
|
||||
}
|
||||
advance();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// retrieve the next character, no advance
|
||||
int peek()
|
||||
{
|
||||
if (currentSource >= numSources) {
|
||||
endOfFileReached = true;
|
||||
return EndOfInput;
|
||||
}
|
||||
// Make sure we do not read off the end of a string.
|
||||
// N.B. Sources can have a length of 0.
|
||||
int sourceToRead = currentSource;
|
||||
size_t charToRead = currentChar;
|
||||
while(charToRead >= lengths[sourceToRead]) {
|
||||
charToRead = 0;
|
||||
sourceToRead += 1;
|
||||
if (sourceToRead >= numSources) {
|
||||
return EndOfInput;
|
||||
}
|
||||
}
|
||||
|
||||
// Here, we care about making negative valued characters positive
|
||||
return sources[sourceToRead][charToRead];
|
||||
}
|
||||
|
||||
// go back one character
|
||||
void unget()
|
||||
{
|
||||
// Do not roll back once we've reached the end of the file.
|
||||
if (endOfFileReached)
|
||||
return;
|
||||
|
||||
if (currentChar > 0) {
|
||||
--currentChar;
|
||||
--loc[currentSource].column;
|
||||
--logicalSourceLoc.column;
|
||||
if (loc[currentSource].column < 0) {
|
||||
// We've moved back past a new line. Find the
|
||||
// previous newline (or start of the file) to compute
|
||||
// the column count on the now current line.
|
||||
size_t chIndex = currentChar;
|
||||
while (chIndex > 0) {
|
||||
if (sources[currentSource][chIndex] == '\n') {
|
||||
break;
|
||||
}
|
||||
--chIndex;
|
||||
}
|
||||
logicalSourceLoc.column = (int)(currentChar - chIndex);
|
||||
loc[currentSource].column = (int)(currentChar - chIndex);
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
--currentSource;
|
||||
} while (currentSource > 0 && lengths[currentSource] == 0);
|
||||
if (lengths[currentSource] == 0) {
|
||||
// set to 0 if we've backed up to the start of an empty string
|
||||
currentChar = 0;
|
||||
} else
|
||||
currentChar = lengths[currentSource] - 1;
|
||||
}
|
||||
if (peek() == '\n') {
|
||||
--loc[currentSource].line;
|
||||
--logicalSourceLoc.line;
|
||||
}
|
||||
}
|
||||
|
||||
// for #line override
|
||||
void setLine(int newLine)
|
||||
{
|
||||
logicalSourceLoc.line = newLine;
|
||||
loc[getLastValidSourceIndex()].line = newLine;
|
||||
}
|
||||
|
||||
// for #line override in filename based parsing
|
||||
void setFile(const char* filename)
|
||||
{
|
||||
logicalSourceLoc.name = filename;
|
||||
loc[getLastValidSourceIndex()].name = filename;
|
||||
}
|
||||
|
||||
void setFile(const char* filename, int i)
|
||||
{
|
||||
if (i == getLastValidSourceIndex()) {
|
||||
logicalSourceLoc.name = filename;
|
||||
}
|
||||
loc[i].name = filename;
|
||||
}
|
||||
|
||||
void setString(int newString)
|
||||
{
|
||||
logicalSourceLoc.string = newString;
|
||||
loc[getLastValidSourceIndex()].string = newString;
|
||||
logicalSourceLoc.name = nullptr;
|
||||
loc[getLastValidSourceIndex()].name = nullptr;
|
||||
}
|
||||
|
||||
// for #include content indentation
|
||||
void setColumn(int col)
|
||||
{
|
||||
logicalSourceLoc.column = col;
|
||||
loc[getLastValidSourceIndex()].column = col;
|
||||
}
|
||||
|
||||
void setEndOfInput()
|
||||
{
|
||||
endOfFileReached = true;
|
||||
currentSource = numSources;
|
||||
}
|
||||
|
||||
const TSourceLoc& getSourceLoc() const
|
||||
{
|
||||
if (singleLogical) {
|
||||
return logicalSourceLoc;
|
||||
} else {
|
||||
return loc[std::max(0, std::min(currentSource, numSources - finale - 1))];
|
||||
}
|
||||
}
|
||||
// Returns the index (starting from 0) of the most recent valid source string we are reading from.
|
||||
int getLastValidSourceIndex() const { return std::min(currentSource, numSources - 1); }
|
||||
|
||||
void consumeWhiteSpace(bool& foundNonSpaceTab);
|
||||
bool consumeComment();
|
||||
void consumeWhitespaceComment(bool& foundNonSpaceTab);
|
||||
bool scanVersion(int& version, EProfile& profile, bool& notFirstToken);
|
||||
|
||||
protected:
|
||||
|
||||
// advance one character
|
||||
void advance()
|
||||
{
|
||||
++currentChar;
|
||||
if (currentChar >= lengths[currentSource]) {
|
||||
++currentSource;
|
||||
if (currentSource < numSources) {
|
||||
loc[currentSource].string = loc[currentSource - 1].string + 1;
|
||||
loc[currentSource].line = 1;
|
||||
loc[currentSource].column = 0;
|
||||
}
|
||||
while (currentSource < numSources && lengths[currentSource] == 0) {
|
||||
++currentSource;
|
||||
if (currentSource < numSources) {
|
||||
loc[currentSource].string = loc[currentSource - 1].string + 1;
|
||||
loc[currentSource].line = 1;
|
||||
loc[currentSource].column = 0;
|
||||
}
|
||||
}
|
||||
currentChar = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int numSources; // number of strings in source
|
||||
const unsigned char* const *sources; // array of strings; must be converted to positive values on use, to avoid aliasing with -1 as EndOfInput
|
||||
const size_t *lengths; // length of each string
|
||||
int currentSource;
|
||||
size_t currentChar;
|
||||
|
||||
// This is for reporting what string/line an error occurred on, and can be overridden by #line.
|
||||
// It remembers the last state of each source string as it is left for the next one, so unget()
|
||||
// can restore that state.
|
||||
TSourceLoc* loc; // an array
|
||||
|
||||
int stringBias; // the first string that is the user's string number 0
|
||||
int finale; // number of internal strings after user's last string
|
||||
|
||||
TSourceLoc logicalSourceLoc;
|
||||
bool singleLogical; // treats the strings as a single logical string.
|
||||
// locations will be reported from the first string.
|
||||
|
||||
// Set to true once peek() returns EndOfFile, so that we won't roll back
|
||||
// once we've reached EndOfFile.
|
||||
bool endOfFileReached;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _GLSLANG_SCAN_INCLUDED_
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// This holds context specific to the GLSL scanner, which
|
||||
// sits between the preprocessor scanner and parser.
|
||||
//
|
||||
|
||||
#include "ParseHelper.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TPpContext;
|
||||
class TPpToken;
|
||||
class TParserToken;
|
||||
|
||||
class TScanContext {
|
||||
public:
|
||||
explicit TScanContext(TParseContextBase& pc) : parseContext(pc), afterType(false), field(false) { }
|
||||
virtual ~TScanContext() { }
|
||||
|
||||
static void fillInKeywordMap();
|
||||
static void deleteKeywordMap();
|
||||
|
||||
int tokenize(TPpContext*, TParserToken&);
|
||||
|
||||
protected:
|
||||
TScanContext(TScanContext&);
|
||||
TScanContext& operator=(TScanContext&);
|
||||
|
||||
int tokenizeIdentifier();
|
||||
int identifierOrType();
|
||||
int reservedWord();
|
||||
int identifierOrReserved(bool reserved);
|
||||
int es30ReservedFromGLSL(int version);
|
||||
int nonreservedKeyword(int esVersion, int nonEsVersion);
|
||||
int precisionKeyword();
|
||||
int matNxM();
|
||||
int dMat();
|
||||
int firstGenerationImage(bool inEs310);
|
||||
int secondGenerationImage();
|
||||
|
||||
TParseContextBase& parseContext;
|
||||
bool afterType; // true if we've recognized a type, so can only be looking for an identifier
|
||||
bool field; // true if we're on a field, right after a '.'
|
||||
TSourceLoc loc;
|
||||
TParserToken* parserToken;
|
||||
TPpToken* ppToken;
|
||||
|
||||
const char* tokenText;
|
||||
int keyword;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,351 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// Symbol table for parsing. Most functionaliy and main ideas
|
||||
// are documented in the header file.
|
||||
//
|
||||
|
||||
#include "SymbolTable.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// TType helper function needs a place to live.
|
||||
//
|
||||
|
||||
//
|
||||
// Recursively generate mangled names.
|
||||
//
|
||||
void TType::buildMangledName(TString& mangledName)
|
||||
{
|
||||
if (isMatrix())
|
||||
mangledName += 'm';
|
||||
else if (isVector())
|
||||
mangledName += 'v';
|
||||
|
||||
switch (basicType) {
|
||||
case EbtFloat: mangledName += 'f'; break;
|
||||
case EbtDouble: mangledName += 'd'; break;
|
||||
case EbtInt: mangledName += 'i'; break;
|
||||
case EbtUint: mangledName += 'u'; break;
|
||||
case EbtInt64: mangledName += "i64"; break;
|
||||
case EbtUint64: mangledName += "u64"; break;
|
||||
case EbtBool: mangledName += 'b'; break;
|
||||
case EbtAtomicUint: mangledName += "au"; break;
|
||||
case EbtSampler:
|
||||
switch (sampler.type) {
|
||||
case EbtInt: mangledName += "i"; break;
|
||||
case EbtUint: mangledName += "u"; break;
|
||||
default: break; // some compilers want this
|
||||
}
|
||||
if (sampler.image)
|
||||
mangledName += "I"; // a normal image
|
||||
else if (sampler.sampler)
|
||||
mangledName += "p"; // a "pure" sampler
|
||||
else if (!sampler.combined)
|
||||
mangledName += "t"; // a "pure" texture
|
||||
else
|
||||
mangledName += "s"; // traditional combined sampler
|
||||
if (sampler.arrayed)
|
||||
mangledName += "A";
|
||||
if (sampler.shadow)
|
||||
mangledName += "S";
|
||||
if (sampler.external)
|
||||
mangledName += "E";
|
||||
switch (sampler.dim) {
|
||||
case Esd1D: mangledName += "1"; break;
|
||||
case Esd2D: mangledName += "2"; break;
|
||||
case Esd3D: mangledName += "3"; break;
|
||||
case EsdCube: mangledName += "C"; break;
|
||||
case EsdRect: mangledName += "R2"; break;
|
||||
case EsdBuffer: mangledName += "B"; break;
|
||||
case EsdSubpass: mangledName += "P"; break;
|
||||
default: break; // some compilers want this
|
||||
}
|
||||
if (sampler.ms)
|
||||
mangledName += "M";
|
||||
break;
|
||||
case EbtStruct:
|
||||
mangledName += "struct-";
|
||||
if (typeName)
|
||||
mangledName += *typeName;
|
||||
for (unsigned int i = 0; i < structure->size(); ++i) {
|
||||
mangledName += '-';
|
||||
(*structure)[i].type->buildMangledName(mangledName);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (getVectorSize() > 0)
|
||||
mangledName += static_cast<char>('0' + getVectorSize());
|
||||
else {
|
||||
mangledName += static_cast<char>('0' + getMatrixCols());
|
||||
mangledName += static_cast<char>('0' + getMatrixRows());
|
||||
}
|
||||
|
||||
if (arraySizes) {
|
||||
const int maxSize = 11;
|
||||
char buf[maxSize];
|
||||
for (int i = 0; i < arraySizes->getNumDims(); ++i) {
|
||||
if (arraySizes->getDimNode(i)) {
|
||||
if (arraySizes->getDimNode(i)->getAsSymbolNode())
|
||||
snprintf(buf, maxSize, "s%d", arraySizes->getDimNode(i)->getAsSymbolNode()->getId());
|
||||
else
|
||||
snprintf(buf, maxSize, "s%p", arraySizes->getDimNode(i));
|
||||
} else
|
||||
snprintf(buf, maxSize, "%d", arraySizes->getDimSize(i));
|
||||
mangledName += '[';
|
||||
mangledName += buf;
|
||||
mangledName += ']';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Dump functions.
|
||||
//
|
||||
|
||||
void TVariable::dump(TInfoSink& infoSink) const
|
||||
{
|
||||
infoSink.debug << getName().c_str() << ": " << type.getStorageQualifierString() << " " << type.getBasicTypeString();
|
||||
if (type.isArray()) {
|
||||
infoSink.debug << "[0]";
|
||||
}
|
||||
infoSink.debug << "\n";
|
||||
}
|
||||
|
||||
void TFunction::dump(TInfoSink& infoSink) const
|
||||
{
|
||||
infoSink.debug << getName().c_str() << ": " << returnType.getBasicTypeString() << " " << getMangledName().c_str() << "\n";
|
||||
}
|
||||
|
||||
void TAnonMember::dump(TInfoSink& TInfoSink) const
|
||||
{
|
||||
TInfoSink.debug << "anonymous member " << getMemberNumber() << " of " << getAnonContainer().getName().c_str() << "\n";
|
||||
}
|
||||
|
||||
void TSymbolTableLevel::dump(TInfoSink &infoSink) const
|
||||
{
|
||||
tLevel::const_iterator it;
|
||||
for (it = level.begin(); it != level.end(); ++it)
|
||||
(*it).second->dump(infoSink);
|
||||
}
|
||||
|
||||
void TSymbolTable::dump(TInfoSink &infoSink) const
|
||||
{
|
||||
for (int level = currentLevel(); level >= 0; --level) {
|
||||
infoSink.debug << "LEVEL " << level << "\n";
|
||||
table[level]->dump(infoSink);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Functions have buried pointers to delete.
|
||||
//
|
||||
TFunction::~TFunction()
|
||||
{
|
||||
for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
|
||||
delete (*i).type;
|
||||
}
|
||||
|
||||
//
|
||||
// Symbol table levels are a map of pointers to symbols that have to be deleted.
|
||||
//
|
||||
TSymbolTableLevel::~TSymbolTableLevel()
|
||||
{
|
||||
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
|
||||
delete (*it).second;
|
||||
|
||||
delete [] defaultPrecision;
|
||||
}
|
||||
|
||||
//
|
||||
// Change all function entries in the table with the non-mangled name
|
||||
// to be related to the provided built-in operation.
|
||||
//
|
||||
void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
|
||||
{
|
||||
tLevel::const_iterator candidate = level.lower_bound(name);
|
||||
while (candidate != level.end()) {
|
||||
const TString& candidateName = (*candidate).first;
|
||||
TString::size_type parenAt = candidateName.find_first_of('(');
|
||||
if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0) {
|
||||
TFunction* function = (*candidate).second->getAsFunction();
|
||||
function->relateToOperator(op);
|
||||
} else
|
||||
break;
|
||||
++candidate;
|
||||
}
|
||||
}
|
||||
|
||||
// Make all function overloads of the given name require an extension(s).
|
||||
// Should only be used for a version/profile that actually needs the extension(s).
|
||||
void TSymbolTableLevel::setFunctionExtensions(const char* name, int num, const char* const extensions[])
|
||||
{
|
||||
tLevel::const_iterator candidate = level.lower_bound(name);
|
||||
while (candidate != level.end()) {
|
||||
const TString& candidateName = (*candidate).first;
|
||||
TString::size_type parenAt = candidateName.find_first_of('(');
|
||||
if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0) {
|
||||
TSymbol* symbol = candidate->second;
|
||||
symbol->setExtensions(num, extensions);
|
||||
} else
|
||||
break;
|
||||
++candidate;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Make all symbols in this table level read only.
|
||||
//
|
||||
void TSymbolTableLevel::readOnly()
|
||||
{
|
||||
for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
|
||||
(*it).second->makeReadOnly();
|
||||
}
|
||||
|
||||
//
|
||||
// Copy a symbol, but the copy is writable; call readOnly() afterward if that's not desired.
|
||||
//
|
||||
TSymbol::TSymbol(const TSymbol& copyOf)
|
||||
{
|
||||
name = NewPoolTString(copyOf.name->c_str());
|
||||
uniqueId = copyOf.uniqueId;
|
||||
writable = true;
|
||||
}
|
||||
|
||||
TVariable::TVariable(const TVariable& copyOf) : TSymbol(copyOf)
|
||||
{
|
||||
type.deepCopy(copyOf.type);
|
||||
userType = copyOf.userType;
|
||||
numExtensions = 0;
|
||||
extensions = 0;
|
||||
if (copyOf.numExtensions != 0)
|
||||
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
||||
|
||||
if (! copyOf.constArray.empty()) {
|
||||
assert(! copyOf.type.isStruct());
|
||||
TConstUnionArray newArray(copyOf.constArray, 0, copyOf.constArray.size());
|
||||
constArray = newArray;
|
||||
}
|
||||
|
||||
// don't support specialization-constant subtrees in cloned tables
|
||||
constSubtree = nullptr;
|
||||
}
|
||||
|
||||
TVariable* TVariable::clone() const
|
||||
{
|
||||
TVariable *variable = new TVariable(*this);
|
||||
|
||||
return variable;
|
||||
}
|
||||
|
||||
TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf)
|
||||
{
|
||||
for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) {
|
||||
TParameter param;
|
||||
parameters.push_back(param);
|
||||
parameters.back().copyParam(copyOf.parameters[i]);
|
||||
}
|
||||
|
||||
numExtensions = 0;
|
||||
extensions = 0;
|
||||
if (copyOf.extensions != 0)
|
||||
setExtensions(copyOf.numExtensions, copyOf.extensions);
|
||||
returnType.deepCopy(copyOf.returnType);
|
||||
mangledName = copyOf.mangledName;
|
||||
op = copyOf.op;
|
||||
defined = copyOf.defined;
|
||||
prototyped = copyOf.prototyped;
|
||||
}
|
||||
|
||||
TFunction* TFunction::clone() const
|
||||
{
|
||||
TFunction *function = new TFunction(*this);
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
TAnonMember* TAnonMember::clone() const
|
||||
{
|
||||
// Anonymous members of a given block should be cloned at a higher level,
|
||||
// where they can all be assured to still end up pointing to a single
|
||||
// copy of the original container.
|
||||
assert(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TSymbolTableLevel* TSymbolTableLevel::clone() const
|
||||
{
|
||||
TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
|
||||
symTableLevel->anonId = anonId;
|
||||
std::vector<bool> containerCopied(anonId, false);
|
||||
tLevel::const_iterator iter;
|
||||
for (iter = level.begin(); iter != level.end(); ++iter) {
|
||||
const TAnonMember* anon = iter->second->getAsAnonMember();
|
||||
if (anon) {
|
||||
// Insert all the anonymous members of this same container at once,
|
||||
// avoid inserting the other members in the future, once this has been done,
|
||||
// allowing them to all be part of the same new container.
|
||||
if (! containerCopied[anon->getAnonId()]) {
|
||||
TVariable* container = anon->getAnonContainer().clone();
|
||||
container->changeName(NewPoolTString(""));
|
||||
// insert the whole container
|
||||
symTableLevel->insert(*container, false);
|
||||
containerCopied[anon->getAnonId()] = true;
|
||||
}
|
||||
} else
|
||||
symTableLevel->insert(*iter->second->clone(), false);
|
||||
}
|
||||
|
||||
return symTableLevel;
|
||||
}
|
||||
|
||||
void TSymbolTable::copyTable(const TSymbolTable& copyOf)
|
||||
{
|
||||
assert(adoptedLevels == copyOf.adoptedLevels);
|
||||
|
||||
uniqueId = copyOf.uniqueId;
|
||||
noBuiltInRedeclarations = copyOf.noBuiltInRedeclarations;
|
||||
separateNameSpaces = copyOf.separateNameSpaces;
|
||||
for (unsigned int i = copyOf.adoptedLevels; i < copyOf.table.size(); ++i)
|
||||
table.push_back(copyOf.table[i]->clone());
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,694 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _SYMBOL_TABLE_INCLUDED_
|
||||
#define _SYMBOL_TABLE_INCLUDED_
|
||||
|
||||
//
|
||||
// Symbol table for parsing. Has these design characteristics:
|
||||
//
|
||||
// * Same symbol table can be used to compile many shaders, to preserve
|
||||
// effort of creating and loading with the large numbers of built-in
|
||||
// symbols.
|
||||
//
|
||||
// --> This requires a copy mechanism, so initial pools used to create
|
||||
// the shared information can be popped. Done through "clone"
|
||||
// methods.
|
||||
//
|
||||
// * Name mangling will be used to give each function a unique name
|
||||
// so that symbol table lookups are never ambiguous. This allows
|
||||
// a simpler symbol table structure.
|
||||
//
|
||||
// * Pushing and popping of scope, so symbol table will really be a stack
|
||||
// of symbol tables. Searched from the top, with new inserts going into
|
||||
// the top.
|
||||
//
|
||||
// * Constants: Compile time constant symbols will keep their values
|
||||
// in the symbol table. The parser can substitute constants at parse
|
||||
// time, including doing constant folding and constant propagation.
|
||||
//
|
||||
// * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
|
||||
// are tracked in the intermediate representation, not the symbol table.
|
||||
//
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "../Include/intermediate.h"
|
||||
#include "../Include/InfoSink.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Symbol base class. (Can build functions or variables out of these...)
|
||||
//
|
||||
|
||||
class TVariable;
|
||||
class TFunction;
|
||||
class TAnonMember;
|
||||
|
||||
class TSymbol {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
explicit TSymbol(const TString *n) : name(n), numExtensions(0), extensions(0), writable(true) { }
|
||||
virtual TSymbol* clone() const = 0;
|
||||
virtual ~TSymbol() { } // rely on all symbol owned memory coming from the pool
|
||||
|
||||
virtual const TString& getName() const { return *name; }
|
||||
virtual void changeName(const TString* newName) { name = newName; }
|
||||
virtual const TString& getMangledName() const { return getName(); }
|
||||
virtual TFunction* getAsFunction() { return 0; }
|
||||
virtual const TFunction* getAsFunction() const { return 0; }
|
||||
virtual TVariable* getAsVariable() { return 0; }
|
||||
virtual const TVariable* getAsVariable() const { return 0; }
|
||||
virtual const TAnonMember* getAsAnonMember() const { return 0; }
|
||||
virtual const TType& getType() const = 0;
|
||||
virtual TType& getWritableType() = 0;
|
||||
virtual void setUniqueId(int id) { uniqueId = id; }
|
||||
virtual int getUniqueId() const { return uniqueId; }
|
||||
virtual void setExtensions(int num, const char* const exts[])
|
||||
{
|
||||
assert(extensions == 0);
|
||||
assert(num > 0);
|
||||
numExtensions = num;
|
||||
extensions = NewPoolObject(exts[0], num);
|
||||
for (int e = 0; e < num; ++e)
|
||||
extensions[e] = exts[e];
|
||||
}
|
||||
virtual int getNumExtensions() const { return numExtensions; }
|
||||
virtual const char** getExtensions() const { return extensions; }
|
||||
virtual void dump(TInfoSink &infoSink) const = 0;
|
||||
|
||||
virtual bool isReadOnly() const { return ! writable; }
|
||||
virtual void makeReadOnly() { writable = false; }
|
||||
|
||||
protected:
|
||||
explicit TSymbol(const TSymbol&);
|
||||
TSymbol& operator=(const TSymbol&);
|
||||
|
||||
const TString *name;
|
||||
unsigned int uniqueId; // For cross-scope comparing during code generation
|
||||
|
||||
// For tracking what extensions must be present
|
||||
// (don't use if correct version/profile is present).
|
||||
int numExtensions;
|
||||
const char** extensions; // an array of pointers to existing constant char strings
|
||||
|
||||
//
|
||||
// N.B.: Non-const functions that will be generally used should assert on this,
|
||||
// to avoid overwriting shared symbol-table information.
|
||||
//
|
||||
bool writable;
|
||||
};
|
||||
|
||||
//
|
||||
// Variable class, meaning a symbol that's not a function.
|
||||
//
|
||||
// There could be a separate class hierarchy for Constant variables;
|
||||
// Only one of int, bool, or float, (or none) is correct for
|
||||
// any particular use, but it's easy to do this way, and doesn't
|
||||
// seem worth having separate classes, and "getConst" can't simply return
|
||||
// different values for different types polymorphically, so this is
|
||||
// just simple and pragmatic.
|
||||
//
|
||||
class TVariable : public TSymbol {
|
||||
public:
|
||||
TVariable(const TString *name, const TType& t, bool uT = false )
|
||||
: TSymbol(name),
|
||||
userType(uT),
|
||||
constSubtree(nullptr) { type.shallowCopy(t); }
|
||||
virtual TVariable* clone() const;
|
||||
virtual ~TVariable() { }
|
||||
|
||||
virtual TVariable* getAsVariable() { return this; }
|
||||
virtual const TVariable* getAsVariable() const { return this; }
|
||||
virtual const TType& getType() const { return type; }
|
||||
virtual TType& getWritableType() { assert(writable); return type; }
|
||||
virtual bool isUserType() const { return userType; }
|
||||
virtual const TConstUnionArray& getConstArray() const { return constArray; }
|
||||
virtual TConstUnionArray& getWritableConstArray() { assert(writable); return constArray; }
|
||||
virtual void setConstArray(const TConstUnionArray& array) { constArray = array; }
|
||||
virtual void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; }
|
||||
virtual TIntermTyped* getConstSubtree() const { return constSubtree; }
|
||||
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
protected:
|
||||
explicit TVariable(const TVariable&);
|
||||
TVariable& operator=(const TVariable&);
|
||||
|
||||
TType type;
|
||||
bool userType;
|
||||
// we are assuming that Pool Allocator will free the memory allocated to unionArray
|
||||
// when this object is destroyed
|
||||
|
||||
// TODO: these two should be a union
|
||||
// A variable could be a compile-time constant, or a specialization
|
||||
// constant, or neither, but never both.
|
||||
TConstUnionArray constArray; // for compile-time constant value
|
||||
TIntermTyped* constSubtree; // for specialization constant computation
|
||||
};
|
||||
|
||||
//
|
||||
// The function sub-class of symbols and the parser will need to
|
||||
// share this definition of a function parameter.
|
||||
//
|
||||
struct TParameter {
|
||||
TString *name;
|
||||
TType* type;
|
||||
void copyParam(const TParameter& param)
|
||||
{
|
||||
if (param.name)
|
||||
name = NewPoolTString(param.name->c_str());
|
||||
else
|
||||
name = 0;
|
||||
type = param.type->clone();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// The function sub-class of a symbol.
|
||||
//
|
||||
class TFunction : public TSymbol {
|
||||
public:
|
||||
explicit TFunction(TOperator o) :
|
||||
TSymbol(0),
|
||||
op(o),
|
||||
defined(false), prototyped(false) { }
|
||||
TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) :
|
||||
TSymbol(name),
|
||||
mangledName(*name + '('),
|
||||
op(tOp),
|
||||
defined(false), prototyped(false) { returnType.shallowCopy(retType); }
|
||||
virtual TFunction* clone() const;
|
||||
virtual ~TFunction();
|
||||
|
||||
virtual TFunction* getAsFunction() { return this; }
|
||||
virtual const TFunction* getAsFunction() const { return this; }
|
||||
|
||||
virtual void addParameter(TParameter& p)
|
||||
{
|
||||
assert(writable);
|
||||
parameters.push_back(p);
|
||||
p.type->appendMangledName(mangledName);
|
||||
}
|
||||
|
||||
virtual const TString& getMangledName() const { return mangledName; }
|
||||
virtual const TType& getType() const { return returnType; }
|
||||
virtual TType& getWritableType() { return returnType; }
|
||||
virtual void relateToOperator(TOperator o) { assert(writable); op = o; }
|
||||
virtual TOperator getBuiltInOp() const { return op; }
|
||||
virtual void setDefined() { assert(writable); defined = true; }
|
||||
virtual bool isDefined() const { return defined; }
|
||||
virtual void setPrototyped() { assert(writable); prototyped = true; }
|
||||
virtual bool isPrototyped() const { return prototyped; }
|
||||
|
||||
virtual int getParamCount() const { return static_cast<int>(parameters.size()); }
|
||||
virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; }
|
||||
virtual const TParameter& operator[](int i) const { return parameters[i]; }
|
||||
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
protected:
|
||||
explicit TFunction(const TFunction&);
|
||||
TFunction& operator=(const TFunction&);
|
||||
|
||||
typedef TVector<TParameter> TParamList;
|
||||
TParamList parameters;
|
||||
TType returnType;
|
||||
TString mangledName;
|
||||
TOperator op;
|
||||
bool defined;
|
||||
bool prototyped;
|
||||
};
|
||||
|
||||
//
|
||||
// Members of anonymous blocks are a kind of TSymbol. They are not hidden in
|
||||
// the symbol table behind a container; rather they are visible and point to
|
||||
// their anonymous container. (The anonymous container is found through the
|
||||
// member, not the other way around.)
|
||||
//
|
||||
class TAnonMember : public TSymbol {
|
||||
public:
|
||||
TAnonMember(const TString* n, unsigned int m, const TVariable& a, int an) : TSymbol(n), anonContainer(a), memberNumber(m), anonId(an) { }
|
||||
virtual TAnonMember* clone() const;
|
||||
virtual ~TAnonMember() { }
|
||||
|
||||
virtual const TAnonMember* getAsAnonMember() const { return this; }
|
||||
virtual const TVariable& getAnonContainer() const { return anonContainer; }
|
||||
virtual unsigned int getMemberNumber() const { return memberNumber; }
|
||||
|
||||
virtual const TType& getType() const
|
||||
{
|
||||
const TTypeList& types = *anonContainer.getType().getStruct();
|
||||
return *types[memberNumber].type;
|
||||
}
|
||||
|
||||
virtual TType& getWritableType()
|
||||
{
|
||||
assert(writable);
|
||||
const TTypeList& types = *anonContainer.getType().getStruct();
|
||||
return *types[memberNumber].type;
|
||||
}
|
||||
|
||||
virtual int getAnonId() const { return anonId; }
|
||||
virtual void dump(TInfoSink &infoSink) const;
|
||||
|
||||
protected:
|
||||
explicit TAnonMember(const TAnonMember&);
|
||||
TAnonMember& operator=(const TAnonMember&);
|
||||
|
||||
const TVariable& anonContainer;
|
||||
unsigned int memberNumber;
|
||||
int anonId;
|
||||
};
|
||||
|
||||
class TSymbolTableLevel {
|
||||
public:
|
||||
POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator())
|
||||
TSymbolTableLevel() : defaultPrecision(0), anonId(0) { }
|
||||
~TSymbolTableLevel();
|
||||
|
||||
bool insert(TSymbol& symbol, bool separateNameSpaces)
|
||||
{
|
||||
//
|
||||
// returning true means symbol was added to the table with no semantic errors
|
||||
//
|
||||
tInsertResult result;
|
||||
const TString& name = symbol.getName();
|
||||
if (name == "") {
|
||||
// An empty name means an anonymous container, exposing its members to the external scope.
|
||||
// Give it a name and insert its members in the symbol table, pointing to the container.
|
||||
char buf[20];
|
||||
snprintf(buf, 20, "%s%d", AnonymousPrefix, anonId);
|
||||
symbol.changeName(NewPoolTString(buf));
|
||||
|
||||
bool isOkay = true;
|
||||
const TTypeList& types = *symbol.getAsVariable()->getType().getStruct();
|
||||
for (unsigned int m = 0; m < types.size(); ++m) {
|
||||
TAnonMember* member = new TAnonMember(&types[m].type->getFieldName(), m, *symbol.getAsVariable(), anonId);
|
||||
result = level.insert(tLevelPair(member->getMangledName(), member));
|
||||
if (! result.second)
|
||||
isOkay = false;
|
||||
}
|
||||
|
||||
++anonId;
|
||||
|
||||
return isOkay;
|
||||
} else {
|
||||
// Check for redefinition errors:
|
||||
// - STL itself will tell us if there is a direct name collision, with name mangling, at this level
|
||||
// - additionally, check for function-redefining-variable name collisions
|
||||
const TString& insertName = symbol.getMangledName();
|
||||
if (symbol.getAsFunction()) {
|
||||
// make sure there isn't a variable of this name
|
||||
if (! separateNameSpaces && level.find(name) != level.end())
|
||||
return false;
|
||||
|
||||
// insert, and whatever happens is okay
|
||||
level.insert(tLevelPair(insertName, &symbol));
|
||||
|
||||
return true;
|
||||
} else {
|
||||
result = level.insert(tLevelPair(insertName, &symbol));
|
||||
|
||||
return result.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TSymbol* find(const TString& name) const
|
||||
{
|
||||
tLevel::const_iterator it = level.find(name);
|
||||
if (it == level.end())
|
||||
return 0;
|
||||
else
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
void findFunctionNameList(const TString& name, TVector<TFunction*>& list)
|
||||
{
|
||||
size_t parenAt = name.find_first_of('(');
|
||||
TString base(name, 0, parenAt + 1);
|
||||
|
||||
tLevel::const_iterator begin = level.lower_bound(base);
|
||||
base[parenAt] = ')'; // assume ')' is lexically after '('
|
||||
tLevel::const_iterator end = level.upper_bound(base);
|
||||
for (tLevel::const_iterator it = begin; it != end; ++it)
|
||||
list.push_back(it->second->getAsFunction());
|
||||
}
|
||||
|
||||
// See if there is already a function in the table having the given non-function-style name.
|
||||
bool hasFunctionName(const TString& name) const
|
||||
{
|
||||
tLevel::const_iterator candidate = level.lower_bound(name);
|
||||
if (candidate != level.end()) {
|
||||
const TString& candidateName = (*candidate).first;
|
||||
TString::size_type parenAt = candidateName.find_first_of('(');
|
||||
if (parenAt != candidateName.npos && candidateName.compare(0, parenAt, name) == 0)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if there is a variable at this level having the given non-function-style name.
|
||||
// Return true if name is found, and set variable to true if the name was a variable.
|
||||
bool findFunctionVariableName(const TString& name, bool& variable) const
|
||||
{
|
||||
tLevel::const_iterator candidate = level.lower_bound(name);
|
||||
if (candidate != level.end()) {
|
||||
const TString& candidateName = (*candidate).first;
|
||||
TString::size_type parenAt = candidateName.find_first_of('(');
|
||||
if (parenAt == candidateName.npos) {
|
||||
// not a mangled name
|
||||
if (candidateName == name) {
|
||||
// found a variable name match
|
||||
variable = true;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// a mangled name
|
||||
if (candidateName.compare(0, parenAt, name) == 0) {
|
||||
// found a function name match
|
||||
variable = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use this to do a lazy 'push' of precision defaults the first time
|
||||
// a precision statement is seen in a new scope. Leave it at 0 for
|
||||
// when no push was needed. Thus, it is not the current defaults,
|
||||
// it is what to restore the defaults to when popping a level.
|
||||
void setPreviousDefaultPrecisions(const TPrecisionQualifier *p)
|
||||
{
|
||||
// can call multiple times at one scope, will only latch on first call,
|
||||
// as we're tracking the previous scope's values, not the current values
|
||||
if (defaultPrecision != 0)
|
||||
return;
|
||||
|
||||
defaultPrecision = new TPrecisionQualifier[EbtNumTypes];
|
||||
for (int t = 0; t < EbtNumTypes; ++t)
|
||||
defaultPrecision[t] = p[t];
|
||||
}
|
||||
|
||||
void getPreviousDefaultPrecisions(TPrecisionQualifier *p)
|
||||
{
|
||||
// can be called for table level pops that didn't set the
|
||||
// defaults
|
||||
if (defaultPrecision == 0 || p == 0)
|
||||
return;
|
||||
|
||||
for (int t = 0; t < EbtNumTypes; ++t)
|
||||
p[t] = defaultPrecision[t];
|
||||
}
|
||||
|
||||
void relateToOperator(const char* name, TOperator op);
|
||||
void setFunctionExtensions(const char* name, int num, const char* const extensions[]);
|
||||
void dump(TInfoSink &infoSink) const;
|
||||
TSymbolTableLevel* clone() const;
|
||||
void readOnly();
|
||||
|
||||
protected:
|
||||
explicit TSymbolTableLevel(TSymbolTableLevel&);
|
||||
TSymbolTableLevel& operator=(TSymbolTableLevel&);
|
||||
|
||||
typedef std::map<TString, TSymbol*, std::less<TString>, pool_allocator<std::pair<const TString, TSymbol*> > > tLevel;
|
||||
typedef const tLevel::value_type tLevelPair;
|
||||
typedef std::pair<tLevel::iterator, bool> tInsertResult;
|
||||
|
||||
tLevel level; // named mappings
|
||||
TPrecisionQualifier *defaultPrecision;
|
||||
int anonId;
|
||||
};
|
||||
|
||||
class TSymbolTable {
|
||||
public:
|
||||
TSymbolTable() : uniqueId(0), noBuiltInRedeclarations(false), separateNameSpaces(false), adoptedLevels(0)
|
||||
{
|
||||
//
|
||||
// This symbol table cannot be used until push() is called.
|
||||
//
|
||||
}
|
||||
~TSymbolTable()
|
||||
{
|
||||
// this can be called explicitly; safest to code it so it can be called multiple times
|
||||
|
||||
// don't deallocate levels passed in from elsewhere
|
||||
while (table.size() > adoptedLevels)
|
||||
pop(0);
|
||||
}
|
||||
|
||||
void adoptLevels(TSymbolTable& symTable)
|
||||
{
|
||||
for (unsigned int level = 0; level < symTable.table.size(); ++level) {
|
||||
table.push_back(symTable.table[level]);
|
||||
++adoptedLevels;
|
||||
}
|
||||
uniqueId = symTable.uniqueId;
|
||||
noBuiltInRedeclarations = symTable.noBuiltInRedeclarations;
|
||||
separateNameSpaces = symTable.separateNameSpaces;
|
||||
}
|
||||
|
||||
//
|
||||
// While level adopting is generic, the methods below enact a the following
|
||||
// convention for levels:
|
||||
// 0: common built-ins shared across all stages, all compiles, only one copy for all symbol tables
|
||||
// 1: per-stage built-ins, shared across all compiles, but a different copy per stage
|
||||
// 2: built-ins specific to a compile, like resources that are context-dependent, or redeclared built-ins
|
||||
// 3: user-shader globals
|
||||
//
|
||||
protected:
|
||||
static const int globalLevel = 3;
|
||||
bool isSharedLevel(int level) { return level <= 1; } // exclude all per-compile levels
|
||||
bool isBuiltInLevel(int level) { return level <= 2; } // exclude user globals
|
||||
bool isGlobalLevel(int level) { return level <= globalLevel; } // include user globals
|
||||
public:
|
||||
bool isEmpty() { return table.size() == 0; }
|
||||
bool atBuiltInLevel() { return isBuiltInLevel(currentLevel()); }
|
||||
bool atGlobalLevel() { return isGlobalLevel(currentLevel()); }
|
||||
|
||||
void setNoBuiltInRedeclarations() { noBuiltInRedeclarations = true; }
|
||||
void setSeparateNameSpaces() { separateNameSpaces = true; }
|
||||
|
||||
void push()
|
||||
{
|
||||
table.push_back(new TSymbolTableLevel);
|
||||
}
|
||||
|
||||
void pop(TPrecisionQualifier *p)
|
||||
{
|
||||
table[currentLevel()]->getPreviousDefaultPrecisions(p);
|
||||
delete table.back();
|
||||
table.pop_back();
|
||||
}
|
||||
|
||||
//
|
||||
// Insert a visible symbol into the symbol table so it can
|
||||
// be found later by name.
|
||||
//
|
||||
// Returns false if the was a name collision.
|
||||
//
|
||||
bool insert(TSymbol& symbol)
|
||||
{
|
||||
symbol.setUniqueId(++uniqueId);
|
||||
|
||||
// make sure there isn't a function of this variable name
|
||||
if (! separateNameSpaces && ! symbol.getAsFunction() && table[currentLevel()]->hasFunctionName(symbol.getName()))
|
||||
return false;
|
||||
|
||||
// check for not overloading or redefining a built-in function
|
||||
if (noBuiltInRedeclarations) {
|
||||
if (atGlobalLevel() && currentLevel() > 0) {
|
||||
if (table[0]->hasFunctionName(symbol.getName()))
|
||||
return false;
|
||||
if (currentLevel() > 1 && table[1]->hasFunctionName(symbol.getName()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return table[currentLevel()]->insert(symbol, separateNameSpaces);
|
||||
}
|
||||
|
||||
//
|
||||
// To allocate an internal temporary, which will need to be uniquely
|
||||
// identified by the consumer of the AST, but never need to
|
||||
// found by doing a symbol table search by name, hence allowed an
|
||||
// arbitrary name in the symbol with no worry of collision.
|
||||
//
|
||||
void makeInternalVariable(TSymbol& symbol)
|
||||
{
|
||||
symbol.setUniqueId(++uniqueId);
|
||||
}
|
||||
|
||||
//
|
||||
// Copy a variable or anonymous member's structure from a shared level so that
|
||||
// it can be added (soon after return) to the symbol table where it can be
|
||||
// modified without impacting other users of the shared table.
|
||||
//
|
||||
TSymbol* copyUpDeferredInsert(TSymbol* shared)
|
||||
{
|
||||
if (shared->getAsVariable()) {
|
||||
TSymbol* copy = shared->clone();
|
||||
copy->setUniqueId(shared->getUniqueId());
|
||||
return copy;
|
||||
} else {
|
||||
const TAnonMember* anon = shared->getAsAnonMember();
|
||||
assert(anon);
|
||||
TVariable* container = anon->getAnonContainer().clone();
|
||||
container->changeName(NewPoolTString(""));
|
||||
container->setUniqueId(anon->getAnonContainer().getUniqueId());
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
TSymbol* copyUp(TSymbol* shared)
|
||||
{
|
||||
TSymbol* copy = copyUpDeferredInsert(shared);
|
||||
table[globalLevel]->insert(*copy, separateNameSpaces);
|
||||
if (shared->getAsVariable())
|
||||
return copy;
|
||||
else {
|
||||
// return the copy of the anonymous member
|
||||
return table[globalLevel]->find(shared->getName());
|
||||
}
|
||||
}
|
||||
|
||||
TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0)
|
||||
{
|
||||
int level = currentLevel();
|
||||
TSymbol* symbol;
|
||||
do {
|
||||
symbol = table[level]->find(name);
|
||||
--level;
|
||||
} while (symbol == 0 && level >= 0);
|
||||
level++;
|
||||
if (builtIn)
|
||||
*builtIn = isBuiltInLevel(level);
|
||||
if (currentScope)
|
||||
*currentScope = isGlobalLevel(currentLevel()) || level == currentLevel(); // consider shared levels as "current scope" WRT user globals
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
bool isFunctionNameVariable(const TString& name) const
|
||||
{
|
||||
if (separateNameSpaces)
|
||||
return false;
|
||||
|
||||
int level = currentLevel();
|
||||
do {
|
||||
bool variable;
|
||||
bool found = table[level]->findFunctionVariableName(name, variable);
|
||||
if (found)
|
||||
return variable;
|
||||
--level;
|
||||
} while (level >= 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void findFunctionNameList(const TString& name, TVector<TFunction*>& list, bool& builtIn)
|
||||
{
|
||||
// For user levels, return the set found in the first scope with a match
|
||||
builtIn = false;
|
||||
int level = currentLevel();
|
||||
do {
|
||||
table[level]->findFunctionNameList(name, list);
|
||||
--level;
|
||||
} while (list.empty() && level >= globalLevel);
|
||||
|
||||
if (! list.empty())
|
||||
return;
|
||||
|
||||
// Gather across all built-in levels; they don't hide each other
|
||||
builtIn = true;
|
||||
do {
|
||||
table[level]->findFunctionNameList(name, list);
|
||||
--level;
|
||||
} while (level >= 0);
|
||||
}
|
||||
|
||||
void relateToOperator(const char* name, TOperator op)
|
||||
{
|
||||
for (unsigned int level = 0; level < table.size(); ++level)
|
||||
table[level]->relateToOperator(name, op);
|
||||
}
|
||||
|
||||
void setFunctionExtensions(const char* name, int num, const char* const extensions[])
|
||||
{
|
||||
for (unsigned int level = 0; level < table.size(); ++level)
|
||||
table[level]->setFunctionExtensions(name, num, extensions);
|
||||
}
|
||||
|
||||
void setVariableExtensions(const char* name, int num, const char* const extensions[])
|
||||
{
|
||||
TSymbol* symbol = find(TString(name));
|
||||
if (symbol)
|
||||
symbol->setExtensions(num, extensions);
|
||||
}
|
||||
|
||||
int getMaxSymbolId() { return uniqueId; }
|
||||
void dump(TInfoSink &infoSink) const;
|
||||
void copyTable(const TSymbolTable& copyOf);
|
||||
|
||||
void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); }
|
||||
|
||||
void readOnly()
|
||||
{
|
||||
for (unsigned int level = 0; level < table.size(); ++level)
|
||||
table[level]->readOnly();
|
||||
}
|
||||
|
||||
protected:
|
||||
TSymbolTable(TSymbolTable&);
|
||||
TSymbolTable& operator=(TSymbolTableLevel&);
|
||||
|
||||
int currentLevel() const { return static_cast<int>(table.size()) - 1; }
|
||||
|
||||
std::vector<TSymbolTableLevel*> table;
|
||||
int uniqueId; // for unique identification in code generation
|
||||
bool noBuiltInRedeclarations;
|
||||
bool separateNameSpaces;
|
||||
unsigned int adoptedLevels;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _SYMBOL_TABLE_INCLUDED_
|
|
@ -0,0 +1,691 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// Help manage multiple profiles, versions, extensions etc.
|
||||
//
|
||||
// These don't return error codes, as the presumption is parsing will
|
||||
// always continue as if the tested feature were enabled, and thus there
|
||||
// is no error recovery needed.
|
||||
//
|
||||
|
||||
//
|
||||
// HOW TO add a feature enabled by an extension.
|
||||
//
|
||||
// To add a new hypothetical "Feature F" to the front end, where an extension
|
||||
// "XXX_extension_X" can be used to enable the feature, do the following.
|
||||
//
|
||||
// OVERVIEW: Specific features are what are error-checked for, not
|
||||
// extensions: A specific Feature F might be enabled by an extension, or a
|
||||
// particular version in a particular profile, or a stage, or combinations, etc.
|
||||
//
|
||||
// The basic mechanism is to use the following to "declare" all the things that
|
||||
// enable/disable Feature F, in a code path that implements Feature F:
|
||||
//
|
||||
// requireProfile()
|
||||
// profileRequires()
|
||||
// requireStage()
|
||||
// checkDeprecated()
|
||||
// requireNotRemoved()
|
||||
// requireExtensions()
|
||||
//
|
||||
// Typically, only the first two calls are needed. They go into a code path that
|
||||
// implements Feature F, and will log the proper error/warning messages. Parsing
|
||||
// will then always continue as if the tested feature was enabled.
|
||||
//
|
||||
// There is typically no if-testing or conditional parsing, just insertion of the calls above.
|
||||
// However, if symbols specific to the extension are added (step 5), they will
|
||||
// only be added under tests that the minimum version and profile are present.
|
||||
//
|
||||
// 1) Add a symbol name for the extension string at the bottom of Versions.h:
|
||||
//
|
||||
// const char* const XXX_extension_X = "XXX_extension_X";
|
||||
//
|
||||
// 2) Add extension initialization to TParseVersions::initializeExtensionBehavior(),
|
||||
// the first function below:
|
||||
//
|
||||
// extensionBehavior[XXX_extension_X] = EBhDisable;
|
||||
//
|
||||
// 3) Add any preprocessor directives etc. in the next function, TParseVersions::getPreamble():
|
||||
//
|
||||
// "#define XXX_extension_X 1\n"
|
||||
//
|
||||
// The new-line is important, as that ends preprocess tokens.
|
||||
//
|
||||
// 4) Insert a profile check in the feature's path (unless all profiles support the feature,
|
||||
// for some version level). That is, call requireProfile() to constrain the profiles, e.g.:
|
||||
//
|
||||
// // ... in a path specific to Feature F...
|
||||
// requireProfile(loc,
|
||||
// ECoreProfile | ECompatibilityProfile,
|
||||
// "Feature F");
|
||||
//
|
||||
// 5) For each profile that supports the feature, insert version/extension checks:
|
||||
//
|
||||
// The mostly likely scenario is that Feature F can only be used with a
|
||||
// particular profile if XXX_extension_X is present or the version is
|
||||
// high enough that the core specification already incorporated it.
|
||||
//
|
||||
// // following the requireProfile() call...
|
||||
// profileRequires(loc,
|
||||
// ECoreProfile | ECompatibilityProfile,
|
||||
// 420, // 0 if no version incorporated the feature into the core spec.
|
||||
// XXX_extension_X, // can be a list of extensions that all add the feature
|
||||
// "Feature F Description");
|
||||
//
|
||||
// This allows the feature if either A) one of the extensions is enabled or
|
||||
// B) the version is high enough. If no version yet incorporates the feature
|
||||
// into core, pass in 0.
|
||||
//
|
||||
// This can be called multiple times, if different profiles support the
|
||||
// feature starting at different version numbers or with different
|
||||
// extensions.
|
||||
//
|
||||
// This must be called for each profile allowed by the initial call to requireProfile().
|
||||
//
|
||||
// Profiles are all masks, which can be "or"-ed together.
|
||||
//
|
||||
// ENoProfile
|
||||
// ECoreProfile
|
||||
// ECompatibilityProfile
|
||||
// EEsProfile
|
||||
//
|
||||
// The ENoProfile profile is only for desktop, before profiles showed up in version 150;
|
||||
// All other #version with no profile default to either es or core, and so have profiles.
|
||||
//
|
||||
// You can select all but a particular profile using ~. The following basically means "desktop":
|
||||
//
|
||||
// ~EEsProfile
|
||||
//
|
||||
// 6) If built-in symbols are added by the extension, add them in Initialize.cpp: Their use
|
||||
// will be automatically error checked against the extensions enabled at that moment.
|
||||
// see the comment at the top of Initialize.cpp for where to put them. Establish them at
|
||||
// the earliest release that supports the extension. Then, tag them with the
|
||||
// set of extensions that both enable them and are necessary, given the version of the symbol
|
||||
// table. (There is a different symbol table for each version.)
|
||||
//
|
||||
|
||||
#include "parseVersions.h"
|
||||
#include "localintermediate.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Initialize all extensions, almost always to 'disable', as once their features
|
||||
// are incorporated into a core version, their features are supported through allowing that
|
||||
// core version, not through a pseudo-enablement of the extension.
|
||||
//
|
||||
void TParseVersions::initializeExtensionBehavior()
|
||||
{
|
||||
extensionBehavior[E_GL_OES_texture_3D] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_standard_derivatives] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_frag_depth] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_EGL_image_external] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_shader_texture_lod] = EBhDisable;
|
||||
|
||||
extensionBehavior[E_GL_ARB_texture_rectangle] = EBhDisable;
|
||||
extensionBehavior[E_GL_3DL_array_objects] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shading_language_420pack] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_texture_gather] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_gpu_shader5] = EBhDisablePartial;
|
||||
extensionBehavior[E_GL_ARB_separate_shader_objects] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_compute_shader] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_tessellation_shader] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_enhanced_layouts] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_texture_cube_map_array] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_texture_lod] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_explicit_attrib_location] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_image_load_store] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_atomic_counters] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_draw_parameters] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_group_vote] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_derivative_control] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_texture_image_samples] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_viewport_array] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_gpu_shader_int64] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_shader_ballot] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_sparse_texture2] = EBhDisable;
|
||||
extensionBehavior[E_GL_ARB_sparse_texture_clamp] = EBhDisable;
|
||||
// extensionBehavior[E_GL_ARB_cull_distance] = EBhDisable; // present for 4.5, but need extension control over block members
|
||||
|
||||
extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
|
||||
|
||||
// #line and #include
|
||||
extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable;
|
||||
extensionBehavior[E_GL_GOOGLE_include_directive] = EBhDisable;
|
||||
|
||||
// AEP
|
||||
extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisable;
|
||||
extensionBehavior[E_GL_KHR_blend_equation_advanced] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_sample_variables] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_shader_image_atomic] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_shader_multisample_interpolation] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_texture_storage_multisample_2d_array] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_geometry_shader] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_geometry_point_size] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_gpu_shader5] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_primitive_bounding_box] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_shader_io_blocks] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_tessellation_shader] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_tessellation_point_size] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_texture_buffer] = EBhDisable;
|
||||
extensionBehavior[E_GL_EXT_texture_cube_map_array] = EBhDisable;
|
||||
|
||||
// OES matching AEP
|
||||
extensionBehavior[E_GL_OES_geometry_shader] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_geometry_point_size] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_gpu_shader5] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_primitive_bounding_box] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_shader_io_blocks] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_tessellation_shader] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_tessellation_point_size] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_texture_buffer] = EBhDisable;
|
||||
extensionBehavior[E_GL_OES_texture_cube_map_array] = EBhDisable;
|
||||
}
|
||||
|
||||
// Get code that is not part of a shared symbol table, is specific to this shader,
|
||||
// or needed by the preprocessor (which does not use a shared symbol table).
|
||||
void TParseVersions::getPreamble(std::string& preamble)
|
||||
{
|
||||
if (profile == EEsProfile) {
|
||||
preamble =
|
||||
"#define GL_ES 1\n"
|
||||
"#define GL_FRAGMENT_PRECISION_HIGH 1\n"
|
||||
"#define GL_OES_texture_3D 1\n"
|
||||
"#define GL_OES_standard_derivatives 1\n"
|
||||
"#define GL_EXT_frag_depth 1\n"
|
||||
"#define GL_OES_EGL_image_external 1\n"
|
||||
"#define GL_EXT_shader_texture_lod 1\n"
|
||||
|
||||
// AEP
|
||||
"#define GL_ANDROID_extension_pack_es31a 1\n"
|
||||
"#define GL_KHR_blend_equation_advanced 1\n"
|
||||
"#define GL_OES_sample_variables 1\n"
|
||||
"#define GL_OES_shader_image_atomic 1\n"
|
||||
"#define GL_OES_shader_multisample_interpolation 1\n"
|
||||
"#define GL_OES_texture_storage_multisample_2d_array 1\n"
|
||||
"#define GL_EXT_geometry_shader 1\n"
|
||||
"#define GL_EXT_geometry_point_size 1\n"
|
||||
"#define GL_EXT_gpu_shader5 1\n"
|
||||
"#define GL_EXT_primitive_bounding_box 1\n"
|
||||
"#define GL_EXT_shader_io_blocks 1\n"
|
||||
"#define GL_EXT_tessellation_shader 1\n"
|
||||
"#define GL_EXT_tessellation_point_size 1\n"
|
||||
"#define GL_EXT_texture_buffer 1\n"
|
||||
"#define GL_EXT_texture_cube_map_array 1\n"
|
||||
|
||||
// OES matching AEP
|
||||
"#define GL_OES_geometry_shader 1\n"
|
||||
"#define GL_OES_geometry_point_size 1\n"
|
||||
"#define GL_OES_gpu_shader5 1\n"
|
||||
"#define GL_OES_primitive_bounding_box 1\n"
|
||||
"#define GL_OES_shader_io_blocks 1\n"
|
||||
"#define GL_OES_tessellation_shader 1\n"
|
||||
"#define GL_OES_tessellation_point_size 1\n"
|
||||
"#define GL_OES_texture_buffer 1\n"
|
||||
"#define GL_OES_texture_cube_map_array 1\n"
|
||||
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
||||
;
|
||||
} else {
|
||||
preamble =
|
||||
"#define GL_FRAGMENT_PRECISION_HIGH 1\n"
|
||||
"#define GL_ARB_texture_rectangle 1\n"
|
||||
"#define GL_ARB_shading_language_420pack 1\n"
|
||||
"#define GL_ARB_texture_gather 1\n"
|
||||
"#define GL_ARB_gpu_shader5 1\n"
|
||||
"#define GL_ARB_separate_shader_objects 1\n"
|
||||
"#define GL_ARB_compute_shader 1\n"
|
||||
"#define GL_ARB_tessellation_shader 1\n"
|
||||
"#define GL_ARB_enhanced_layouts 1\n"
|
||||
"#define GL_ARB_texture_cube_map_array 1\n"
|
||||
"#define GL_ARB_shader_texture_lod 1\n"
|
||||
"#define GL_ARB_explicit_attrib_location 1\n"
|
||||
"#define GL_ARB_shader_image_load_store 1\n"
|
||||
"#define GL_ARB_shader_atomic_counters 1\n"
|
||||
"#define GL_ARB_shader_draw_parameters 1\n"
|
||||
"#define GL_ARB_shader_group_vote 1\n"
|
||||
"#define GL_ARB_derivative_control 1\n"
|
||||
"#define GL_ARB_shader_texture_image_samples 1\n"
|
||||
"#define GL_ARB_viewport_array 1\n"
|
||||
"#define GL_ARB_gpu_shader_int64 1\n"
|
||||
"#define GL_ARB_shader_ballot 1\n"
|
||||
"#define GL_ARB_sparse_texture2 1\n"
|
||||
"#define GL_ARB_sparse_texture_clamp 1\n"
|
||||
// "#define GL_ARB_cull_distance 1\n" // present for 4.5, but need extension control over block members
|
||||
"#define GL_EXT_shader_non_constant_global_initializers 1\n"
|
||||
;
|
||||
}
|
||||
|
||||
// #line and #include
|
||||
preamble +=
|
||||
"#define GL_GOOGLE_cpp_style_line_directive 1\n"
|
||||
"#define GL_GOOGLE_include_directive 1\n"
|
||||
;
|
||||
|
||||
// #define VULKAN XXXX
|
||||
const int numberBufSize = 12;
|
||||
char numberBuf[numberBufSize];
|
||||
if (spvVersion.vulkan > 0) {
|
||||
preamble += "#define VULKAN ";
|
||||
snprintf(numberBuf, numberBufSize, "%d", spvVersion.vulkan);
|
||||
preamble += numberBuf;
|
||||
preamble += "\n";
|
||||
}
|
||||
// #define GL_SPIRV XXXX
|
||||
if (spvVersion.openGl > 0) {
|
||||
preamble += "#define GL_SPIRV ";
|
||||
snprintf(numberBuf, numberBufSize, "%d", spvVersion.openGl);
|
||||
preamble += numberBuf;
|
||||
preamble += "\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// When to use requireProfile():
|
||||
//
|
||||
// Use if only some profiles support a feature. However, if within a profile the feature
|
||||
// is version or extension specific, follow this call with calls to profileRequires().
|
||||
//
|
||||
// Operation: If the current profile is not one of the profileMask,
|
||||
// give an error message.
|
||||
//
|
||||
void TParseVersions::requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc)
|
||||
{
|
||||
if (! (profile & profileMask))
|
||||
error(loc, "not supported with this profile:", featureDesc, ProfileName(profile));
|
||||
}
|
||||
|
||||
//
|
||||
// Map from stage enum to externally readable text name.
|
||||
//
|
||||
const char* StageName(EShLanguage stage)
|
||||
{
|
||||
switch(stage) {
|
||||
case EShLangVertex: return "vertex";
|
||||
case EShLangTessControl: return "tessellation control";
|
||||
case EShLangTessEvaluation: return "tessellation evaluation";
|
||||
case EShLangGeometry: return "geometry";
|
||||
case EShLangFragment: return "fragment";
|
||||
case EShLangCompute: return "compute";
|
||||
default: return "unknown stage";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// When to use profileRequires():
|
||||
//
|
||||
// If a set of profiles have the same requirements for what version or extensions
|
||||
// are needed to support a feature.
|
||||
//
|
||||
// It must be called for each profile that needs protection. Use requireProfile() first
|
||||
// to reduce that set of profiles.
|
||||
//
|
||||
// Operation: Will issue warnings/errors based on the current profile, version, and extension
|
||||
// behaviors. It only checks extensions when the current profile is one of the profileMask.
|
||||
//
|
||||
// A minVersion of 0 means no version of the profileMask support this in core,
|
||||
// the extension must be present.
|
||||
//
|
||||
|
||||
// entry point that takes multiple extensions
|
||||
void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
{
|
||||
if (profile & profileMask) {
|
||||
bool okay = false;
|
||||
if (minVersion > 0 && version >= minVersion)
|
||||
okay = true;
|
||||
for (int i = 0; i < numExtensions; ++i) {
|
||||
switch (getExtensionBehavior(extensions[i])) {
|
||||
case EBhWarn:
|
||||
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
|
||||
// fall through
|
||||
case EBhRequire:
|
||||
case EBhEnable:
|
||||
okay = true;
|
||||
break;
|
||||
default: break; // some compilers want this
|
||||
}
|
||||
}
|
||||
|
||||
if (! okay)
|
||||
error(loc, "not supported for this version or the enabled extensions", featureDesc, "");
|
||||
}
|
||||
}
|
||||
|
||||
// entry point for the above that takes a single extension
|
||||
void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension, const char* featureDesc)
|
||||
{
|
||||
profileRequires(loc, profileMask, minVersion, extension ? 1 : 0, &extension, featureDesc);
|
||||
}
|
||||
|
||||
//
|
||||
// When to use requireStage()
|
||||
//
|
||||
// If only some stages support a feature.
|
||||
//
|
||||
// Operation: If the current stage is not present, give an error message.
|
||||
//
|
||||
void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguageMask languageMask, const char* featureDesc)
|
||||
{
|
||||
if (((1 << language) & languageMask) == 0)
|
||||
error(loc, "not supported in this stage:", featureDesc, StageName(language));
|
||||
}
|
||||
|
||||
// If only one stage supports a feature, this can be called. But, all supporting stages
|
||||
// must be specified with one call.
|
||||
void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguage stage, const char* featureDesc)
|
||||
{
|
||||
requireStage(loc, static_cast<EShLanguageMask>(1 << stage), featureDesc);
|
||||
}
|
||||
|
||||
//
|
||||
// Within a set of profiles, see if a feature is deprecated and give an error or warning based on whether
|
||||
// a future compatibility context is being use.
|
||||
//
|
||||
void TParseVersions::checkDeprecated(const TSourceLoc& loc, int profileMask, int depVersion, const char* featureDesc)
|
||||
{
|
||||
if (profile & profileMask) {
|
||||
if (version >= depVersion) {
|
||||
if (forwardCompatible)
|
||||
error(loc, "deprecated, may be removed in future release", featureDesc, "");
|
||||
else if (! suppressWarnings())
|
||||
infoSink.info.message(EPrefixWarning, (TString(featureDesc) + " deprecated in version " +
|
||||
String(depVersion) + "; may be removed in future release").c_str(), loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Within a set of profiles, see if a feature has now been removed and if so, give an error.
|
||||
// The version argument is the first version no longer having the feature.
|
||||
//
|
||||
void TParseVersions::requireNotRemoved(const TSourceLoc& loc, int profileMask, int removedVersion, const char* featureDesc)
|
||||
{
|
||||
if (profile & profileMask) {
|
||||
if (version >= removedVersion) {
|
||||
const int maxSize = 60;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%s profile; removed in version %d", ProfileName(profile), removedVersion);
|
||||
error(loc, "no longer supported in", featureDesc, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if at least one of the extensions in the extensions parameter is requested. Otherwise, returns false.
|
||||
// Warns appropriately if the requested behavior of an extension is "warn".
|
||||
bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
{
|
||||
// First, see if any of the extensions are enabled
|
||||
for (int i = 0; i < numExtensions; ++i) {
|
||||
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
|
||||
if (behavior == EBhEnable || behavior == EBhRequire)
|
||||
return true;
|
||||
}
|
||||
|
||||
// See if any extensions want to give a warning on use; give warnings for all such extensions
|
||||
bool warned = false;
|
||||
for (int i = 0; i < numExtensions; ++i) {
|
||||
TExtensionBehavior behavior = getExtensionBehavior(extensions[i]);
|
||||
if (behavior == EBhDisable && relaxedErrors()) {
|
||||
infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc);
|
||||
behavior = EBhWarn;
|
||||
}
|
||||
if (behavior == EBhWarn) {
|
||||
infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc);
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
if (warned)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Use when there are no profile/version to check, it's just an error if one of the
|
||||
// extensions is not present.
|
||||
//
|
||||
void TParseVersions::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
{
|
||||
if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
|
||||
|
||||
// If we get this far, give errors explaining what extensions are needed
|
||||
if (numExtensions == 1)
|
||||
error(loc, "required extension not requested:", featureDesc, extensions[0]);
|
||||
else {
|
||||
error(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
|
||||
for (int i = 0; i < numExtensions; ++i)
|
||||
infoSink.info.message(EPrefixNone, extensions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Use by preprocessor when there are no profile/version to check, it's just an error if one of the
|
||||
// extensions is not present.
|
||||
//
|
||||
void TParseVersions::ppRequireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
|
||||
{
|
||||
if (checkExtensionsRequested(loc, numExtensions, extensions, featureDesc)) return;
|
||||
|
||||
// If we get this far, give errors explaining what extensions are needed
|
||||
if (numExtensions == 1)
|
||||
ppError(loc, "required extension not requested:", featureDesc, extensions[0]);
|
||||
else {
|
||||
ppError(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
|
||||
for (int i = 0; i < numExtensions; ++i)
|
||||
infoSink.info.message(EPrefixNone, extensions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TExtensionBehavior TParseVersions::getExtensionBehavior(const char* extension)
|
||||
{
|
||||
auto iter = extensionBehavior.find(TString(extension));
|
||||
if (iter == extensionBehavior.end())
|
||||
return EBhMissing;
|
||||
else
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
// Returns true if the given extension is set to enable, require, or warn.
|
||||
bool TParseVersions::extensionTurnedOn(const char* const extension)
|
||||
{
|
||||
switch (getExtensionBehavior(extension)) {
|
||||
case EBhEnable:
|
||||
case EBhRequire:
|
||||
case EBhWarn:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// See if any of the extensions are set to enable, require, or warn.
|
||||
bool TParseVersions::extensionsTurnedOn(int numExtensions, const char* const extensions[])
|
||||
{
|
||||
for (int i = 0; i < numExtensions; ++i) {
|
||||
if (extensionTurnedOn(extensions[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Change the current state of an extension's behavior.
|
||||
//
|
||||
void TParseVersions::updateExtensionBehavior(int line, const char* extension, const char* behaviorString)
|
||||
{
|
||||
// Translate from text string of extension's behavior to an enum.
|
||||
TExtensionBehavior behavior = EBhDisable;
|
||||
if (! strcmp("require", behaviorString))
|
||||
behavior = EBhRequire;
|
||||
else if (! strcmp("enable", behaviorString))
|
||||
behavior = EBhEnable;
|
||||
else if (! strcmp("disable", behaviorString))
|
||||
behavior = EBhDisable;
|
||||
else if (! strcmp("warn", behaviorString))
|
||||
behavior = EBhWarn;
|
||||
else {
|
||||
error(getCurrentLoc(), "behavior not supported:", "#extension", behaviorString);
|
||||
return;
|
||||
}
|
||||
|
||||
// update the requested extension
|
||||
updateExtensionBehavior(extension, behavior);
|
||||
|
||||
// see if need to propagate to implicitly modified things
|
||||
if (strcmp(extension, "GL_ANDROID_extension_pack_es31a") == 0) {
|
||||
// to everything in AEP
|
||||
updateExtensionBehavior(line, "GL_KHR_blend_equation_advanced", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_OES_sample_variables", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_OES_shader_image_atomic", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_OES_shader_multisample_interpolation", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_OES_texture_storage_multisample_2d_array", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_EXT_geometry_shader", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_EXT_gpu_shader5", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_EXT_primitive_bounding_box", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_EXT_tessellation_shader", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_EXT_texture_buffer", behaviorString);
|
||||
updateExtensionBehavior(line, "GL_EXT_texture_cube_map_array", behaviorString);
|
||||
}
|
||||
// geometry to io_blocks
|
||||
else if (strcmp(extension, "GL_EXT_geometry_shader") == 0)
|
||||
updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
|
||||
else if (strcmp(extension, "GL_OES_geometry_shader") == 0)
|
||||
updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
|
||||
// tessellation to io_blocks
|
||||
else if (strcmp(extension, "GL_EXT_tessellation_shader") == 0)
|
||||
updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
|
||||
else if (strcmp(extension, "GL_OES_tessellation_shader") == 0)
|
||||
updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
|
||||
else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0)
|
||||
updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString);
|
||||
}
|
||||
|
||||
void TParseVersions::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
|
||||
{
|
||||
// Update the current behavior
|
||||
if (strcmp(extension, "all") == 0) {
|
||||
// special case for the 'all' extension; apply it to every extension present
|
||||
if (behavior == EBhRequire || behavior == EBhEnable) {
|
||||
error(getCurrentLoc(), "extension 'all' cannot have 'require' or 'enable' behavior", "#extension", "");
|
||||
return;
|
||||
} else {
|
||||
for (auto iter = extensionBehavior.begin(); iter != extensionBehavior.end(); ++iter)
|
||||
iter->second = behavior;
|
||||
}
|
||||
} else {
|
||||
// Do the update for this single extension
|
||||
auto iter = extensionBehavior.find(TString(extension));
|
||||
if (iter == extensionBehavior.end()) {
|
||||
switch (behavior) {
|
||||
case EBhRequire:
|
||||
error(getCurrentLoc(), "extension not supported:", "#extension", extension);
|
||||
break;
|
||||
case EBhEnable:
|
||||
case EBhWarn:
|
||||
case EBhDisable:
|
||||
warn(getCurrentLoc(), "extension not supported:", "#extension", extension);
|
||||
break;
|
||||
default:
|
||||
assert(0 && "unexpected behavior");
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
if (iter->second == EBhDisablePartial)
|
||||
warn(getCurrentLoc(), "extension is only partially supported:", "#extension", extension);
|
||||
if (behavior == EBhEnable || behavior == EBhRequire)
|
||||
intermediate.addRequestedExtension(extension);
|
||||
iter->second = behavior;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call for any operation needing full GLSL integer data-type support.
|
||||
void TParseVersions::fullIntegerCheck(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
profileRequires(loc, ENoProfile, 130, nullptr, op);
|
||||
profileRequires(loc, EEsProfile, 300, nullptr, op);
|
||||
}
|
||||
|
||||
// Call for any operation needing GLSL double data-type support.
|
||||
void TParseVersions::doubleCheck(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
|
||||
profileRequires(loc, ECoreProfile, 400, nullptr, op);
|
||||
profileRequires(loc, ECompatibilityProfile, 400, nullptr, op);
|
||||
}
|
||||
|
||||
// Call for any operation needing GLSL 64-bit integer data-type support.
|
||||
void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool builtIn)
|
||||
{
|
||||
if (! builtIn) {
|
||||
requireExtensions(loc, 1, &E_GL_ARB_gpu_shader_int64, "shader int64");
|
||||
requireProfile(loc, ECoreProfile | ECompatibilityProfile, op);
|
||||
profileRequires(loc, ECoreProfile, 450, nullptr, op);
|
||||
profileRequires(loc, ECompatibilityProfile, 450, nullptr, op);
|
||||
}
|
||||
}
|
||||
|
||||
// Call for any operation removed because SPIR-V is in use.
|
||||
void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (spvVersion.spv != 0)
|
||||
error(loc, "not allowed when generating SPIR-V", op, "");
|
||||
}
|
||||
|
||||
// Call for any operation removed because Vulkan SPIR-V is being generated.
|
||||
void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (spvVersion.vulkan >= 100)
|
||||
error(loc, "not allowed when using GLSL for Vulkan", op, "");
|
||||
}
|
||||
|
||||
// Call for any operation that requires Vulkan.
|
||||
void TParseVersions::requireVulkan(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (spvVersion.vulkan == 0)
|
||||
error(loc, "only allowed when using GLSL for Vulkan", op, "");
|
||||
}
|
||||
|
||||
// Call for any operation that requires SPIR-V.
|
||||
void TParseVersions::requireSpv(const TSourceLoc& loc, const char* op)
|
||||
{
|
||||
if (spvVersion.spv == 0)
|
||||
error(loc, "only allowed when generating SPIR-V", op, "");
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,197 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
#ifndef _VERSIONS_INCLUDED_
|
||||
#define _VERSIONS_INCLUDED_
|
||||
|
||||
//
|
||||
// Help manage multiple profiles, versions, extensions etc.
|
||||
//
|
||||
|
||||
//
|
||||
// Profiles are set up for masking operations, so queries can be done on multiple
|
||||
// profiles at the same time.
|
||||
//
|
||||
// Don't maintain an ordinal set of enums (0,1,2,3...) to avoid all possible
|
||||
// defects from mixing the two different forms.
|
||||
//
|
||||
typedef enum {
|
||||
EBadProfile = 0,
|
||||
ENoProfile = (1 << 0), // only for desktop, before profiles showed up
|
||||
ECoreProfile = (1 << 1),
|
||||
ECompatibilityProfile = (1 << 2),
|
||||
EEsProfile = (1 << 3)
|
||||
} EProfile;
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Map from profile enum to externally readable text name.
|
||||
//
|
||||
inline const char* ProfileName(EProfile profile)
|
||||
{
|
||||
switch (profile) {
|
||||
case ENoProfile: return "none";
|
||||
case ECoreProfile: return "core";
|
||||
case ECompatibilityProfile: return "compatibility";
|
||||
case EEsProfile: return "es";
|
||||
default: return "unknown profile";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// SPIR-V has versions for multiple things; tie them together.
|
||||
// 0 means a target or rule set is not enabled.
|
||||
//
|
||||
struct SpvVersion {
|
||||
SpvVersion() : spv(0), vulkan(0), openGl(0) {}
|
||||
unsigned int spv; // the version of the targeted SPIR-V, as defined by SPIR-V in word 1 of the SPIR-V binary header
|
||||
int vulkan; // the version of semantics for Vulkan; e.g., for GLSL from KHR_vulkan_glsl "#define VULKAN"
|
||||
int openGl; // the version of semantics for OpenGL; e.g., for GLSL from KHR_vulkan_glsl "#define GL_SPIRV"
|
||||
};
|
||||
|
||||
//
|
||||
// The behaviors from the GLSL "#extension extension_name : behavior"
|
||||
//
|
||||
typedef enum {
|
||||
EBhMissing = 0,
|
||||
EBhRequire,
|
||||
EBhEnable,
|
||||
EBhWarn,
|
||||
EBhDisable,
|
||||
EBhDisablePartial // use as initial state of an extension that is only partially implemented
|
||||
} TExtensionBehavior;
|
||||
|
||||
//
|
||||
// Symbolic names for extensions. Strings may be directly used when calling the
|
||||
// functions, but better to have the compiler do spelling checks.
|
||||
//
|
||||
const char* const E_GL_OES_texture_3D = "GL_OES_texture_3D";
|
||||
const char* const E_GL_OES_standard_derivatives = "GL_OES_standard_derivatives";
|
||||
const char* const E_GL_EXT_frag_depth = "GL_EXT_frag_depth";
|
||||
const char* const E_GL_OES_EGL_image_external = "GL_OES_EGL_image_external";
|
||||
const char* const E_GL_EXT_shader_texture_lod = "GL_EXT_shader_texture_lod";
|
||||
|
||||
const char* const E_GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle";
|
||||
const char* const E_GL_3DL_array_objects = "GL_3DL_array_objects";
|
||||
const char* const E_GL_ARB_shading_language_420pack = "GL_ARB_shading_language_420pack";
|
||||
const char* const E_GL_ARB_texture_gather = "GL_ARB_texture_gather";
|
||||
const char* const E_GL_ARB_gpu_shader5 = "GL_ARB_gpu_shader5";
|
||||
const char* const E_GL_ARB_separate_shader_objects = "GL_ARB_separate_shader_objects";
|
||||
const char* const E_GL_ARB_compute_shader = "GL_ARB_compute_shader";
|
||||
const char* const E_GL_ARB_tessellation_shader = "GL_ARB_tessellation_shader";
|
||||
const char* const E_GL_ARB_enhanced_layouts = "GL_ARB_enhanced_layouts";
|
||||
const char* const E_GL_ARB_texture_cube_map_array = "GL_ARB_texture_cube_map_array";
|
||||
const char* const E_GL_ARB_shader_texture_lod = "GL_ARB_shader_texture_lod";
|
||||
const char* const E_GL_ARB_explicit_attrib_location = "GL_ARB_explicit_attrib_location";
|
||||
const char* const E_GL_ARB_shader_image_load_store = "GL_ARB_shader_image_load_store";
|
||||
const char* const E_GL_ARB_shader_atomic_counters = "GL_ARB_shader_atomic_counters";
|
||||
const char* const E_GL_ARB_shader_draw_parameters = "GL_ARB_shader_draw_parameters";
|
||||
const char* const E_GL_ARB_shader_group_vote = "GL_ARB_shader_group_vote";
|
||||
const char* const E_GL_ARB_derivative_control = "GL_ARB_derivative_control";
|
||||
const char* const E_GL_ARB_shader_texture_image_samples = "GL_ARB_shader_texture_image_samples";
|
||||
const char* const E_GL_ARB_viewport_array = "GL_ARB_viewport_array";
|
||||
const char* const E_GL_ARB_gpu_shader_int64 = "GL_ARB_gpu_shader_int64";
|
||||
const char* const E_GL_ARB_shader_ballot = "GL_ARB_shader_ballot";
|
||||
const char* const E_GL_ARB_sparse_texture2 = "GL_ARB_sparse_texture2";
|
||||
const char* const E_GL_ARB_sparse_texture_clamp = "GL_ARB_sparse_texture_clamp";
|
||||
//const char* const E_GL_ARB_cull_distance = "GL_ARB_cull_distance"; // present for 4.5, but need extension control over block members
|
||||
|
||||
const char* const E_GL_EXT_shader_non_constant_global_initializers = "GL_EXT_shader_non_constant_global_initializers";
|
||||
|
||||
// #line and #include
|
||||
const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive";
|
||||
const char* const E_GL_GOOGLE_include_directive = "GL_GOOGLE_include_directive";
|
||||
|
||||
// AEP
|
||||
const char* const E_GL_ANDROID_extension_pack_es31a = "GL_ANDROID_extension_pack_es31a";
|
||||
const char* const E_GL_KHR_blend_equation_advanced = "GL_KHR_blend_equation_advanced";
|
||||
const char* const E_GL_OES_sample_variables = "GL_OES_sample_variables";
|
||||
const char* const E_GL_OES_shader_image_atomic = "GL_OES_shader_image_atomic";
|
||||
const char* const E_GL_OES_shader_multisample_interpolation = "GL_OES_shader_multisample_interpolation";
|
||||
const char* const E_GL_OES_texture_storage_multisample_2d_array = "GL_OES_texture_storage_multisample_2d_array";
|
||||
const char* const E_GL_EXT_geometry_shader = "GL_EXT_geometry_shader";
|
||||
const char* const E_GL_EXT_geometry_point_size = "GL_EXT_geometry_point_size";
|
||||
const char* const E_GL_EXT_gpu_shader5 = "GL_EXT_gpu_shader5";
|
||||
const char* const E_GL_EXT_primitive_bounding_box = "GL_EXT_primitive_bounding_box";
|
||||
const char* const E_GL_EXT_shader_io_blocks = "GL_EXT_shader_io_blocks";
|
||||
const char* const E_GL_EXT_tessellation_shader = "GL_EXT_tessellation_shader";
|
||||
const char* const E_GL_EXT_tessellation_point_size = "GL_EXT_tessellation_point_size";
|
||||
const char* const E_GL_EXT_texture_buffer = "GL_EXT_texture_buffer";
|
||||
const char* const E_GL_EXT_texture_cube_map_array = "GL_EXT_texture_cube_map_array";
|
||||
|
||||
// OES matching AEP
|
||||
const char* const E_GL_OES_geometry_shader = "GL_OES_geometry_shader";
|
||||
const char* const E_GL_OES_geometry_point_size = "GL_OES_geometry_point_size";
|
||||
const char* const E_GL_OES_gpu_shader5 = "GL_OES_gpu_shader5";
|
||||
const char* const E_GL_OES_primitive_bounding_box = "GL_OES_primitive_bounding_box";
|
||||
const char* const E_GL_OES_shader_io_blocks = "GL_OES_shader_io_blocks";
|
||||
const char* const E_GL_OES_tessellation_shader = "GL_OES_tessellation_shader";
|
||||
const char* const E_GL_OES_tessellation_point_size = "GL_OES_tessellation_point_size";
|
||||
const char* const E_GL_OES_texture_buffer = "GL_OES_texture_buffer";
|
||||
const char* const E_GL_OES_texture_cube_map_array = "GL_OES_texture_cube_map_array";
|
||||
|
||||
// Arrays of extensions for the above AEP duplications
|
||||
|
||||
const char* const AEP_geometry_shader[] = { E_GL_EXT_geometry_shader, E_GL_OES_geometry_shader };
|
||||
const int Num_AEP_geometry_shader = sizeof(AEP_geometry_shader)/sizeof(AEP_geometry_shader[0]);
|
||||
|
||||
const char* const AEP_geometry_point_size[] = { E_GL_EXT_geometry_point_size, E_GL_OES_geometry_point_size };
|
||||
const int Num_AEP_geometry_point_size = sizeof(AEP_geometry_point_size)/sizeof(AEP_geometry_point_size[0]);
|
||||
|
||||
const char* const AEP_gpu_shader5[] = { E_GL_EXT_gpu_shader5, E_GL_OES_gpu_shader5 };
|
||||
const int Num_AEP_gpu_shader5 = sizeof(AEP_gpu_shader5)/sizeof(AEP_gpu_shader5[0]);
|
||||
|
||||
const char* const AEP_primitive_bounding_box[] = { E_GL_EXT_primitive_bounding_box, E_GL_OES_primitive_bounding_box };
|
||||
const int Num_AEP_primitive_bounding_box = sizeof(AEP_primitive_bounding_box)/sizeof(AEP_primitive_bounding_box[0]);
|
||||
|
||||
const char* const AEP_shader_io_blocks[] = { E_GL_EXT_shader_io_blocks, E_GL_OES_shader_io_blocks };
|
||||
const int Num_AEP_shader_io_blocks = sizeof(AEP_shader_io_blocks)/sizeof(AEP_shader_io_blocks[0]);
|
||||
|
||||
const char* const AEP_tessellation_shader[] = { E_GL_EXT_tessellation_shader, E_GL_OES_tessellation_shader };
|
||||
const int Num_AEP_tessellation_shader = sizeof(AEP_tessellation_shader)/sizeof(AEP_tessellation_shader[0]);
|
||||
|
||||
const char* const AEP_tessellation_point_size[] = { E_GL_EXT_tessellation_point_size, E_GL_OES_tessellation_point_size };
|
||||
const int Num_AEP_tessellation_point_size = sizeof(AEP_tessellation_point_size)/sizeof(AEP_tessellation_point_size[0]);
|
||||
|
||||
const char* const AEP_texture_buffer[] = { E_GL_EXT_texture_buffer, E_GL_OES_texture_buffer };
|
||||
const int Num_AEP_texture_buffer = sizeof(AEP_texture_buffer)/sizeof(AEP_texture_buffer[0]);
|
||||
|
||||
const char* const AEP_texture_cube_map_array[] = { E_GL_EXT_texture_cube_map_array, E_GL_OES_texture_cube_map_array };
|
||||
const int Num_AEP_texture_cube_map_array = sizeof(AEP_texture_cube_map_array)/sizeof(AEP_texture_cube_map_array[0]);
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _VERSIONS_INCLUDED_
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
** Copyright (c) 2013 The Khronos Group 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 and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
|
||||
#define GL_FLOAT 0x1406
|
||||
#define GL_FLOAT_VEC2 0x8B50
|
||||
#define GL_FLOAT_VEC3 0x8B51
|
||||
#define GL_FLOAT_VEC4 0x8B52
|
||||
|
||||
#define GL_DOUBLE 0x140A
|
||||
#define GL_DOUBLE_VEC2 0x8FFC
|
||||
#define GL_DOUBLE_VEC3 0x8FFD
|
||||
#define GL_DOUBLE_VEC4 0x8FFE
|
||||
|
||||
#define GL_INT 0x1404
|
||||
#define GL_INT_VEC2 0x8B53
|
||||
#define GL_INT_VEC3 0x8B54
|
||||
#define GL_INT_VEC4 0x8B55
|
||||
|
||||
#define GL_UNSIGNED_INT 0x1405
|
||||
#define GL_UNSIGNED_INT_VEC2 0x8DC6
|
||||
#define GL_UNSIGNED_INT_VEC3 0x8DC7
|
||||
#define GL_UNSIGNED_INT_VEC4 0x8DC8
|
||||
|
||||
#define GL_INT64_ARB 0x140E
|
||||
#define GL_INT64_VEC2_ARB 0x8FE9
|
||||
#define GL_INT64_VEC3_ARB 0x8FEA
|
||||
#define GL_INT64_VEC4_ARB 0x8FEB
|
||||
|
||||
#define GL_UNSIGNED_INT64_ARB 0x140F
|
||||
#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FE5
|
||||
#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FE6
|
||||
#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FE7
|
||||
|
||||
#define GL_BOOL 0x8B56
|
||||
#define GL_BOOL_VEC2 0x8B57
|
||||
#define GL_BOOL_VEC3 0x8B58
|
||||
#define GL_BOOL_VEC4 0x8B59
|
||||
|
||||
#define GL_FLOAT_MAT2 0x8B5A
|
||||
#define GL_FLOAT_MAT3 0x8B5B
|
||||
#define GL_FLOAT_MAT4 0x8B5C
|
||||
#define GL_FLOAT_MAT2x3 0x8B65
|
||||
#define GL_FLOAT_MAT2x4 0x8B66
|
||||
#define GL_FLOAT_MAT3x2 0x8B67
|
||||
#define GL_FLOAT_MAT3x4 0x8B68
|
||||
#define GL_FLOAT_MAT4x2 0x8B69
|
||||
#define GL_FLOAT_MAT4x3 0x8B6A
|
||||
|
||||
#define GL_DOUBLE_MAT2 0x8F46
|
||||
#define GL_DOUBLE_MAT3 0x8F47
|
||||
#define GL_DOUBLE_MAT4 0x8F48
|
||||
#define GL_DOUBLE_MAT2x3 0x8F49
|
||||
#define GL_DOUBLE_MAT2x4 0x8F4A
|
||||
#define GL_DOUBLE_MAT3x2 0x8F4B
|
||||
#define GL_DOUBLE_MAT3x4 0x8F4C
|
||||
#define GL_DOUBLE_MAT4x2 0x8F4D
|
||||
#define GL_DOUBLE_MAT4x3 0x8F4E
|
||||
|
||||
#define GL_SAMPLER_1D 0x8B5D
|
||||
#define GL_SAMPLER_2D 0x8B5E
|
||||
#define GL_SAMPLER_3D 0x8B5F
|
||||
#define GL_SAMPLER_CUBE 0x8B60
|
||||
#define GL_SAMPLER_BUFFER 0x8DC2
|
||||
#define GL_SAMPLER_1D_ARRAY 0x8DC0
|
||||
#define GL_SAMPLER_2D_ARRAY 0x8DC1
|
||||
#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
|
||||
#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
|
||||
#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
|
||||
#define GL_SAMPLER_1D_SHADOW 0x8B61
|
||||
#define GL_SAMPLER_2D_SHADOW 0x8B62
|
||||
#define GL_SAMPLER_2D_RECT 0x8B63
|
||||
#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
|
||||
#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
|
||||
#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
|
||||
#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
|
||||
#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
|
||||
#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900C
|
||||
#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D
|
||||
|
||||
#define GL_INT_SAMPLER_1D 0x8DC9
|
||||
#define GL_INT_SAMPLER_2D 0x8DCA
|
||||
#define GL_INT_SAMPLER_3D 0x8DCB
|
||||
#define GL_INT_SAMPLER_CUBE 0x8DCC
|
||||
#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
|
||||
#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
|
||||
#define GL_INT_SAMPLER_2D_RECT 0x8DCD
|
||||
#define GL_INT_SAMPLER_BUFFER 0x8DD0
|
||||
#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
|
||||
#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
|
||||
#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
|
||||
#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E
|
||||
|
||||
#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
|
||||
#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
|
||||
#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
|
||||
#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
|
||||
#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
|
||||
#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
|
||||
#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
|
||||
#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
|
||||
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
|
||||
#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
|
||||
#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F
|
||||
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
|
||||
|
||||
#define GL_IMAGE_1D 0x904C
|
||||
#define GL_IMAGE_2D 0x904D
|
||||
#define GL_IMAGE_3D 0x904E
|
||||
#define GL_IMAGE_2D_RECT 0x904F
|
||||
#define GL_IMAGE_CUBE 0x9050
|
||||
#define GL_IMAGE_BUFFER 0x9051
|
||||
#define GL_IMAGE_1D_ARRAY 0x9052
|
||||
#define GL_IMAGE_2D_ARRAY 0x9053
|
||||
#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
|
||||
#define GL_IMAGE_2D_MULTISAMPLE 0x9055
|
||||
#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
|
||||
#define GL_INT_IMAGE_1D 0x9057
|
||||
#define GL_INT_IMAGE_2D 0x9058
|
||||
#define GL_INT_IMAGE_3D 0x9059
|
||||
#define GL_INT_IMAGE_2D_RECT 0x905A
|
||||
#define GL_INT_IMAGE_CUBE 0x905B
|
||||
#define GL_INT_IMAGE_BUFFER 0x905C
|
||||
#define GL_INT_IMAGE_1D_ARRAY 0x905D
|
||||
#define GL_INT_IMAGE_2D_ARRAY 0x905E
|
||||
#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
|
||||
#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
|
||||
#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
|
||||
#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
|
||||
#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
|
||||
#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
|
||||
#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
|
||||
#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
|
||||
#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
|
||||
#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
|
||||
#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
|
||||
#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
|
||||
#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
|
||||
#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
|
||||
|
||||
#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,369 @@
|
|||
/* A Bison parser, made by GNU Bison 3.0.4. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
#ifndef YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED
|
||||
# define YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 1
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int yydebug;
|
||||
#endif
|
||||
|
||||
/* Token type. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
enum yytokentype
|
||||
{
|
||||
ATTRIBUTE = 258,
|
||||
VARYING = 259,
|
||||
CONST = 260,
|
||||
BOOL = 261,
|
||||
FLOAT = 262,
|
||||
DOUBLE = 263,
|
||||
INT = 264,
|
||||
UINT = 265,
|
||||
INT64_T = 266,
|
||||
UINT64_T = 267,
|
||||
BREAK = 268,
|
||||
CONTINUE = 269,
|
||||
DO = 270,
|
||||
ELSE = 271,
|
||||
FOR = 272,
|
||||
IF = 273,
|
||||
DISCARD = 274,
|
||||
RETURN = 275,
|
||||
SWITCH = 276,
|
||||
CASE = 277,
|
||||
DEFAULT = 278,
|
||||
SUBROUTINE = 279,
|
||||
BVEC2 = 280,
|
||||
BVEC3 = 281,
|
||||
BVEC4 = 282,
|
||||
IVEC2 = 283,
|
||||
IVEC3 = 284,
|
||||
IVEC4 = 285,
|
||||
I64VEC2 = 286,
|
||||
I64VEC3 = 287,
|
||||
I64VEC4 = 288,
|
||||
UVEC2 = 289,
|
||||
UVEC3 = 290,
|
||||
UVEC4 = 291,
|
||||
U64VEC2 = 292,
|
||||
U64VEC3 = 293,
|
||||
U64VEC4 = 294,
|
||||
VEC2 = 295,
|
||||
VEC3 = 296,
|
||||
VEC4 = 297,
|
||||
MAT2 = 298,
|
||||
MAT3 = 299,
|
||||
MAT4 = 300,
|
||||
CENTROID = 301,
|
||||
IN = 302,
|
||||
OUT = 303,
|
||||
INOUT = 304,
|
||||
UNIFORM = 305,
|
||||
PATCH = 306,
|
||||
SAMPLE = 307,
|
||||
BUFFER = 308,
|
||||
SHARED = 309,
|
||||
COHERENT = 310,
|
||||
VOLATILE = 311,
|
||||
RESTRICT = 312,
|
||||
READONLY = 313,
|
||||
WRITEONLY = 314,
|
||||
DVEC2 = 315,
|
||||
DVEC3 = 316,
|
||||
DVEC4 = 317,
|
||||
DMAT2 = 318,
|
||||
DMAT3 = 319,
|
||||
DMAT4 = 320,
|
||||
NOPERSPECTIVE = 321,
|
||||
FLAT = 322,
|
||||
SMOOTH = 323,
|
||||
LAYOUT = 324,
|
||||
MAT2X2 = 325,
|
||||
MAT2X3 = 326,
|
||||
MAT2X4 = 327,
|
||||
MAT3X2 = 328,
|
||||
MAT3X3 = 329,
|
||||
MAT3X4 = 330,
|
||||
MAT4X2 = 331,
|
||||
MAT4X3 = 332,
|
||||
MAT4X4 = 333,
|
||||
DMAT2X2 = 334,
|
||||
DMAT2X3 = 335,
|
||||
DMAT2X4 = 336,
|
||||
DMAT3X2 = 337,
|
||||
DMAT3X3 = 338,
|
||||
DMAT3X4 = 339,
|
||||
DMAT4X2 = 340,
|
||||
DMAT4X3 = 341,
|
||||
DMAT4X4 = 342,
|
||||
ATOMIC_UINT = 343,
|
||||
SAMPLER1D = 344,
|
||||
SAMPLER2D = 345,
|
||||
SAMPLER3D = 346,
|
||||
SAMPLERCUBE = 347,
|
||||
SAMPLER1DSHADOW = 348,
|
||||
SAMPLER2DSHADOW = 349,
|
||||
SAMPLERCUBESHADOW = 350,
|
||||
SAMPLER1DARRAY = 351,
|
||||
SAMPLER2DARRAY = 352,
|
||||
SAMPLER1DARRAYSHADOW = 353,
|
||||
SAMPLER2DARRAYSHADOW = 354,
|
||||
ISAMPLER1D = 355,
|
||||
ISAMPLER2D = 356,
|
||||
ISAMPLER3D = 357,
|
||||
ISAMPLERCUBE = 358,
|
||||
ISAMPLER1DARRAY = 359,
|
||||
ISAMPLER2DARRAY = 360,
|
||||
USAMPLER1D = 361,
|
||||
USAMPLER2D = 362,
|
||||
USAMPLER3D = 363,
|
||||
USAMPLERCUBE = 364,
|
||||
USAMPLER1DARRAY = 365,
|
||||
USAMPLER2DARRAY = 366,
|
||||
SAMPLER2DRECT = 367,
|
||||
SAMPLER2DRECTSHADOW = 368,
|
||||
ISAMPLER2DRECT = 369,
|
||||
USAMPLER2DRECT = 370,
|
||||
SAMPLERBUFFER = 371,
|
||||
ISAMPLERBUFFER = 372,
|
||||
USAMPLERBUFFER = 373,
|
||||
SAMPLERCUBEARRAY = 374,
|
||||
SAMPLERCUBEARRAYSHADOW = 375,
|
||||
ISAMPLERCUBEARRAY = 376,
|
||||
USAMPLERCUBEARRAY = 377,
|
||||
SAMPLER2DMS = 378,
|
||||
ISAMPLER2DMS = 379,
|
||||
USAMPLER2DMS = 380,
|
||||
SAMPLER2DMSARRAY = 381,
|
||||
ISAMPLER2DMSARRAY = 382,
|
||||
USAMPLER2DMSARRAY = 383,
|
||||
SAMPLEREXTERNALOES = 384,
|
||||
SAMPLER = 385,
|
||||
SAMPLERSHADOW = 386,
|
||||
TEXTURE1D = 387,
|
||||
TEXTURE2D = 388,
|
||||
TEXTURE3D = 389,
|
||||
TEXTURECUBE = 390,
|
||||
TEXTURE1DARRAY = 391,
|
||||
TEXTURE2DARRAY = 392,
|
||||
ITEXTURE1D = 393,
|
||||
ITEXTURE2D = 394,
|
||||
ITEXTURE3D = 395,
|
||||
ITEXTURECUBE = 396,
|
||||
ITEXTURE1DARRAY = 397,
|
||||
ITEXTURE2DARRAY = 398,
|
||||
UTEXTURE1D = 399,
|
||||
UTEXTURE2D = 400,
|
||||
UTEXTURE3D = 401,
|
||||
UTEXTURECUBE = 402,
|
||||
UTEXTURE1DARRAY = 403,
|
||||
UTEXTURE2DARRAY = 404,
|
||||
TEXTURE2DRECT = 405,
|
||||
ITEXTURE2DRECT = 406,
|
||||
UTEXTURE2DRECT = 407,
|
||||
TEXTUREBUFFER = 408,
|
||||
ITEXTUREBUFFER = 409,
|
||||
UTEXTUREBUFFER = 410,
|
||||
TEXTURECUBEARRAY = 411,
|
||||
ITEXTURECUBEARRAY = 412,
|
||||
UTEXTURECUBEARRAY = 413,
|
||||
TEXTURE2DMS = 414,
|
||||
ITEXTURE2DMS = 415,
|
||||
UTEXTURE2DMS = 416,
|
||||
TEXTURE2DMSARRAY = 417,
|
||||
ITEXTURE2DMSARRAY = 418,
|
||||
UTEXTURE2DMSARRAY = 419,
|
||||
SUBPASSINPUT = 420,
|
||||
SUBPASSINPUTMS = 421,
|
||||
ISUBPASSINPUT = 422,
|
||||
ISUBPASSINPUTMS = 423,
|
||||
USUBPASSINPUT = 424,
|
||||
USUBPASSINPUTMS = 425,
|
||||
IMAGE1D = 426,
|
||||
IIMAGE1D = 427,
|
||||
UIMAGE1D = 428,
|
||||
IMAGE2D = 429,
|
||||
IIMAGE2D = 430,
|
||||
UIMAGE2D = 431,
|
||||
IMAGE3D = 432,
|
||||
IIMAGE3D = 433,
|
||||
UIMAGE3D = 434,
|
||||
IMAGE2DRECT = 435,
|
||||
IIMAGE2DRECT = 436,
|
||||
UIMAGE2DRECT = 437,
|
||||
IMAGECUBE = 438,
|
||||
IIMAGECUBE = 439,
|
||||
UIMAGECUBE = 440,
|
||||
IMAGEBUFFER = 441,
|
||||
IIMAGEBUFFER = 442,
|
||||
UIMAGEBUFFER = 443,
|
||||
IMAGE1DARRAY = 444,
|
||||
IIMAGE1DARRAY = 445,
|
||||
UIMAGE1DARRAY = 446,
|
||||
IMAGE2DARRAY = 447,
|
||||
IIMAGE2DARRAY = 448,
|
||||
UIMAGE2DARRAY = 449,
|
||||
IMAGECUBEARRAY = 450,
|
||||
IIMAGECUBEARRAY = 451,
|
||||
UIMAGECUBEARRAY = 452,
|
||||
IMAGE2DMS = 453,
|
||||
IIMAGE2DMS = 454,
|
||||
UIMAGE2DMS = 455,
|
||||
IMAGE2DMSARRAY = 456,
|
||||
IIMAGE2DMSARRAY = 457,
|
||||
UIMAGE2DMSARRAY = 458,
|
||||
STRUCT = 459,
|
||||
VOID = 460,
|
||||
WHILE = 461,
|
||||
IDENTIFIER = 462,
|
||||
TYPE_NAME = 463,
|
||||
FLOATCONSTANT = 464,
|
||||
DOUBLECONSTANT = 465,
|
||||
INTCONSTANT = 466,
|
||||
UINTCONSTANT = 467,
|
||||
INT64CONSTANT = 468,
|
||||
UINT64CONSTANT = 469,
|
||||
BOOLCONSTANT = 470,
|
||||
LEFT_OP = 471,
|
||||
RIGHT_OP = 472,
|
||||
INC_OP = 473,
|
||||
DEC_OP = 474,
|
||||
LE_OP = 475,
|
||||
GE_OP = 476,
|
||||
EQ_OP = 477,
|
||||
NE_OP = 478,
|
||||
AND_OP = 479,
|
||||
OR_OP = 480,
|
||||
XOR_OP = 481,
|
||||
MUL_ASSIGN = 482,
|
||||
DIV_ASSIGN = 483,
|
||||
ADD_ASSIGN = 484,
|
||||
MOD_ASSIGN = 485,
|
||||
LEFT_ASSIGN = 486,
|
||||
RIGHT_ASSIGN = 487,
|
||||
AND_ASSIGN = 488,
|
||||
XOR_ASSIGN = 489,
|
||||
OR_ASSIGN = 490,
|
||||
SUB_ASSIGN = 491,
|
||||
LEFT_PAREN = 492,
|
||||
RIGHT_PAREN = 493,
|
||||
LEFT_BRACKET = 494,
|
||||
RIGHT_BRACKET = 495,
|
||||
LEFT_BRACE = 496,
|
||||
RIGHT_BRACE = 497,
|
||||
DOT = 498,
|
||||
COMMA = 499,
|
||||
COLON = 500,
|
||||
EQUAL = 501,
|
||||
SEMICOLON = 502,
|
||||
BANG = 503,
|
||||
DASH = 504,
|
||||
TILDE = 505,
|
||||
PLUS = 506,
|
||||
STAR = 507,
|
||||
SLASH = 508,
|
||||
PERCENT = 509,
|
||||
LEFT_ANGLE = 510,
|
||||
RIGHT_ANGLE = 511,
|
||||
VERTICAL_BAR = 512,
|
||||
CARET = 513,
|
||||
AMPERSAND = 514,
|
||||
QUESTION = 515,
|
||||
INVARIANT = 516,
|
||||
PRECISE = 517,
|
||||
HIGH_PRECISION = 518,
|
||||
MEDIUM_PRECISION = 519,
|
||||
LOW_PRECISION = 520,
|
||||
PRECISION = 521,
|
||||
PACKED = 522,
|
||||
RESOURCE = 523,
|
||||
SUPERP = 524
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 66 "MachineIndependent/glslang.y" /* yacc.c:1909 */
|
||||
|
||||
struct {
|
||||
glslang::TSourceLoc loc;
|
||||
union {
|
||||
glslang::TString *string;
|
||||
int i;
|
||||
unsigned int u;
|
||||
long long i64;
|
||||
unsigned long long u64;
|
||||
bool b;
|
||||
double d;
|
||||
};
|
||||
glslang::TSymbol* symbol;
|
||||
} lex;
|
||||
struct {
|
||||
glslang::TSourceLoc loc;
|
||||
glslang::TOperator op;
|
||||
union {
|
||||
TIntermNode* intermNode;
|
||||
glslang::TIntermNodePair nodePair;
|
||||
glslang::TIntermTyped* intermTypedNode;
|
||||
};
|
||||
union {
|
||||
glslang::TPublicType type;
|
||||
glslang::TFunction* function;
|
||||
glslang::TParameter param;
|
||||
glslang::TTypeLoc typeLine;
|
||||
glslang::TTypeList* typeList;
|
||||
glslang::TArraySizes* arraySizes;
|
||||
glslang::TIdentifierList* identifierList;
|
||||
};
|
||||
} interm;
|
||||
|
||||
#line 358 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909 */
|
||||
};
|
||||
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int yyparse (glslang::TParseContext* pParseContext);
|
||||
|
||||
#endif /* !YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED */
|
|
@ -0,0 +1,869 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2012-2016 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "localintermediate.h"
|
||||
#include "../Include/InfoSink.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <float.h>
|
||||
#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__
|
||||
#include <cmath>
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
bool is_positive_infinity(double x) {
|
||||
#ifdef _MSC_VER
|
||||
return _fpclass(x) == _FPCLASS_PINF;
|
||||
#elif defined __ANDROID__ || defined __linux__ || __MINGW32__ || __MINGW64__
|
||||
return std::isinf(x) && (x >= 0);
|
||||
#else
|
||||
return isinf(x) && (x >= 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Two purposes:
|
||||
// 1. Show an example of how to iterate tree. Functions can
|
||||
// also directly call Traverse() on children themselves to
|
||||
// have finer grained control over the process than shown here.
|
||||
// See the last function for how to get started.
|
||||
// 2. Print out a text based description of the tree.
|
||||
//
|
||||
|
||||
//
|
||||
// Use this class to carry along data from node to node in
|
||||
// the traversal
|
||||
//
|
||||
class TOutputTraverser : public TIntermTraverser {
|
||||
public:
|
||||
TOutputTraverser(TInfoSink& i) : infoSink(i) { }
|
||||
|
||||
virtual bool visitBinary(TVisit, TIntermBinary* node);
|
||||
virtual bool visitUnary(TVisit, TIntermUnary* node);
|
||||
virtual bool visitAggregate(TVisit, TIntermAggregate* node);
|
||||
virtual bool visitSelection(TVisit, TIntermSelection* node);
|
||||
virtual void visitConstantUnion(TIntermConstantUnion* node);
|
||||
virtual void visitSymbol(TIntermSymbol* node);
|
||||
virtual bool visitLoop(TVisit, TIntermLoop* node);
|
||||
virtual bool visitBranch(TVisit, TIntermBranch* node);
|
||||
virtual bool visitSwitch(TVisit, TIntermSwitch* node);
|
||||
|
||||
TInfoSink& infoSink;
|
||||
protected:
|
||||
TOutputTraverser(TOutputTraverser&);
|
||||
TOutputTraverser& operator=(TOutputTraverser&);
|
||||
};
|
||||
|
||||
//
|
||||
// Helper functions for printing, not part of traversing.
|
||||
//
|
||||
|
||||
static void OutputTreeText(TInfoSink& infoSink, const TIntermNode* node, const int depth)
|
||||
{
|
||||
int i;
|
||||
|
||||
infoSink.debug << node->getLoc().string << ":";
|
||||
if (node->getLoc().line)
|
||||
infoSink.debug << node->getLoc().line;
|
||||
else
|
||||
infoSink.debug << "? ";
|
||||
|
||||
for (i = 0; i < depth; ++i)
|
||||
infoSink.debug << " ";
|
||||
}
|
||||
|
||||
//
|
||||
// The rest of the file are the traversal functions. The last one
|
||||
// is the one that starts the traversal.
|
||||
//
|
||||
// Return true from interior nodes to have the external traversal
|
||||
// continue on to children. If you process children yourself,
|
||||
// return false.
|
||||
//
|
||||
|
||||
bool TOutputTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
|
||||
{
|
||||
TInfoSink& out = infoSink;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
|
||||
switch (node->getOp()) {
|
||||
case EOpAssign: out.debug << "move second child to first child"; break;
|
||||
case EOpAddAssign: out.debug << "add second child into first child"; break;
|
||||
case EOpSubAssign: out.debug << "subtract second child into first child"; break;
|
||||
case EOpMulAssign: out.debug << "multiply second child into first child"; break;
|
||||
case EOpVectorTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break;
|
||||
case EOpVectorTimesScalarAssign: out.debug << "vector scale second child into first child"; break;
|
||||
case EOpMatrixTimesScalarAssign: out.debug << "matrix scale second child into first child"; break;
|
||||
case EOpMatrixTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break;
|
||||
case EOpDivAssign: out.debug << "divide second child into first child"; break;
|
||||
case EOpModAssign: out.debug << "mod second child into first child"; break;
|
||||
case EOpAndAssign: out.debug << "and second child into first child"; break;
|
||||
case EOpInclusiveOrAssign: out.debug << "or second child into first child"; break;
|
||||
case EOpExclusiveOrAssign: out.debug << "exclusive or second child into first child"; break;
|
||||
case EOpLeftShiftAssign: out.debug << "left shift second child into first child"; break;
|
||||
case EOpRightShiftAssign: out.debug << "right shift second child into first child"; break;
|
||||
|
||||
case EOpIndexDirect: out.debug << "direct index"; break;
|
||||
case EOpIndexIndirect: out.debug << "indirect index"; break;
|
||||
case EOpIndexDirectStruct:
|
||||
out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
|
||||
out.debug << ": direct index for structure"; break;
|
||||
case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
|
||||
|
||||
case EOpAdd: out.debug << "add"; break;
|
||||
case EOpSub: out.debug << "subtract"; break;
|
||||
case EOpMul: out.debug << "component-wise multiply"; break;
|
||||
case EOpDiv: out.debug << "divide"; break;
|
||||
case EOpMod: out.debug << "mod"; break;
|
||||
case EOpRightShift: out.debug << "right-shift"; break;
|
||||
case EOpLeftShift: out.debug << "left-shift"; break;
|
||||
case EOpAnd: out.debug << "bitwise and"; break;
|
||||
case EOpInclusiveOr: out.debug << "inclusive-or"; break;
|
||||
case EOpExclusiveOr: out.debug << "exclusive-or"; break;
|
||||
case EOpEqual: out.debug << "Compare Equal"; break;
|
||||
case EOpNotEqual: out.debug << "Compare Not Equal"; break;
|
||||
case EOpLessThan: out.debug << "Compare Less Than"; break;
|
||||
case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
|
||||
case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break;
|
||||
case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
|
||||
|
||||
case EOpVectorTimesScalar: out.debug << "vector-scale"; break;
|
||||
case EOpVectorTimesMatrix: out.debug << "vector-times-matrix"; break;
|
||||
case EOpMatrixTimesVector: out.debug << "matrix-times-vector"; break;
|
||||
case EOpMatrixTimesScalar: out.debug << "matrix-scale"; break;
|
||||
case EOpMatrixTimesMatrix: out.debug << "matrix-multiply"; break;
|
||||
|
||||
case EOpLogicalOr: out.debug << "logical-or"; break;
|
||||
case EOpLogicalXor: out.debug << "logical-xor"; break;
|
||||
case EOpLogicalAnd: out.debug << "logical-and"; break;
|
||||
default: out.debug << "<unknown op>";
|
||||
}
|
||||
|
||||
out.debug << " (" << node->getCompleteString() << ")";
|
||||
|
||||
out.debug << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
|
||||
{
|
||||
TInfoSink& out = infoSink;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
|
||||
switch (node->getOp()) {
|
||||
case EOpNegative: out.debug << "Negate value"; break;
|
||||
case EOpVectorLogicalNot:
|
||||
case EOpLogicalNot: out.debug << "Negate conditional"; break;
|
||||
case EOpBitwiseNot: out.debug << "Bitwise not"; break;
|
||||
|
||||
case EOpPostIncrement: out.debug << "Post-Increment"; break;
|
||||
case EOpPostDecrement: out.debug << "Post-Decrement"; break;
|
||||
case EOpPreIncrement: out.debug << "Pre-Increment"; break;
|
||||
case EOpPreDecrement: out.debug << "Pre-Decrement"; break;
|
||||
|
||||
case EOpConvIntToBool: out.debug << "Convert int to bool"; break;
|
||||
case EOpConvUintToBool: out.debug << "Convert uint to bool"; break;
|
||||
case EOpConvFloatToBool: out.debug << "Convert float to bool"; break;
|
||||
case EOpConvDoubleToBool: out.debug << "Convert double to bool"; break;
|
||||
case EOpConvInt64ToBool: out.debug << "Convert int64 to bool"; break;
|
||||
case EOpConvUint64ToBool: out.debug << "Convert uint64 to bool"; break;
|
||||
case EOpConvIntToFloat: out.debug << "Convert int to float"; break;
|
||||
case EOpConvUintToFloat: out.debug << "Convert uint to float"; break;
|
||||
case EOpConvDoubleToFloat: out.debug << "Convert double to float"; break;
|
||||
case EOpConvInt64ToFloat: out.debug << "Convert int64 to float"; break;
|
||||
case EOpConvUint64ToFloat: out.debug << "Convert uint64 to float"; break;
|
||||
case EOpConvBoolToFloat: out.debug << "Convert bool to float"; break;
|
||||
case EOpConvUintToInt: out.debug << "Convert uint to int"; break;
|
||||
case EOpConvFloatToInt: out.debug << "Convert float to int"; break;
|
||||
case EOpConvDoubleToInt: out.debug << "Convert double to int"; break;
|
||||
case EOpConvBoolToInt: out.debug << "Convert bool to int"; break;
|
||||
case EOpConvInt64ToInt: out.debug << "Convert int64 to int"; break;
|
||||
case EOpConvUint64ToInt: out.debug << "Convert uint64 to int"; break;
|
||||
case EOpConvIntToUint: out.debug << "Convert int to uint"; break;
|
||||
case EOpConvFloatToUint: out.debug << "Convert float to uint"; break;
|
||||
case EOpConvDoubleToUint: out.debug << "Convert double to uint"; break;
|
||||
case EOpConvBoolToUint: out.debug << "Convert bool to uint"; break;
|
||||
case EOpConvInt64ToUint: out.debug << "Convert int64 to uint"; break;
|
||||
case EOpConvUint64ToUint: out.debug << "Convert uint64 to uint"; break;
|
||||
case EOpConvIntToDouble: out.debug << "Convert int to double"; break;
|
||||
case EOpConvUintToDouble: out.debug << "Convert uint to double"; break;
|
||||
case EOpConvFloatToDouble: out.debug << "Convert float to double"; break;
|
||||
case EOpConvBoolToDouble: out.debug << "Convert bool to double"; break;
|
||||
case EOpConvInt64ToDouble: out.debug << "Convert int64 to double"; break;
|
||||
case EOpConvUint64ToDouble: out.debug << "Convert uint64 to double"; break;
|
||||
case EOpConvBoolToInt64: out.debug << "Convert bool to int64"; break;
|
||||
case EOpConvIntToInt64: out.debug << "Convert int to int64"; break;
|
||||
case EOpConvUintToInt64: out.debug << "Convert uint to int64"; break;
|
||||
case EOpConvFloatToInt64: out.debug << "Convert float to int64"; break;
|
||||
case EOpConvDoubleToInt64: out.debug << "Convert double to int64"; break;
|
||||
case EOpConvUint64ToInt64: out.debug << "Convert uint64 to int64"; break;
|
||||
case EOpConvBoolToUint64: out.debug << "Convert bool to uint64"; break;
|
||||
case EOpConvIntToUint64: out.debug << "Convert int to uint64"; break;
|
||||
case EOpConvUintToUint64: out.debug << "Convert uint to uint64"; break;
|
||||
case EOpConvFloatToUint64: out.debug << "Convert float to uint64"; break;
|
||||
case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
|
||||
case EOpConvInt64ToUint64: out.debug << "Convert uint64 to uint64"; break;
|
||||
|
||||
case EOpRadians: out.debug << "radians"; break;
|
||||
case EOpDegrees: out.debug << "degrees"; break;
|
||||
case EOpSin: out.debug << "sine"; break;
|
||||
case EOpCos: out.debug << "cosine"; break;
|
||||
case EOpTan: out.debug << "tangent"; break;
|
||||
case EOpAsin: out.debug << "arc sine"; break;
|
||||
case EOpAcos: out.debug << "arc cosine"; break;
|
||||
case EOpAtan: out.debug << "arc tangent"; break;
|
||||
case EOpSinh: out.debug << "hyp. sine"; break;
|
||||
case EOpCosh: out.debug << "hyp. cosine"; break;
|
||||
case EOpTanh: out.debug << "hyp. tangent"; break;
|
||||
case EOpAsinh: out.debug << "arc hyp. sine"; break;
|
||||
case EOpAcosh: out.debug << "arc hyp. cosine"; break;
|
||||
case EOpAtanh: out.debug << "arc hyp. tangent"; break;
|
||||
|
||||
case EOpExp: out.debug << "exp"; break;
|
||||
case EOpLog: out.debug << "log"; break;
|
||||
case EOpExp2: out.debug << "exp2"; break;
|
||||
case EOpLog2: out.debug << "log2"; break;
|
||||
case EOpSqrt: out.debug << "sqrt"; break;
|
||||
case EOpInverseSqrt: out.debug << "inverse sqrt"; break;
|
||||
|
||||
case EOpAbs: out.debug << "Absolute value"; break;
|
||||
case EOpSign: out.debug << "Sign"; break;
|
||||
case EOpFloor: out.debug << "Floor"; break;
|
||||
case EOpTrunc: out.debug << "trunc"; break;
|
||||
case EOpRound: out.debug << "round"; break;
|
||||
case EOpRoundEven: out.debug << "roundEven"; break;
|
||||
case EOpCeil: out.debug << "Ceiling"; break;
|
||||
case EOpFract: out.debug << "Fraction"; break;
|
||||
|
||||
case EOpIsNan: out.debug << "isnan"; break;
|
||||
case EOpIsInf: out.debug << "isinf"; break;
|
||||
|
||||
case EOpFloatBitsToInt: out.debug << "floatBitsToInt"; break;
|
||||
case EOpFloatBitsToUint:out.debug << "floatBitsToUint"; break;
|
||||
case EOpIntBitsToFloat: out.debug << "intBitsToFloat"; break;
|
||||
case EOpUintBitsToFloat:out.debug << "uintBitsToFloat"; break;
|
||||
case EOpDoubleBitsToInt64: out.debug << "doubleBitsToInt64"; break;
|
||||
case EOpDoubleBitsToUint64: out.debug << "doubleBitsToUint64"; break;
|
||||
case EOpInt64BitsToDouble: out.debug << "int64BitsToDouble"; break;
|
||||
case EOpUint64BitsToDouble: out.debug << "uint64BitsToDouble"; break;
|
||||
case EOpPackSnorm2x16: out.debug << "packSnorm2x16"; break;
|
||||
case EOpUnpackSnorm2x16:out.debug << "unpackSnorm2x16"; break;
|
||||
case EOpPackUnorm2x16: out.debug << "packUnorm2x16"; break;
|
||||
case EOpUnpackUnorm2x16:out.debug << "unpackUnorm2x16"; break;
|
||||
case EOpPackHalf2x16: out.debug << "packHalf2x16"; break;
|
||||
case EOpUnpackHalf2x16: out.debug << "unpackHalf2x16"; break;
|
||||
|
||||
case EOpPackSnorm4x8: out.debug << "PackSnorm4x8"; break;
|
||||
case EOpUnpackSnorm4x8: out.debug << "UnpackSnorm4x8"; break;
|
||||
case EOpPackUnorm4x8: out.debug << "PackUnorm4x8"; break;
|
||||
case EOpUnpackUnorm4x8: out.debug << "UnpackUnorm4x8"; break;
|
||||
case EOpPackDouble2x32: out.debug << "PackDouble2x32"; break;
|
||||
case EOpUnpackDouble2x32: out.debug << "UnpackDouble2x32"; break;
|
||||
|
||||
case EOpPackInt2x32: out.debug << "packInt2x32"; break;
|
||||
case EOpUnpackInt2x32: out.debug << "unpackInt2x32"; break;
|
||||
case EOpPackUint2x32: out.debug << "packUint2x32"; break;
|
||||
case EOpUnpackUint2x32: out.debug << "unpackUint2x32"; break;
|
||||
|
||||
case EOpLength: out.debug << "length"; break;
|
||||
case EOpNormalize: out.debug << "normalize"; break;
|
||||
case EOpDPdx: out.debug << "dPdx"; break;
|
||||
case EOpDPdy: out.debug << "dPdy"; break;
|
||||
case EOpFwidth: out.debug << "fwidth"; break;
|
||||
case EOpDPdxFine: out.debug << "dPdxFine"; break;
|
||||
case EOpDPdyFine: out.debug << "dPdyFine"; break;
|
||||
case EOpFwidthFine: out.debug << "fwidthFine"; break;
|
||||
case EOpDPdxCoarse: out.debug << "dPdxCoarse"; break;
|
||||
case EOpDPdyCoarse: out.debug << "dPdyCoarse"; break;
|
||||
case EOpFwidthCoarse: out.debug << "fwidthCoarse"; break;
|
||||
|
||||
case EOpInterpolateAtCentroid: out.debug << "interpolateAtCentroid"; break;
|
||||
|
||||
case EOpDeterminant: out.debug << "determinant"; break;
|
||||
case EOpMatrixInverse: out.debug << "inverse"; break;
|
||||
case EOpTranspose: out.debug << "transpose"; break;
|
||||
|
||||
case EOpAny: out.debug << "any"; break;
|
||||
case EOpAll: out.debug << "all"; break;
|
||||
|
||||
case EOpArrayLength: out.debug << "array length"; break;
|
||||
|
||||
case EOpEmitStreamVertex: out.debug << "EmitStreamVertex"; break;
|
||||
case EOpEndStreamPrimitive: out.debug << "EndStreamPrimitive"; break;
|
||||
|
||||
case EOpAtomicCounterIncrement: out.debug << "AtomicCounterIncrement";break;
|
||||
case EOpAtomicCounterDecrement: out.debug << "AtomicCounterDecrement";break;
|
||||
case EOpAtomicCounter: out.debug << "AtomicCounter"; break;
|
||||
|
||||
case EOpTextureQuerySize: out.debug << "textureSize"; break;
|
||||
case EOpTextureQueryLod: out.debug << "textureQueryLod"; break;
|
||||
case EOpTextureQueryLevels: out.debug << "textureQueryLevels"; break;
|
||||
case EOpTextureQuerySamples: out.debug << "textureSamples"; break;
|
||||
case EOpImageQuerySize: out.debug << "imageQuerySize"; break;
|
||||
case EOpImageQuerySamples: out.debug << "imageQuerySamples"; break;
|
||||
case EOpImageLoad: out.debug << "imageLoad"; break;
|
||||
|
||||
case EOpBitFieldReverse: out.debug << "bitFieldReverse"; break;
|
||||
case EOpBitCount: out.debug << "bitCount"; break;
|
||||
case EOpFindLSB: out.debug << "findLSB"; break;
|
||||
case EOpFindMSB: out.debug << "findMSB"; break;
|
||||
|
||||
case EOpNoise: out.debug << "noise"; break;
|
||||
|
||||
case EOpBallot: out.debug << "ballot"; break;
|
||||
case EOpReadFirstInvocation: out.debug << "readFirstInvocation"; break;
|
||||
case EOpAnyInvocation: out.debug << "anyInvocation"; break;
|
||||
case EOpAllInvocations: out.debug << "allInvocations"; break;
|
||||
case EOpAllInvocationsEqual: out.debug << "allInvocationsEqual"; break;
|
||||
|
||||
case EOpClip: out.debug << "clip"; break;
|
||||
case EOpIsFinite: out.debug << "isfinite"; break;
|
||||
case EOpLog10: out.debug << "log10"; break;
|
||||
case EOpRcp: out.debug << "rcp"; break;
|
||||
case EOpSaturate: out.debug << "saturate"; break;
|
||||
|
||||
default: out.debug.message(EPrefixError, "Bad unary op");
|
||||
}
|
||||
|
||||
out.debug << " (" << node->getCompleteString() << ")";
|
||||
|
||||
out.debug << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
|
||||
{
|
||||
TInfoSink& out = infoSink;
|
||||
|
||||
if (node->getOp() == EOpNull) {
|
||||
out.debug.message(EPrefixError, "node is still EOpNull!");
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
|
||||
switch (node->getOp()) {
|
||||
case EOpSequence: out.debug << "Sequence\n"; return true;
|
||||
case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true;
|
||||
case EOpComma: out.debug << "Comma"; break;
|
||||
case EOpFunction: out.debug << "Function Definition: " << node->getName(); break;
|
||||
case EOpFunctionCall: out.debug << "Function Call: " << node->getName(); break;
|
||||
case EOpParameters: out.debug << "Function Parameters: "; break;
|
||||
|
||||
case EOpConstructFloat: out.debug << "Construct float"; break;
|
||||
case EOpConstructDouble:out.debug << "Construct double"; break;
|
||||
case EOpConstructVec2: out.debug << "Construct vec2"; break;
|
||||
case EOpConstructVec3: out.debug << "Construct vec3"; break;
|
||||
case EOpConstructVec4: out.debug << "Construct vec4"; break;
|
||||
case EOpConstructBool: out.debug << "Construct bool"; break;
|
||||
case EOpConstructBVec2: out.debug << "Construct bvec2"; break;
|
||||
case EOpConstructBVec3: out.debug << "Construct bvec3"; break;
|
||||
case EOpConstructBVec4: out.debug << "Construct bvec4"; break;
|
||||
case EOpConstructInt: out.debug << "Construct int"; break;
|
||||
case EOpConstructIVec2: out.debug << "Construct ivec2"; break;
|
||||
case EOpConstructIVec3: out.debug << "Construct ivec3"; break;
|
||||
case EOpConstructIVec4: out.debug << "Construct ivec4"; break;
|
||||
case EOpConstructUint: out.debug << "Construct uint"; break;
|
||||
case EOpConstructUVec2: out.debug << "Construct uvec2"; break;
|
||||
case EOpConstructUVec3: out.debug << "Construct uvec3"; break;
|
||||
case EOpConstructUVec4: out.debug << "Construct uvec4"; break;
|
||||
case EOpConstructInt64: out.debug << "Construct int64_t"; break;
|
||||
case EOpConstructI64Vec2: out.debug << "Construct i64vec2"; break;
|
||||
case EOpConstructI64Vec3: out.debug << "Construct i64vec3"; break;
|
||||
case EOpConstructI64Vec4: out.debug << "Construct i64vec4"; break;
|
||||
case EOpConstructUint64: out.debug << "Construct uint64_t"; break;
|
||||
case EOpConstructU64Vec2: out.debug << "Construct u64vec2"; break;
|
||||
case EOpConstructU64Vec3: out.debug << "Construct u64vec3"; break;
|
||||
case EOpConstructU64Vec4: out.debug << "Construct u64vec4"; break;
|
||||
case EOpConstructMat2x2: out.debug << "Construct mat2"; break;
|
||||
case EOpConstructMat2x3: out.debug << "Construct mat2x3"; break;
|
||||
case EOpConstructMat2x4: out.debug << "Construct mat2x4"; break;
|
||||
case EOpConstructMat3x2: out.debug << "Construct mat3x2"; break;
|
||||
case EOpConstructMat3x3: out.debug << "Construct mat3"; break;
|
||||
case EOpConstructMat3x4: out.debug << "Construct mat3x4"; break;
|
||||
case EOpConstructMat4x2: out.debug << "Construct mat4x2"; break;
|
||||
case EOpConstructMat4x3: out.debug << "Construct mat4x3"; break;
|
||||
case EOpConstructMat4x4: out.debug << "Construct mat4"; break;
|
||||
case EOpConstructDMat2x2: out.debug << "Construct dmat2"; break;
|
||||
case EOpConstructDMat2x3: out.debug << "Construct dmat2x3"; break;
|
||||
case EOpConstructDMat2x4: out.debug << "Construct dmat2x4"; break;
|
||||
case EOpConstructDMat3x2: out.debug << "Construct dmat3x2"; break;
|
||||
case EOpConstructDMat3x3: out.debug << "Construct dmat3"; break;
|
||||
case EOpConstructDMat3x4: out.debug << "Construct dmat3x4"; break;
|
||||
case EOpConstructDMat4x2: out.debug << "Construct dmat4x2"; break;
|
||||
case EOpConstructDMat4x3: out.debug << "Construct dmat4x3"; break;
|
||||
case EOpConstructDMat4x4: out.debug << "Construct dmat4"; break;
|
||||
case EOpConstructStruct: out.debug << "Construct structure"; break;
|
||||
case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
|
||||
|
||||
case EOpLessThan: out.debug << "Compare Less Than"; break;
|
||||
case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
|
||||
case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break;
|
||||
case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break;
|
||||
case EOpVectorEqual: out.debug << "Equal"; break;
|
||||
case EOpVectorNotEqual: out.debug << "NotEqual"; break;
|
||||
|
||||
case EOpMod: out.debug << "mod"; break;
|
||||
case EOpModf: out.debug << "modf"; break;
|
||||
case EOpPow: out.debug << "pow"; break;
|
||||
|
||||
case EOpAtan: out.debug << "arc tangent"; break;
|
||||
|
||||
case EOpMin: out.debug << "min"; break;
|
||||
case EOpMax: out.debug << "max"; break;
|
||||
case EOpClamp: out.debug << "clamp"; break;
|
||||
case EOpMix: out.debug << "mix"; break;
|
||||
case EOpStep: out.debug << "step"; break;
|
||||
case EOpSmoothStep: out.debug << "smoothstep"; break;
|
||||
|
||||
case EOpDistance: out.debug << "distance"; break;
|
||||
case EOpDot: out.debug << "dot-product"; break;
|
||||
case EOpCross: out.debug << "cross-product"; break;
|
||||
case EOpFaceForward: out.debug << "face-forward"; break;
|
||||
case EOpReflect: out.debug << "reflect"; break;
|
||||
case EOpRefract: out.debug << "refract"; break;
|
||||
case EOpMul: out.debug << "component-wise multiply"; break;
|
||||
case EOpOuterProduct: out.debug << "outer product"; break;
|
||||
|
||||
case EOpEmitVertex: out.debug << "EmitVertex"; break;
|
||||
case EOpEndPrimitive: out.debug << "EndPrimitive"; break;
|
||||
|
||||
case EOpBarrier: out.debug << "Barrier"; break;
|
||||
case EOpMemoryBarrier: out.debug << "MemoryBarrier"; break;
|
||||
case EOpMemoryBarrierAtomicCounter: out.debug << "MemoryBarrierAtomicCounter"; break;
|
||||
case EOpMemoryBarrierBuffer: out.debug << "MemoryBarrierBuffer"; break;
|
||||
case EOpMemoryBarrierImage: out.debug << "MemoryBarrierImage"; break;
|
||||
case EOpMemoryBarrierShared: out.debug << "MemoryBarrierShared"; break;
|
||||
case EOpGroupMemoryBarrier: out.debug << "GroupMemoryBarrier"; break;
|
||||
|
||||
case EOpReadInvocation: out.debug << "readInvocation"; break;
|
||||
|
||||
case EOpAtomicAdd: out.debug << "AtomicAdd"; break;
|
||||
case EOpAtomicMin: out.debug << "AtomicMin"; break;
|
||||
case EOpAtomicMax: out.debug << "AtomicMax"; break;
|
||||
case EOpAtomicAnd: out.debug << "AtomicAnd"; break;
|
||||
case EOpAtomicOr: out.debug << "AtomicOr"; break;
|
||||
case EOpAtomicXor: out.debug << "AtomicXor"; break;
|
||||
case EOpAtomicExchange: out.debug << "AtomicExchange"; break;
|
||||
case EOpAtomicCompSwap: out.debug << "AtomicCompSwap"; break;
|
||||
|
||||
case EOpImageQuerySize: out.debug << "imageQuerySize"; break;
|
||||
case EOpImageQuerySamples: out.debug << "imageQuerySamples"; break;
|
||||
case EOpImageLoad: out.debug << "imageLoad"; break;
|
||||
case EOpImageStore: out.debug << "imageStore"; break;
|
||||
case EOpImageAtomicAdd: out.debug << "imageAtomicAdd"; break;
|
||||
case EOpImageAtomicMin: out.debug << "imageAtomicMin"; break;
|
||||
case EOpImageAtomicMax: out.debug << "imageAtomicMax"; break;
|
||||
case EOpImageAtomicAnd: out.debug << "imageAtomicAnd"; break;
|
||||
case EOpImageAtomicOr: out.debug << "imageAtomicOr"; break;
|
||||
case EOpImageAtomicXor: out.debug << "imageAtomicXor"; break;
|
||||
case EOpImageAtomicExchange: out.debug << "imageAtomicExchange"; break;
|
||||
case EOpImageAtomicCompSwap: out.debug << "imageAtomicCompSwap"; break;
|
||||
|
||||
case EOpTextureQuerySize: out.debug << "textureSize"; break;
|
||||
case EOpTextureQueryLod: out.debug << "textureQueryLod"; break;
|
||||
case EOpTextureQueryLevels: out.debug << "textureQueryLevels"; break;
|
||||
case EOpTextureQuerySamples: out.debug << "textureSamples"; break;
|
||||
case EOpTexture: out.debug << "texture"; break;
|
||||
case EOpTextureProj: out.debug << "textureProj"; break;
|
||||
case EOpTextureLod: out.debug << "textureLod"; break;
|
||||
case EOpTextureOffset: out.debug << "textureOffset"; break;
|
||||
case EOpTextureFetch: out.debug << "textureFetch"; break;
|
||||
case EOpTextureFetchOffset: out.debug << "textureFetchOffset"; break;
|
||||
case EOpTextureProjOffset: out.debug << "textureProjOffset"; break;
|
||||
case EOpTextureLodOffset: out.debug << "textureLodOffset"; break;
|
||||
case EOpTextureProjLod: out.debug << "textureProjLod"; break;
|
||||
case EOpTextureProjLodOffset: out.debug << "textureProjLodOffset"; break;
|
||||
case EOpTextureGrad: out.debug << "textureGrad"; break;
|
||||
case EOpTextureGradOffset: out.debug << "textureGradOffset"; break;
|
||||
case EOpTextureProjGrad: out.debug << "textureProjGrad"; break;
|
||||
case EOpTextureProjGradOffset: out.debug << "textureProjGradOffset"; break;
|
||||
case EOpTextureGather: out.debug << "textureGather"; break;
|
||||
case EOpTextureGatherOffset: out.debug << "textureGatherOffset"; break;
|
||||
case EOpTextureGatherOffsets: out.debug << "textureGatherOffsets"; break;
|
||||
|
||||
case EOpAddCarry: out.debug << "addCarry"; break;
|
||||
case EOpSubBorrow: out.debug << "subBorrow"; break;
|
||||
case EOpUMulExtended: out.debug << "uMulExtended"; break;
|
||||
case EOpIMulExtended: out.debug << "iMulExtended"; break;
|
||||
case EOpBitfieldExtract: out.debug << "bitfieldExtract"; break;
|
||||
case EOpBitfieldInsert: out.debug << "bitfieldInsert"; break;
|
||||
|
||||
case EOpFma: out.debug << "fma"; break;
|
||||
case EOpFrexp: out.debug << "frexp"; break;
|
||||
case EOpLdexp: out.debug << "ldexp"; break;
|
||||
|
||||
case EOpInterpolateAtSample: out.debug << "interpolateAtSample"; break;
|
||||
case EOpInterpolateAtOffset: out.debug << "interpolateAtOffset"; break;
|
||||
|
||||
case EOpSinCos: out.debug << "sincos"; break;
|
||||
case EOpGenMul: out.debug << "mul"; break;
|
||||
|
||||
case EOpAllMemoryBarrierWithGroupSync: out.debug << "AllMemoryBarrierWithGroupSync"; break;
|
||||
case EOpGroupMemoryBarrierWithGroupSync: out.debug << "GroupMemoryBarrierWithGroupSync"; break;
|
||||
case EOpWorkgroupMemoryBarrier: out.debug << "WorkgroupMemoryBarrier"; break;
|
||||
case EOpWorkgroupMemoryBarrierWithGroupSync: out.debug << "WorkgroupMemoryBarrierWithGroupSync"; break;
|
||||
|
||||
default: out.debug.message(EPrefixError, "Bad aggregation op");
|
||||
}
|
||||
|
||||
if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
|
||||
out.debug << " (" << node->getCompleteString() << ")";
|
||||
|
||||
out.debug << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node)
|
||||
{
|
||||
TInfoSink& out = infoSink;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
|
||||
out.debug << "Test condition and select";
|
||||
out.debug << " (" << node->getCompleteString() << ")\n";
|
||||
|
||||
++depth;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
out.debug << "Condition\n";
|
||||
node->getCondition()->traverse(this);
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
if (node->getTrueBlock()) {
|
||||
out.debug << "true case\n";
|
||||
node->getTrueBlock()->traverse(this);
|
||||
} else
|
||||
out.debug << "true case is null\n";
|
||||
|
||||
if (node->getFalseBlock()) {
|
||||
OutputTreeText(out, node, depth);
|
||||
out.debug << "false case\n";
|
||||
node->getFalseBlock()->traverse(this);
|
||||
}
|
||||
|
||||
--depth;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void OutputConstantUnion(TInfoSink& out, const TIntermTyped* node, const TConstUnionArray& constUnion, int depth)
|
||||
{
|
||||
int size = node->getType().computeNumComponents();
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
OutputTreeText(out, node, depth);
|
||||
switch (constUnion[i].getType()) {
|
||||
case EbtBool:
|
||||
if (constUnion[i].getBConst())
|
||||
out.debug << "true";
|
||||
else
|
||||
out.debug << "false";
|
||||
|
||||
out.debug << " (" << "const bool" << ")";
|
||||
|
||||
out.debug << "\n";
|
||||
break;
|
||||
case EbtFloat:
|
||||
case EbtDouble:
|
||||
{
|
||||
const double value = constUnion[i].getDConst();
|
||||
// Print infinity in a portable way, for test stability.
|
||||
// Other cases may be needed in the future: negative infinity,
|
||||
// and NaNs.
|
||||
if (is_positive_infinity(value))
|
||||
out.debug << "inf\n";
|
||||
else {
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%f", value);
|
||||
|
||||
out.debug << buf << "\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EbtInt:
|
||||
{
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%d (%s)", constUnion[i].getIConst(), "const int");
|
||||
|
||||
out.debug << buf << "\n";
|
||||
}
|
||||
break;
|
||||
case EbtUint:
|
||||
{
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%u (%s)", constUnion[i].getUConst(), "const uint");
|
||||
|
||||
out.debug << buf << "\n";
|
||||
}
|
||||
break;
|
||||
case EbtInt64:
|
||||
{
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%lld (%s)", constUnion[i].getI64Const(), "const int64_t");
|
||||
|
||||
out.debug << buf << "\n";
|
||||
}
|
||||
break;
|
||||
case EbtUint64:
|
||||
{
|
||||
const int maxSize = 300;
|
||||
char buf[maxSize];
|
||||
snprintf(buf, maxSize, "%llu (%s)", constUnion[i].getU64Const(), "const uint64_t");
|
||||
|
||||
out.debug << buf << "\n";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
out.info.message(EPrefixInternalError, "Unknown constant", node->getLoc());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
|
||||
{
|
||||
OutputTreeText(infoSink, node, depth);
|
||||
infoSink.debug << "Constant:\n";
|
||||
|
||||
OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
|
||||
}
|
||||
|
||||
void TOutputTraverser::visitSymbol(TIntermSymbol* node)
|
||||
{
|
||||
OutputTreeText(infoSink, node, depth);
|
||||
|
||||
infoSink.debug << "'" << node->getName() << "' (" << node->getCompleteString() << ")\n";
|
||||
|
||||
if (! node->getConstArray().empty())
|
||||
OutputConstantUnion(infoSink, node, node->getConstArray(), depth + 1);
|
||||
else if (node->getConstSubtree()) {
|
||||
incrementDepth(node);
|
||||
node->getConstSubtree()->traverse(this);
|
||||
decrementDepth();
|
||||
}
|
||||
}
|
||||
|
||||
bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
|
||||
{
|
||||
TInfoSink& out = infoSink;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
|
||||
out.debug << "Loop with condition ";
|
||||
if (! node->testFirst())
|
||||
out.debug << "not ";
|
||||
out.debug << "tested first\n";
|
||||
|
||||
++depth;
|
||||
|
||||
OutputTreeText(infoSink, node, depth);
|
||||
if (node->getTest()) {
|
||||
out.debug << "Loop Condition\n";
|
||||
node->getTest()->traverse(this);
|
||||
} else
|
||||
out.debug << "No loop condition\n";
|
||||
|
||||
OutputTreeText(infoSink, node, depth);
|
||||
if (node->getBody()) {
|
||||
out.debug << "Loop Body\n";
|
||||
node->getBody()->traverse(this);
|
||||
} else
|
||||
out.debug << "No loop body\n";
|
||||
|
||||
if (node->getTerminal()) {
|
||||
OutputTreeText(infoSink, node, depth);
|
||||
out.debug << "Loop Terminal Expression\n";
|
||||
node->getTerminal()->traverse(this);
|
||||
}
|
||||
|
||||
--depth;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TOutputTraverser::visitBranch(TVisit /* visit*/, TIntermBranch* node)
|
||||
{
|
||||
TInfoSink& out = infoSink;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
|
||||
switch (node->getFlowOp()) {
|
||||
case EOpKill: out.debug << "Branch: Kill"; break;
|
||||
case EOpBreak: out.debug << "Branch: Break"; break;
|
||||
case EOpContinue: out.debug << "Branch: Continue"; break;
|
||||
case EOpReturn: out.debug << "Branch: Return"; break;
|
||||
case EOpCase: out.debug << "case: "; break;
|
||||
case EOpDefault: out.debug << "default: "; break;
|
||||
default: out.debug << "Branch: Unknown Branch"; break;
|
||||
}
|
||||
|
||||
if (node->getExpression()) {
|
||||
out.debug << " with expression\n";
|
||||
++depth;
|
||||
node->getExpression()->traverse(this);
|
||||
--depth;
|
||||
} else
|
||||
out.debug << "\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node)
|
||||
{
|
||||
TInfoSink& out = infoSink;
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
out.debug << "switch\n";
|
||||
|
||||
OutputTreeText(out, node, depth);
|
||||
out.debug << "condition\n";
|
||||
++depth;
|
||||
node->getCondition()->traverse(this);
|
||||
|
||||
--depth;
|
||||
OutputTreeText(out, node, depth);
|
||||
out.debug << "body\n";
|
||||
++depth;
|
||||
node->getBody()->traverse(this);
|
||||
|
||||
--depth;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// This function is the one to call externally to start the traversal.
|
||||
// Individual functions can be initialized to 0 to skip processing of that
|
||||
// type of node. It's children will still be processed.
|
||||
//
|
||||
void TIntermediate::output(TInfoSink& infoSink, bool tree)
|
||||
{
|
||||
infoSink.debug << "Shader version: " << version << "\n";
|
||||
if (requestedExtensions.size() > 0) {
|
||||
for (auto extIt = requestedExtensions.begin(); extIt != requestedExtensions.end(); ++extIt)
|
||||
infoSink.debug << "Requested " << *extIt << "\n";
|
||||
}
|
||||
|
||||
if (xfbMode)
|
||||
infoSink.debug << "in xfb mode\n";
|
||||
|
||||
switch (language) {
|
||||
case EShLangVertex:
|
||||
break;
|
||||
|
||||
case EShLangTessControl:
|
||||
infoSink.debug << "vertices = " << vertices << "\n";
|
||||
break;
|
||||
|
||||
case EShLangTessEvaluation:
|
||||
infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
|
||||
infoSink.debug << "vertex spacing = " << TQualifier::getVertexSpacingString(vertexSpacing) << "\n";
|
||||
infoSink.debug << "triangle order = " << TQualifier::getVertexOrderString(vertexOrder) << "\n";
|
||||
if (pointMode)
|
||||
infoSink.debug << "using point mode\n";
|
||||
break;
|
||||
|
||||
case EShLangGeometry:
|
||||
infoSink.debug << "invocations = " << invocations << "\n";
|
||||
infoSink.debug << "max_vertices = " << vertices << "\n";
|
||||
infoSink.debug << "input primitive = " << TQualifier::getGeometryString(inputPrimitive) << "\n";
|
||||
infoSink.debug << "output primitive = " << TQualifier::getGeometryString(outputPrimitive) << "\n";
|
||||
break;
|
||||
|
||||
case EShLangFragment:
|
||||
if (pixelCenterInteger)
|
||||
infoSink.debug << "gl_FragCoord pixel center is integer\n";
|
||||
if (originUpperLeft)
|
||||
infoSink.debug << "gl_FragCoord origin is upper left\n";
|
||||
if (earlyFragmentTests)
|
||||
infoSink.debug << "using early_fragment_tests\n";
|
||||
if (depthLayout != EldNone)
|
||||
infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n";
|
||||
if (blendEquations != 0) {
|
||||
infoSink.debug << "using";
|
||||
// blendEquations is a mask, decode it
|
||||
for (TBlendEquationShift be = (TBlendEquationShift)0; be < EBlendCount; be = (TBlendEquationShift)(be + 1)) {
|
||||
if (blendEquations & (1 << be))
|
||||
infoSink.debug << " " << TQualifier::getBlendEquationString(be);
|
||||
}
|
||||
infoSink.debug << "\n";
|
||||
}
|
||||
break;
|
||||
|
||||
case EShLangCompute:
|
||||
infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n";
|
||||
{
|
||||
if (localSizeSpecId[0] != TQualifier::layoutNotSet ||
|
||||
localSizeSpecId[1] != TQualifier::layoutNotSet ||
|
||||
localSizeSpecId[2] != TQualifier::layoutNotSet) {
|
||||
infoSink.debug << "local_size ids = (" <<
|
||||
localSizeSpecId[0] << ", " <<
|
||||
localSizeSpecId[1] << ", " <<
|
||||
localSizeSpecId[2] << ")\n";
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (treeRoot == 0 || ! tree)
|
||||
return;
|
||||
|
||||
TOutputTraverser it(infoSink);
|
||||
|
||||
treeRoot->traverse(&it);
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,198 @@
|
|||
//
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// Do sub tree walks for
|
||||
// 1) inductive loop bodies to see if the inductive variable is modified
|
||||
// 2) array-index expressions to see if they are "constant-index-expression"
|
||||
//
|
||||
// These are per Appendix A of ES 2.0:
|
||||
//
|
||||
// "Within the body of the loop, the loop index is not statically assigned to nor is it used as the
|
||||
// argument to a function out or inout parameter."
|
||||
//
|
||||
// "The following are constant-index-expressions:
|
||||
// - Constant expressions
|
||||
// - Loop indices as defined in section 4
|
||||
// - Expressions composed of both of the above"
|
||||
//
|
||||
// N.B.: assuming the last rule excludes function calls
|
||||
//
|
||||
|
||||
#include "ParseHelper.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// The inductive loop-body traverser.
|
||||
//
|
||||
// Just look at things that might modify the loop index.
|
||||
//
|
||||
|
||||
class TInductiveTraverser : public TIntermTraverser {
|
||||
public:
|
||||
TInductiveTraverser(int id, TSymbolTable& st)
|
||||
: loopId(id), symbolTable(st), bad(false) { }
|
||||
|
||||
virtual bool visitBinary(TVisit, TIntermBinary* node);
|
||||
virtual bool visitUnary(TVisit, TIntermUnary* node);
|
||||
virtual bool visitAggregate(TVisit, TIntermAggregate* node);
|
||||
|
||||
int loopId; // unique ID of the symbol that's the loop inductive variable
|
||||
TSymbolTable& symbolTable;
|
||||
bool bad;
|
||||
TSourceLoc badLoc;
|
||||
|
||||
protected:
|
||||
TInductiveTraverser(TInductiveTraverser&);
|
||||
TInductiveTraverser& operator=(TInductiveTraverser&);
|
||||
};
|
||||
|
||||
// check binary operations for those modifying the loop index
|
||||
bool TInductiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
|
||||
{
|
||||
if (node->modifiesState() && node->getLeft()->getAsSymbolNode() &&
|
||||
node->getLeft()->getAsSymbolNode()->getId() == loopId) {
|
||||
bad = true;
|
||||
badLoc = node->getLoc();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// check unary operations for those modifying the loop index
|
||||
bool TInductiveTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node)
|
||||
{
|
||||
if (node->modifiesState() && node->getOperand()->getAsSymbolNode() &&
|
||||
node->getOperand()->getAsSymbolNode()->getId() == loopId) {
|
||||
bad = true;
|
||||
badLoc = node->getLoc();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// check function calls for arguments modifying the loop index
|
||||
bool TInductiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
|
||||
{
|
||||
if (node->getOp() == EOpFunctionCall) {
|
||||
// see if an out or inout argument is the loop index
|
||||
const TIntermSequence& args = node->getSequence();
|
||||
for (int i = 0; i < (int)args.size(); ++i) {
|
||||
if (args[i]->getAsSymbolNode() && args[i]->getAsSymbolNode()->getId() == loopId) {
|
||||
TSymbol* function = symbolTable.find(node->getName());
|
||||
const TType* type = (*function->getAsFunction())[i].type;
|
||||
if (type->getQualifier().storage == EvqOut ||
|
||||
type->getQualifier().storage == EvqInOut) {
|
||||
bad = true;
|
||||
badLoc = node->getLoc();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// External function to call for loop check.
|
||||
//
|
||||
void TParseContext::inductiveLoopBodyCheck(TIntermNode* body, int loopId, TSymbolTable& symbolTable)
|
||||
{
|
||||
TInductiveTraverser it(loopId, symbolTable);
|
||||
|
||||
if (body == nullptr)
|
||||
return;
|
||||
|
||||
body->traverse(&it);
|
||||
|
||||
if (it.bad)
|
||||
error(it.badLoc, "inductive loop index modified", "limitations", "");
|
||||
}
|
||||
|
||||
//
|
||||
// The "constant-index-expression" tranverser.
|
||||
//
|
||||
// Just look at things that can form an index.
|
||||
//
|
||||
|
||||
class TIndexTraverser : public TIntermTraverser {
|
||||
public:
|
||||
TIndexTraverser(const TIdSetType& ids) : inductiveLoopIds(ids), bad(false) { }
|
||||
virtual void visitSymbol(TIntermSymbol* symbol);
|
||||
virtual bool visitAggregate(TVisit, TIntermAggregate* node);
|
||||
const TIdSetType& inductiveLoopIds;
|
||||
bool bad;
|
||||
TSourceLoc badLoc;
|
||||
|
||||
protected:
|
||||
TIndexTraverser(TIndexTraverser&);
|
||||
TIndexTraverser& operator=(TIndexTraverser&);
|
||||
};
|
||||
|
||||
// make sure symbols are inductive-loop indexes
|
||||
void TIndexTraverser::visitSymbol(TIntermSymbol* symbol)
|
||||
{
|
||||
if (inductiveLoopIds.find(symbol->getId()) == inductiveLoopIds.end()) {
|
||||
bad = true;
|
||||
badLoc = symbol->getLoc();
|
||||
}
|
||||
}
|
||||
|
||||
// check for function calls, assuming they are bad; spec. doesn't really say
|
||||
bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
|
||||
{
|
||||
if (node->getOp() == EOpFunctionCall) {
|
||||
bad = true;
|
||||
badLoc = node->getLoc();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// External function to call for loop check.
|
||||
//
|
||||
void TParseContext::constantIndexExpressionCheck(TIntermNode* index)
|
||||
{
|
||||
TIndexTraverser it(inductiveLoopIds);
|
||||
|
||||
index->traverse(&it);
|
||||
|
||||
if (it.bad)
|
||||
error(it.badLoc, "Non-constant-index-expression", "limitations", "");
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,396 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _LOCAL_INTERMEDIATE_INCLUDED_
|
||||
#define _LOCAL_INTERMEDIATE_INCLUDED_
|
||||
|
||||
#include "../Include/intermediate.h"
|
||||
#include "../Public/ShaderLang.h"
|
||||
#include "Versions.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
||||
class TInfoSink;
|
||||
|
||||
namespace glslang {
|
||||
|
||||
struct TVectorFields {
|
||||
int offsets[4];
|
||||
int num;
|
||||
};
|
||||
|
||||
//
|
||||
// Some helper structures for TIntermediate. Their contents are encapsulated
|
||||
// by TIntermediate.
|
||||
//
|
||||
|
||||
// Used for detecting recursion: A "call" is a pair: <caller, callee>.
|
||||
struct TCall {
|
||||
TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { }
|
||||
TString caller;
|
||||
TString callee;
|
||||
bool visited;
|
||||
bool currentPath;
|
||||
bool errorGiven;
|
||||
};
|
||||
|
||||
// A generic 1-D range.
|
||||
struct TRange {
|
||||
TRange(int start, int last) : start(start), last(last) { }
|
||||
bool overlap(const TRange& rhs) const
|
||||
{
|
||||
return last >= rhs.start && start <= rhs.last;
|
||||
}
|
||||
int start;
|
||||
int last;
|
||||
};
|
||||
|
||||
// An IO range is a 3-D rectangle; the set of (location, component, index) triples all lying
|
||||
// within the same location range, component range, and index value. Locations don't alias unless
|
||||
// all other dimensions of their range overlap.
|
||||
struct TIoRange {
|
||||
TIoRange(TRange location, TRange component, TBasicType basicType, int index)
|
||||
: location(location), component(component), basicType(basicType), index(index) { }
|
||||
bool overlap(const TIoRange& rhs) const
|
||||
{
|
||||
return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index;
|
||||
}
|
||||
TRange location;
|
||||
TRange component;
|
||||
TBasicType basicType;
|
||||
int index;
|
||||
};
|
||||
|
||||
// An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying
|
||||
// within the same binding and offset range.
|
||||
struct TOffsetRange {
|
||||
TOffsetRange(TRange binding, TRange offset)
|
||||
: binding(binding), offset(offset) { }
|
||||
bool overlap(const TOffsetRange& rhs) const
|
||||
{
|
||||
return binding.overlap(rhs.binding) && offset.overlap(rhs.offset);
|
||||
}
|
||||
TRange binding;
|
||||
TRange offset;
|
||||
};
|
||||
|
||||
// Things that need to be tracked per xfb buffer.
|
||||
struct TXfbBuffer {
|
||||
TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), containsDouble(false) { }
|
||||
std::vector<TRange> ranges; // byte offsets that have already been assigned
|
||||
unsigned int stride;
|
||||
unsigned int implicitStride;
|
||||
bool containsDouble;
|
||||
};
|
||||
|
||||
class TSymbolTable;
|
||||
class TSymbol;
|
||||
class TVariable;
|
||||
|
||||
//
|
||||
// Set of helper functions to help parse and build the tree.
|
||||
//
|
||||
class TIntermediate {
|
||||
public:
|
||||
explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) :
|
||||
source(EShSourceNone), language(l), profile(p), version(v), treeRoot(0),
|
||||
numMains(0), numErrors(0), numPushConstants(0), recursive(false),
|
||||
invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone),
|
||||
pixelCenterInteger(false), originUpperLeft(false),
|
||||
vertexSpacing(EvsNone), vertexOrder(EvoNone), pointMode(false), earlyFragmentTests(false), depthLayout(EldNone), depthReplacing(false), blendEquations(0),
|
||||
multiStream(false), xfbMode(false)
|
||||
{
|
||||
localSize[0] = 1;
|
||||
localSize[1] = 1;
|
||||
localSize[2] = 1;
|
||||
localSizeSpecId[0] = TQualifier::layoutNotSet;
|
||||
localSizeSpecId[1] = TQualifier::layoutNotSet;
|
||||
localSizeSpecId[2] = TQualifier::layoutNotSet;
|
||||
xfbBuffers.resize(TQualifier::layoutXfbBufferEnd);
|
||||
}
|
||||
void setLimits(const TBuiltInResource& r) { resources = r; }
|
||||
|
||||
bool postProcess(TIntermNode*, EShLanguage);
|
||||
void output(TInfoSink&, bool tree);
|
||||
void removeTree();
|
||||
|
||||
void setSource(EShSource s) { source = s; }
|
||||
EShSource getSource() const { return source; }
|
||||
void setEntryPoint(const char* ep) { entryPoint = ep; }
|
||||
const std::string& getEntryPoint() const { return entryPoint; }
|
||||
void setVersion(int v) { version = v; }
|
||||
int getVersion() const { return version; }
|
||||
void setProfile(EProfile p) { profile = p; }
|
||||
EProfile getProfile() const { return profile; }
|
||||
void setSpv(const SpvVersion& s) { spvVersion = s; }
|
||||
const SpvVersion& getSpv() const { return spvVersion; }
|
||||
EShLanguage getStage() const { return language; }
|
||||
void addRequestedExtension(const char* extension) { requestedExtensions.insert(extension); }
|
||||
const std::set<std::string>& getRequestedExtensions() const { return requestedExtensions; }
|
||||
|
||||
void setTreeRoot(TIntermNode* r) { treeRoot = r; }
|
||||
TIntermNode* getTreeRoot() const { return treeRoot; }
|
||||
void addMainCount() { ++numMains; }
|
||||
int getNumMains() const { return numMains; }
|
||||
int getNumErrors() const { return numErrors; }
|
||||
void addPushConstantCount() { ++numPushConstants; }
|
||||
bool isRecursive() const { return recursive; }
|
||||
|
||||
TIntermSymbol* addSymbol(const TVariable&);
|
||||
TIntermSymbol* addSymbol(const TVariable&, const TSourceLoc&);
|
||||
TIntermSymbol* addSymbol(const TType&, const TSourceLoc&);
|
||||
TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
|
||||
TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
|
||||
TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
|
||||
TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
|
||||
TIntermTyped* addUnaryMath(TOperator, TIntermTyped* child, TSourceLoc);
|
||||
TIntermTyped* addBuiltInFunctionCall(const TSourceLoc& line, TOperator, bool unary, TIntermNode*, const TType& returnType);
|
||||
bool canImplicitlyPromote(TBasicType from, TBasicType to) const;
|
||||
TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
|
||||
TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&);
|
||||
TIntermAggregate* makeAggregate(TIntermNode* node);
|
||||
TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&);
|
||||
TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
|
||||
bool areAllChildConst(TIntermAggregate* aggrNode);
|
||||
TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
|
||||
TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
|
||||
TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
|
||||
TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
|
||||
TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermConstantUnion* addConstantUnion(int, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermConstantUnion* addConstantUnion(unsigned int, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermConstantUnion* addConstantUnion(long long, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermConstantUnion* addConstantUnion(unsigned long long, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermConstantUnion* addConstantUnion(bool, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermConstantUnion* addConstantUnion(double, TBasicType, const TSourceLoc&, bool literal = false) const;
|
||||
TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
|
||||
bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
|
||||
TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
|
||||
TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
|
||||
TIntermBranch* addBranch(TOperator, const TSourceLoc&);
|
||||
TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
|
||||
TIntermTyped* addSwizzle(TVectorFields&, const TSourceLoc&);
|
||||
|
||||
// Constant folding (in Constant.cpp)
|
||||
TIntermTyped* fold(TIntermAggregate* aggrNode);
|
||||
TIntermTyped* foldConstructor(TIntermAggregate* aggrNode);
|
||||
TIntermTyped* foldDereference(TIntermTyped* node, int index, const TSourceLoc&);
|
||||
TIntermTyped* foldSwizzle(TIntermTyped* node, TVectorFields& fields, const TSourceLoc&);
|
||||
|
||||
// Tree ops
|
||||
static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay);
|
||||
|
||||
// Linkage related
|
||||
void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, TSymbolTable&, const TString&);
|
||||
void addSymbolLinkageNode(TIntermAggregate*& linkage, const TSymbol&);
|
||||
|
||||
bool setInvocations(int i)
|
||||
{
|
||||
if (invocations != TQualifier::layoutNotSet)
|
||||
return invocations == i;
|
||||
invocations = i;
|
||||
return true;
|
||||
}
|
||||
int getInvocations() const { return invocations; }
|
||||
bool setVertices(int m)
|
||||
{
|
||||
if (vertices != TQualifier::layoutNotSet)
|
||||
return vertices == m;
|
||||
vertices = m;
|
||||
return true;
|
||||
}
|
||||
int getVertices() const { return vertices; }
|
||||
bool setInputPrimitive(TLayoutGeometry p)
|
||||
{
|
||||
if (inputPrimitive != ElgNone)
|
||||
return inputPrimitive == p;
|
||||
inputPrimitive = p;
|
||||
return true;
|
||||
}
|
||||
TLayoutGeometry getInputPrimitive() const { return inputPrimitive; }
|
||||
bool setVertexSpacing(TVertexSpacing s)
|
||||
{
|
||||
if (vertexSpacing != EvsNone)
|
||||
return vertexSpacing == s;
|
||||
vertexSpacing = s;
|
||||
return true;
|
||||
}
|
||||
TVertexSpacing getVertexSpacing() const { return vertexSpacing; }
|
||||
bool setVertexOrder(TVertexOrder o)
|
||||
{
|
||||
if (vertexOrder != EvoNone)
|
||||
return vertexOrder == o;
|
||||
vertexOrder = o;
|
||||
return true;
|
||||
}
|
||||
TVertexOrder getVertexOrder() const { return vertexOrder; }
|
||||
void setPointMode() { pointMode = true; }
|
||||
bool getPointMode() const { return pointMode; }
|
||||
|
||||
bool setLocalSize(int dim, int size)
|
||||
{
|
||||
if (localSize[dim] > 1)
|
||||
return size == localSize[dim];
|
||||
localSize[dim] = size;
|
||||
return true;
|
||||
}
|
||||
unsigned int getLocalSize(int dim) const { return localSize[dim]; }
|
||||
|
||||
bool setLocalSizeSpecId(int dim, int id)
|
||||
{
|
||||
if (localSizeSpecId[dim] != TQualifier::layoutNotSet)
|
||||
return id == localSizeSpecId[dim];
|
||||
localSizeSpecId[dim] = id;
|
||||
return true;
|
||||
}
|
||||
int getLocalSizeSpecId(int dim) const { return localSizeSpecId[dim]; }
|
||||
|
||||
void setXfbMode() { xfbMode = true; }
|
||||
bool getXfbMode() const { return xfbMode; }
|
||||
void setMultiStream() { multiStream = true; }
|
||||
bool isMultiStream() const { return multiStream; }
|
||||
bool setOutputPrimitive(TLayoutGeometry p)
|
||||
{
|
||||
if (outputPrimitive != ElgNone)
|
||||
return outputPrimitive == p;
|
||||
outputPrimitive = p;
|
||||
return true;
|
||||
}
|
||||
TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; }
|
||||
void setOriginUpperLeft() { originUpperLeft = true; }
|
||||
bool getOriginUpperLeft() const { return originUpperLeft; }
|
||||
void setPixelCenterInteger() { pixelCenterInteger = true; }
|
||||
bool getPixelCenterInteger() const { return pixelCenterInteger; }
|
||||
void setEarlyFragmentTests() { earlyFragmentTests = true; }
|
||||
bool getEarlyFragmentTests() const { return earlyFragmentTests; }
|
||||
bool setDepth(TLayoutDepth d)
|
||||
{
|
||||
if (depthLayout != EldNone)
|
||||
return depthLayout == d;
|
||||
depthLayout = d;
|
||||
return true;
|
||||
}
|
||||
TLayoutDepth getDepth() const { return depthLayout; }
|
||||
void setDepthReplacing() { depthReplacing = true; }
|
||||
bool isDepthReplacing() const { return depthReplacing; }
|
||||
|
||||
void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); }
|
||||
unsigned int getBlendEquations() const { return blendEquations; }
|
||||
|
||||
void addToCallGraph(TInfoSink&, const TString& caller, const TString& callee);
|
||||
void merge(TInfoSink&, TIntermediate&);
|
||||
void finalCheck(TInfoSink&);
|
||||
|
||||
void addIoAccessed(const TString& name) { ioAccessed.insert(name); }
|
||||
bool inIoAccessed(const TString& name) const { return ioAccessed.find(name) != ioAccessed.end(); }
|
||||
|
||||
int addUsedLocation(const TQualifier&, const TType&, bool& typeCollision);
|
||||
int addUsedOffsets(int binding, int offset, int numOffsets);
|
||||
bool addUsedConstantId(int id);
|
||||
int computeTypeLocationSize(const TType&) const;
|
||||
|
||||
bool setXfbBufferStride(int buffer, unsigned stride)
|
||||
{
|
||||
if (xfbBuffers[buffer].stride != TQualifier::layoutXfbStrideEnd)
|
||||
return xfbBuffers[buffer].stride == stride;
|
||||
xfbBuffers[buffer].stride = stride;
|
||||
return true;
|
||||
}
|
||||
int addXfbBufferOffset(const TType&);
|
||||
unsigned int computeTypeXfbSize(const TType&, bool& containsDouble) const;
|
||||
static int getBaseAlignment(const TType&, int& size, int& stride, bool std140, bool rowMajor);
|
||||
|
||||
protected:
|
||||
TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&);
|
||||
void error(TInfoSink& infoSink, const char*);
|
||||
void mergeBodies(TInfoSink&, TIntermSequence& globals, const TIntermSequence& unitGlobals);
|
||||
void mergeLinkerObjects(TInfoSink&, TIntermSequence& linkerObjects, const TIntermSequence& unitLinkerObjects);
|
||||
void mergeImplicitArraySizes(TType&, const TType&);
|
||||
void mergeErrorCheck(TInfoSink&, const TIntermSymbol&, const TIntermSymbol&, bool crossStage);
|
||||
void checkCallGraphCycles(TInfoSink&);
|
||||
void inOutLocationCheck(TInfoSink&);
|
||||
TIntermSequence& findLinkerObjects() const;
|
||||
bool userOutputUsed() const;
|
||||
static int getBaseAlignmentScalar(const TType&, int& size);
|
||||
bool isSpecializationOperation(const TIntermOperator&) const;
|
||||
|
||||
const EShLanguage language; // stage, known at construction time
|
||||
EShSource source; // source language, known a bit later
|
||||
std::string entryPoint;
|
||||
EProfile profile;
|
||||
int version;
|
||||
SpvVersion spvVersion;
|
||||
TIntermNode* treeRoot;
|
||||
std::set<std::string> requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them
|
||||
TBuiltInResource resources;
|
||||
int numMains;
|
||||
int numErrors;
|
||||
int numPushConstants;
|
||||
bool recursive;
|
||||
int invocations;
|
||||
int vertices;
|
||||
TLayoutGeometry inputPrimitive;
|
||||
TLayoutGeometry outputPrimitive;
|
||||
bool pixelCenterInteger;
|
||||
bool originUpperLeft;
|
||||
TVertexSpacing vertexSpacing;
|
||||
TVertexOrder vertexOrder;
|
||||
bool pointMode;
|
||||
int localSize[3];
|
||||
int localSizeSpecId[3];
|
||||
bool earlyFragmentTests;
|
||||
TLayoutDepth depthLayout;
|
||||
bool depthReplacing;
|
||||
int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift
|
||||
bool xfbMode;
|
||||
bool multiStream;
|
||||
|
||||
typedef std::list<TCall> TGraph;
|
||||
TGraph callGraph;
|
||||
|
||||
std::set<TString> ioAccessed; // set of names of statically read/written I/O that might need extra checking
|
||||
std::vector<TIoRange> usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers
|
||||
std::vector<TOffsetRange> usedAtomics; // sets of bindings used by atomic counters
|
||||
std::vector<TXfbBuffer> xfbBuffers; // all the data we need to track per xfb buffer
|
||||
std::unordered_set<int> usedConstantId; // specialization constant ids used
|
||||
|
||||
private:
|
||||
void operator=(TIntermediate&); // prevent assignments
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _LOCAL_INTERMEDIATE_INCLUDED_
|
|
@ -0,0 +1,210 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// Travarse a tree of constants to create a single folded constant.
|
||||
// It should only be used when the whole tree is known to be constant.
|
||||
//
|
||||
|
||||
#include "ParseHelper.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TConstTraverser : public TIntermTraverser {
|
||||
public:
|
||||
TConstTraverser(const TConstUnionArray& cUnion, bool singleConstParam, TOperator constructType, const TType& t)
|
||||
: unionArray(cUnion), type(t),
|
||||
constructorType(constructType), singleConstantParam(singleConstParam), error(false), isMatrix(false),
|
||||
matrixCols(0), matrixRows(0) { index = 0; tOp = EOpNull; }
|
||||
|
||||
virtual void visitConstantUnion(TIntermConstantUnion* node);
|
||||
virtual bool visitAggregate(TVisit, TIntermAggregate* node);
|
||||
|
||||
int index;
|
||||
TConstUnionArray unionArray;
|
||||
TOperator tOp;
|
||||
const TType& type;
|
||||
TOperator constructorType;
|
||||
bool singleConstantParam;
|
||||
bool error;
|
||||
int size; // size of the constructor ( 4 for vec4)
|
||||
bool isMatrix;
|
||||
int matrixCols;
|
||||
int matrixRows;
|
||||
|
||||
protected:
|
||||
TConstTraverser(TConstTraverser&);
|
||||
TConstTraverser& operator=(TConstTraverser&);
|
||||
};
|
||||
|
||||
bool TConstTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
|
||||
{
|
||||
if (! node->isConstructor() && node->getOp() != EOpComma) {
|
||||
error = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node->getSequence().size() == 0) {
|
||||
error = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
|
||||
if (flag) {
|
||||
singleConstantParam = true;
|
||||
constructorType = node->getOp();
|
||||
size = node->getType().computeNumComponents();
|
||||
|
||||
if (node->getType().isMatrix()) {
|
||||
isMatrix = true;
|
||||
matrixCols = node->getType().getMatrixCols();
|
||||
matrixRows = node->getType().getMatrixRows();
|
||||
}
|
||||
}
|
||||
|
||||
for (TIntermSequence::iterator p = node->getSequence().begin();
|
||||
p != node->getSequence().end(); p++) {
|
||||
|
||||
if (node->getOp() == EOpComma)
|
||||
index = 0;
|
||||
|
||||
(*p)->traverse(this);
|
||||
}
|
||||
if (flag)
|
||||
{
|
||||
singleConstantParam = false;
|
||||
constructorType = EOpNull;
|
||||
size = 0;
|
||||
isMatrix = false;
|
||||
matrixCols = 0;
|
||||
matrixRows = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
|
||||
{
|
||||
TConstUnionArray leftUnionArray(unionArray);
|
||||
int instanceSize = type.computeNumComponents();
|
||||
|
||||
if (index >= instanceSize)
|
||||
return;
|
||||
|
||||
if (! singleConstantParam) {
|
||||
int rightUnionSize = node->getType().computeNumComponents();
|
||||
|
||||
const TConstUnionArray& rightUnionArray = node->getConstArray();
|
||||
for (int i = 0; i < rightUnionSize; i++) {
|
||||
if (index >= instanceSize)
|
||||
return;
|
||||
leftUnionArray[index] = rightUnionArray[i];
|
||||
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
int endIndex = index + size;
|
||||
const TConstUnionArray& rightUnionArray = node->getConstArray();
|
||||
if (! isMatrix) {
|
||||
int count = 0;
|
||||
int nodeComps = node->getType().computeNumComponents();
|
||||
for (int i = index; i < endIndex; i++) {
|
||||
if (i >= instanceSize)
|
||||
return;
|
||||
|
||||
leftUnionArray[i] = rightUnionArray[count];
|
||||
|
||||
(index)++;
|
||||
|
||||
if (nodeComps > 1)
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
// constructing a matrix, but from what?
|
||||
if (node->isMatrix()) {
|
||||
// Matrix from a matrix; this has the outer matrix, node is the argument matrix.
|
||||
// Traverse the outer, potentially bigger matrix, fill in missing pieces with the
|
||||
// identity matrix.
|
||||
for (int c = 0; c < matrixCols; ++c) {
|
||||
for (int r = 0; r < matrixRows; ++r) {
|
||||
int targetOffset = index + c * matrixRows + r;
|
||||
if (r < node->getType().getMatrixRows() && c < node->getType().getMatrixCols()) {
|
||||
int srcOffset = c * node->getType().getMatrixRows() + r;
|
||||
leftUnionArray[targetOffset] = rightUnionArray[srcOffset];
|
||||
} else if (r == c)
|
||||
leftUnionArray[targetOffset].setDConst(1.0);
|
||||
else
|
||||
leftUnionArray[targetOffset].setDConst(0.0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// matrix from vector
|
||||
int count = 0;
|
||||
const int startIndex = index;
|
||||
int nodeComps = node->getType().computeNumComponents();
|
||||
for (int i = startIndex; i < endIndex; i++) {
|
||||
if (i >= instanceSize)
|
||||
return;
|
||||
if (i == startIndex || (i - startIndex) % (matrixRows + 1) == 0 )
|
||||
leftUnionArray[i] = rightUnionArray[count];
|
||||
else
|
||||
leftUnionArray[i].setDConst(0.0);
|
||||
|
||||
index++;
|
||||
|
||||
if (nodeComps > 1)
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam)
|
||||
{
|
||||
if (root == 0)
|
||||
return false;
|
||||
|
||||
TConstTraverser it(unionArray, singleConstantParam, constructorType, t);
|
||||
|
||||
root->traverse(&it);
|
||||
if (it.error)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
//Copyright (C) 2016 Google, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
// This is implemented in Versions.cpp
|
||||
|
||||
#ifndef _PARSE_VERSIONS_INCLUDED_
|
||||
#define _PARSE_VERSIONS_INCLUDED_
|
||||
|
||||
#include "../Public/ShaderLang.h"
|
||||
#include "../Include/InfoSink.h"
|
||||
#include "Scan.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Base class for parse helpers.
|
||||
// This just has version-related information and checking.
|
||||
// This class should be sufficient for preprocessing.
|
||||
//
|
||||
class TParseVersions {
|
||||
public:
|
||||
TParseVersions(TIntermediate& interm, int version, EProfile profile,
|
||||
const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink,
|
||||
bool forwardCompatible, EShMessages messages)
|
||||
: infoSink(infoSink), version(version), profile(profile), language(language),
|
||||
spvVersion(spvVersion), forwardCompatible(forwardCompatible),
|
||||
intermediate(interm), messages(messages), numErrors(0), currentScanner(0) { }
|
||||
virtual ~TParseVersions() { }
|
||||
virtual void initializeExtensionBehavior();
|
||||
virtual void requireProfile(const TSourceLoc&, int queryProfiles, const char* featureDesc);
|
||||
virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, int numExtensions, const char* const extensions[], const char* featureDesc);
|
||||
virtual void profileRequires(const TSourceLoc&, int queryProfiles, int minVersion, const char* const extension, const char* featureDesc);
|
||||
virtual void requireStage(const TSourceLoc&, EShLanguageMask, const char* featureDesc);
|
||||
virtual void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc);
|
||||
virtual void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc);
|
||||
virtual void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc);
|
||||
virtual void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
|
||||
virtual void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
|
||||
virtual TExtensionBehavior getExtensionBehavior(const char*);
|
||||
virtual bool extensionTurnedOn(const char* const extension);
|
||||
virtual bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
|
||||
virtual void updateExtensionBehavior(int line, const char* const extension, const char* behavior);
|
||||
virtual void fullIntegerCheck(const TSourceLoc&, const char* op);
|
||||
virtual void doubleCheck(const TSourceLoc&, const char* op);
|
||||
virtual void int64Check(const TSourceLoc&, const char* op, bool builtIn = false);
|
||||
virtual void spvRemoved(const TSourceLoc&, const char* op);
|
||||
virtual void vulkanRemoved(const TSourceLoc&, const char* op);
|
||||
virtual void requireVulkan(const TSourceLoc&, const char* op);
|
||||
virtual void requireSpv(const TSourceLoc&, const char* op);
|
||||
virtual bool checkExtensionsRequested(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
|
||||
virtual void updateExtensionBehavior(const char* const extension, TExtensionBehavior);
|
||||
|
||||
virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...) = 0;
|
||||
virtual void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...) = 0;
|
||||
virtual void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...) = 0;
|
||||
virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken,
|
||||
const char* szExtraInfoFormat, ...) = 0;
|
||||
|
||||
void addError() { ++numErrors; }
|
||||
int getNumErrors() const { return numErrors; }
|
||||
|
||||
void setScanner(TInputScanner* scanner) { currentScanner = scanner; }
|
||||
TInputScanner* getScanner() const { return currentScanner; }
|
||||
const TSourceLoc& getCurrentLoc() const { return currentScanner->getSourceLoc(); }
|
||||
void setCurrentLine(int line) { currentScanner->setLine(line); }
|
||||
void setCurrentColumn(int col) { currentScanner->setColumn(col); }
|
||||
void setCurrentSourceName(const char* name) { currentScanner->setFile(name); }
|
||||
void setCurrentString(int string) { currentScanner->setString(string); }
|
||||
|
||||
void getPreamble(std::string&);
|
||||
bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; }
|
||||
bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; }
|
||||
|
||||
TInfoSink& infoSink;
|
||||
|
||||
// compilation mode
|
||||
int version; // version, updated by #version in the shader
|
||||
EProfile profile; // the declared profile in the shader (core by default)
|
||||
EShLanguage language; // really the stage
|
||||
SpvVersion spvVersion;
|
||||
bool forwardCompatible; // true if errors are to be given for use of deprecated features
|
||||
TIntermediate& intermediate; // helper for making and hooking up pieces of the parse tree
|
||||
|
||||
protected:
|
||||
EShMessages messages; // errors/warnings/rule-sets
|
||||
int numErrors; // number of compile-time errors encountered
|
||||
TInputScanner* currentScanner;
|
||||
|
||||
private:
|
||||
TMap<TString, TExtensionBehavior> extensionBehavior; // for each extension string, what its current behavior is set to
|
||||
explicit TParseVersions(const TParseVersions&);
|
||||
TParseVersions& operator=(const TParseVersions&);
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _PARSE_VERSIONS_INCLUDED_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,192 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
|
||||
//
|
||||
// atom.c
|
||||
//
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "PpContext.h"
|
||||
#include "PpTokens.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace glslang;
|
||||
|
||||
const struct {
|
||||
int val;
|
||||
const char* str;
|
||||
} tokens[] = {
|
||||
{ PpAtomDefine, "define" },
|
||||
{ PpAtomDefined, "defined" },
|
||||
{ PpAtomUndef, "undef" },
|
||||
{ PpAtomIf, "if" },
|
||||
{ PpAtomElif, "elif" },
|
||||
{ PpAtomElse, "else" },
|
||||
{ PpAtomEndif, "endif" },
|
||||
{ PpAtomIfdef, "ifdef" },
|
||||
{ PpAtomIfndef, "ifndef" },
|
||||
{ PpAtomLine, "line" },
|
||||
{ PpAtomPragma, "pragma" },
|
||||
{ PpAtomError, "error" },
|
||||
|
||||
{ PpAtomVersion, "version" },
|
||||
{ PpAtomCore, "core" },
|
||||
{ PpAtomCompatibility, "compatibility" },
|
||||
{ PpAtomEs, "es" },
|
||||
{ PpAtomExtension, "extension" },
|
||||
|
||||
{ PpAtomLineMacro, "__LINE__" },
|
||||
{ PpAtomFileMacro, "__FILE__" },
|
||||
{ PpAtomVersionMacro, "__VERSION__" },
|
||||
|
||||
{ PpAtomInclude, "include" },
|
||||
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Map a new or existing string to an atom, inventing a new atom if necessary.
|
||||
//
|
||||
int TPpContext::LookUpAddString(const char* s)
|
||||
{
|
||||
auto it = atomMap.find(s);
|
||||
if (it == atomMap.end()) {
|
||||
AddAtomFixed(s, nextAtom);
|
||||
return nextAtom++;
|
||||
} else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
//
|
||||
// Map an already created atom to its string.
|
||||
//
|
||||
const char* TPpContext::GetAtomString(int atom)
|
||||
{
|
||||
if ((size_t)atom >= stringMap.size())
|
||||
return "<bad token>";
|
||||
|
||||
const TString* atomString = stringMap[atom];
|
||||
|
||||
return atomString ? atomString->c_str() : "<bad token>";
|
||||
}
|
||||
|
||||
//
|
||||
// Add forced mapping of string to atom.
|
||||
//
|
||||
void TPpContext::AddAtomFixed(const char* s, int atom)
|
||||
{
|
||||
auto it = atomMap.insert(std::pair<TString, int>(s, atom)).first;
|
||||
if (stringMap.size() < (size_t)atom + 1)
|
||||
stringMap.resize(atom + 100, 0);
|
||||
stringMap[atom] = &it->first;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the atom table.
|
||||
//
|
||||
void TPpContext::InitAtomTable()
|
||||
{
|
||||
// Add single character tokens to the atom table:
|
||||
const char* s = "~!%^&*()-+=|,.<>/?;:[]{}#\\";
|
||||
char t[2];
|
||||
|
||||
t[1] = '\0';
|
||||
while (*s) {
|
||||
t[0] = *s;
|
||||
AddAtomFixed(t, s[0]);
|
||||
s++;
|
||||
}
|
||||
|
||||
// Add multiple character scanner tokens :
|
||||
for (size_t ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++)
|
||||
AddAtomFixed(tokens[ii].str, tokens[ii].val);
|
||||
|
||||
nextAtom = PpAtomLast;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,122 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PpContext.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) :
|
||||
preamble(0), strings(0), parseContext(pc), includer(inclr), inComment(false),
|
||||
rootFileName(rootFileName),
|
||||
currentSourceFile(rootFileName)
|
||||
{
|
||||
InitAtomTable();
|
||||
InitScanner();
|
||||
|
||||
ifdepth = 0;
|
||||
for (elsetracker = 0; elsetracker < maxIfNesting; elsetracker++)
|
||||
elseSeen[elsetracker] = false;
|
||||
elsetracker = 0;
|
||||
}
|
||||
|
||||
TPpContext::~TPpContext()
|
||||
{
|
||||
for (TSymbolMap::iterator it = symbols.begin(); it != symbols.end(); ++it)
|
||||
delete it->second->mac.body;
|
||||
mem_FreePool(pool);
|
||||
delete [] preamble;
|
||||
|
||||
// free up the inputStack
|
||||
while (! inputStack.empty())
|
||||
popInput();
|
||||
}
|
||||
|
||||
void TPpContext::setInput(TInputScanner& input, bool versionWillBeError)
|
||||
{
|
||||
assert(inputStack.size() == 0);
|
||||
|
||||
pushInput(new tStringInput(this, input));
|
||||
|
||||
errorOnVersion = versionWillBeError;
|
||||
versionSeen = false;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,572 @@
|
|||
//
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef PPCONTEXT_H
|
||||
#define PPCONTEXT_H
|
||||
|
||||
#include <stack>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../ParseHelper.h"
|
||||
|
||||
/* windows only pragma */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TPpToken {
|
||||
public:
|
||||
TPpToken() : token(0), space(false), ival(0), dval(0.0), atom(0)
|
||||
{
|
||||
loc.init();
|
||||
name[0] = 0;
|
||||
}
|
||||
|
||||
bool operator==(const TPpToken& right)
|
||||
{
|
||||
return token == right.token && atom == right.atom &&
|
||||
ival == right.ival && dval == right.dval &&
|
||||
strcmp(name, right.name) == 0;
|
||||
}
|
||||
bool operator!=(const TPpToken& right) { return ! operator==(right); }
|
||||
|
||||
TSourceLoc loc;
|
||||
int token;
|
||||
bool space; // true if a space (for white space or a removed comment) should also be recognized, in front of the token returned
|
||||
int ival;
|
||||
double dval;
|
||||
long long i64val;
|
||||
int atom;
|
||||
char name[MaxTokenLength + 1];
|
||||
};
|
||||
|
||||
class TInputScanner;
|
||||
|
||||
// This class is the result of turning a huge pile of C code communicating through globals
|
||||
// into a class. This was done to allowing instancing to attain thread safety.
|
||||
// Don't expect too much in terms of OO design.
|
||||
class TPpContext {
|
||||
public:
|
||||
TPpContext(TParseContextBase&, const std::string& rootFileName, TShader::Includer&);
|
||||
virtual ~TPpContext();
|
||||
|
||||
void setPreamble(const char* preamble, size_t length);
|
||||
|
||||
const char* tokenize(TPpToken* ppToken);
|
||||
|
||||
class tInput {
|
||||
public:
|
||||
tInput(TPpContext* p) : done(false), pp(p) { }
|
||||
virtual ~tInput() { }
|
||||
|
||||
virtual int scan(TPpToken*) = 0;
|
||||
virtual int getch() = 0;
|
||||
virtual void ungetch() = 0;
|
||||
|
||||
// Will be called when we start reading tokens from this instance
|
||||
virtual void notifyActivated() {}
|
||||
// Will be called when we do not read tokens from this instance anymore
|
||||
virtual void notifyDeleted() {}
|
||||
protected:
|
||||
bool done;
|
||||
TPpContext* pp;
|
||||
};
|
||||
|
||||
void setInput(TInputScanner& input, bool versionWillBeError);
|
||||
|
||||
void pushInput(tInput* in)
|
||||
{
|
||||
inputStack.push_back(in);
|
||||
in->notifyActivated();
|
||||
}
|
||||
void popInput()
|
||||
{
|
||||
inputStack.back()->notifyDeleted();
|
||||
delete inputStack.back();
|
||||
inputStack.pop_back();
|
||||
}
|
||||
|
||||
struct TokenStream {
|
||||
TokenStream() : current(0) { }
|
||||
TVector<unsigned char> data;
|
||||
size_t current;
|
||||
};
|
||||
|
||||
struct MemoryPool {
|
||||
struct chunk *next;
|
||||
uintptr_t free, end;
|
||||
size_t chunksize;
|
||||
uintptr_t alignmask;
|
||||
};
|
||||
|
||||
//
|
||||
// From Pp.cpp
|
||||
//
|
||||
|
||||
struct MacroSymbol {
|
||||
MacroSymbol() : argc(0), args(0), body(0), busy(0), undef(0) { }
|
||||
int argc;
|
||||
int *args;
|
||||
TokenStream *body;
|
||||
unsigned busy:1;
|
||||
unsigned undef:1;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
int atom;
|
||||
MacroSymbol mac;
|
||||
};
|
||||
|
||||
struct SymbolList {
|
||||
struct SymbolList_Rec *next;
|
||||
Symbol *symb;
|
||||
};
|
||||
|
||||
MemoryPool *pool;
|
||||
typedef TMap<int, Symbol*> TSymbolMap;
|
||||
TSymbolMap symbols; // this has light use... just defined macros
|
||||
|
||||
protected:
|
||||
TPpContext(TPpContext&);
|
||||
TPpContext& operator=(TPpContext&);
|
||||
|
||||
char* preamble; // string to parse, all before line 1 of string 0, it is 0 if no preamble
|
||||
int preambleLength;
|
||||
char** strings; // official strings of shader, starting a string 0 line 1
|
||||
size_t* lengths;
|
||||
int numStrings; // how many official strings there are
|
||||
int currentString; // which string we're currently parsing (-1 for preamble)
|
||||
|
||||
// Scanner data:
|
||||
int previous_token;
|
||||
TParseContextBase& parseContext;
|
||||
|
||||
// Get the next token from *stack* of input sources, popping input sources
|
||||
// that are out of tokens, down until an input sources is found that has a token.
|
||||
// Return EndOfInput when there are no more tokens to be found by doing this.
|
||||
int scanToken(TPpToken* ppToken)
|
||||
{
|
||||
int token = EndOfInput;
|
||||
|
||||
while (! inputStack.empty()) {
|
||||
token = inputStack.back()->scan(ppToken);
|
||||
if (token != EndOfInput)
|
||||
break;
|
||||
popInput();
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
int getChar() { return inputStack.back()->getch(); }
|
||||
void ungetChar() { inputStack.back()->ungetch(); }
|
||||
|
||||
static const int maxMacroArgs = 64;
|
||||
static const int maxIfNesting = 64;
|
||||
|
||||
int ifdepth; // current #if-#else-#endif nesting in the cpp.c file (pre-processor)
|
||||
bool elseSeen[maxIfNesting]; // Keep a track of whether an else has been seen at a particular depth
|
||||
int elsetracker; // #if-#else and #endif constructs...Counter.
|
||||
|
||||
class tMacroInput : public tInput {
|
||||
public:
|
||||
tMacroInput(TPpContext* pp) : tInput(pp) { }
|
||||
virtual ~tMacroInput()
|
||||
{
|
||||
for (size_t i = 0; i < args.size(); ++i)
|
||||
delete args[i];
|
||||
}
|
||||
|
||||
virtual int scan(TPpToken*);
|
||||
virtual int getch() { assert(0); return EndOfInput; }
|
||||
virtual void ungetch() { assert(0); }
|
||||
MacroSymbol *mac;
|
||||
TVector<TokenStream*> args;
|
||||
};
|
||||
|
||||
class tMarkerInput : public tInput {
|
||||
public:
|
||||
tMarkerInput(TPpContext* pp) : tInput(pp) { }
|
||||
virtual int scan(TPpToken*)
|
||||
{
|
||||
if (done)
|
||||
return EndOfInput;
|
||||
done = true;
|
||||
|
||||
return marker;
|
||||
}
|
||||
virtual int getch() { assert(0); return EndOfInput; }
|
||||
virtual void ungetch() { assert(0); }
|
||||
static const int marker = -3;
|
||||
};
|
||||
|
||||
class tZeroInput : public tInput {
|
||||
public:
|
||||
tZeroInput(TPpContext* pp) : tInput(pp) { }
|
||||
virtual int scan(TPpToken*);
|
||||
virtual int getch() { assert(0); return EndOfInput; }
|
||||
virtual void ungetch() { assert(0); }
|
||||
};
|
||||
|
||||
std::vector<tInput*> inputStack;
|
||||
bool errorOnVersion;
|
||||
bool versionSeen;
|
||||
|
||||
//
|
||||
// from Pp.cpp
|
||||
//
|
||||
|
||||
// Used to obtain #include content.
|
||||
TShader::Includer& includer;
|
||||
|
||||
int InitCPP();
|
||||
int CPPdefine(TPpToken * ppToken);
|
||||
int CPPundef(TPpToken * ppToken);
|
||||
int CPPelse(int matchelse, TPpToken * ppToken);
|
||||
int extraTokenCheck(int atom, TPpToken* ppToken, int token);
|
||||
int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken);
|
||||
int evalToToken(int token, bool shortCircuit, int& res, bool& err, TPpToken * ppToken);
|
||||
int CPPif (TPpToken * ppToken);
|
||||
int CPPifdef(int defined, TPpToken * ppToken);
|
||||
int CPPinclude(TPpToken * ppToken);
|
||||
int CPPline(TPpToken * ppToken);
|
||||
int CPPerror(TPpToken * ppToken);
|
||||
int CPPpragma(TPpToken * ppToken);
|
||||
int CPPversion(TPpToken * ppToken);
|
||||
int CPPextension(TPpToken * ppToken);
|
||||
int readCPPline(TPpToken * ppToken);
|
||||
TokenStream* PrescanMacroArg(TokenStream *a, TPpToken * ppToken, bool newLineOkay);
|
||||
int MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool newLineOkay);
|
||||
|
||||
//
|
||||
// from PpSymbols.cpp
|
||||
//
|
||||
Symbol *NewSymbol(int name);
|
||||
Symbol *AddSymbol(int atom);
|
||||
Symbol *LookUpSymbol(int atom);
|
||||
|
||||
//
|
||||
// From PpTokens.cpp
|
||||
//
|
||||
void lAddByte(TokenStream *fTok, unsigned char fVal);
|
||||
int lReadByte(TokenStream *pTok);
|
||||
void lUnreadByte(TokenStream *pTok);
|
||||
void RecordToken(TokenStream* pTok, int token, TPpToken* ppToken);
|
||||
void RewindTokenStream(TokenStream *pTok);
|
||||
int ReadToken(TokenStream* pTok, TPpToken* ppToken);
|
||||
void pushTokenStreamInput(TokenStream *ts);
|
||||
void UngetToken(int token, TPpToken* ppToken);
|
||||
|
||||
class tTokenInput : public tInput {
|
||||
public:
|
||||
tTokenInput(TPpContext* pp, TokenStream* t) : tInput(pp), tokens(t) { }
|
||||
virtual int scan(TPpToken *);
|
||||
virtual int getch() { assert(0); return EndOfInput; }
|
||||
virtual void ungetch() { assert(0); }
|
||||
protected:
|
||||
TokenStream *tokens;
|
||||
};
|
||||
|
||||
class tUngotTokenInput : public tInput {
|
||||
public:
|
||||
tUngotTokenInput(TPpContext* pp, int t, TPpToken* p) : tInput(pp), token(t), lval(*p) { }
|
||||
virtual int scan(TPpToken *);
|
||||
virtual int getch() { assert(0); return EndOfInput; }
|
||||
virtual void ungetch() { assert(0); }
|
||||
protected:
|
||||
int token;
|
||||
TPpToken lval;
|
||||
};
|
||||
|
||||
//
|
||||
// From PpScanner.cpp
|
||||
//
|
||||
class tStringInput : public tInput {
|
||||
public:
|
||||
tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { }
|
||||
virtual int scan(TPpToken*);
|
||||
|
||||
// Scanner used to get source stream characters.
|
||||
// - Escaped newlines are handled here, invisibly to the caller.
|
||||
// - All forms of newline are handled, and turned into just a '\n'.
|
||||
int getch()
|
||||
{
|
||||
int ch = input->get();
|
||||
|
||||
if (ch == '\\') {
|
||||
// Move past escaped newlines, as many as sequentially exist
|
||||
do {
|
||||
if (input->peek() == '\r' || input->peek() == '\n') {
|
||||
bool allowed = pp->parseContext.lineContinuationCheck(input->getSourceLoc(), pp->inComment);
|
||||
if (! allowed && pp->inComment)
|
||||
return '\\';
|
||||
|
||||
// escape one newline now
|
||||
ch = input->get();
|
||||
int nextch = input->get();
|
||||
if (ch == '\r' && nextch == '\n')
|
||||
ch = input->get();
|
||||
else
|
||||
ch = nextch;
|
||||
} else
|
||||
return '\\';
|
||||
} while (ch == '\\');
|
||||
}
|
||||
|
||||
// handle any non-escaped newline
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
if (ch == '\r' && input->peek() == '\n')
|
||||
input->get();
|
||||
return '\n';
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
// Scanner used to backup the source stream characters. Newlines are
|
||||
// handled here, invisibly to the caller, meaning have to undo exactly
|
||||
// what getch() above does (e.g., don't leave things in the middle of a
|
||||
// sequence of escaped newlines).
|
||||
void ungetch()
|
||||
{
|
||||
input->unget();
|
||||
|
||||
do {
|
||||
int ch = input->peek();
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
if (ch == '\n') {
|
||||
// correct for two-character newline
|
||||
input->unget();
|
||||
if (input->peek() != '\r')
|
||||
input->get();
|
||||
}
|
||||
// now in front of a complete newline, move past an escape character
|
||||
input->unget();
|
||||
if (input->peek() == '\\')
|
||||
input->unget();
|
||||
else {
|
||||
input->get();
|
||||
break;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
TInputScanner* input;
|
||||
};
|
||||
|
||||
// Holds a reference to included file data, as well as a
|
||||
// prologue and an epilogue string. This can be scanned using the tInput
|
||||
// interface and acts as a single source string.
|
||||
class TokenizableIncludeFile : public tInput {
|
||||
public:
|
||||
// Copies prologue and epilogue. The includedFile must remain valid
|
||||
// until this TokenizableIncludeFile is no longer used.
|
||||
TokenizableIncludeFile(const TSourceLoc& startLoc,
|
||||
const std::string& prologue,
|
||||
TShader::Includer::IncludeResult* includedFile,
|
||||
const std::string& epilogue,
|
||||
TPpContext* pp)
|
||||
: tInput(pp),
|
||||
prologue_(prologue),
|
||||
includedFile_(includedFile),
|
||||
epilogue_(epilogue),
|
||||
scanner(3, strings, lengths, names, 0, 0, true),
|
||||
prevScanner(nullptr),
|
||||
stringInput(pp, scanner)
|
||||
{
|
||||
strings[0] = prologue_.data();
|
||||
strings[1] = includedFile_->file_data;
|
||||
strings[2] = epilogue_.data();
|
||||
|
||||
lengths[0] = prologue_.size();
|
||||
lengths[1] = includedFile_->file_length;
|
||||
lengths[2] = epilogue_.size();
|
||||
|
||||
scanner.setLine(startLoc.line);
|
||||
scanner.setString(startLoc.string);
|
||||
|
||||
scanner.setFile(startLoc.name, 0);
|
||||
scanner.setFile(startLoc.name, 1);
|
||||
scanner.setFile(startLoc.name, 2);
|
||||
}
|
||||
|
||||
// tInput methods:
|
||||
int scan(TPpToken* t) override { return stringInput.scan(t); }
|
||||
int getch() override { return stringInput.getch(); }
|
||||
void ungetch() override { stringInput.ungetch(); }
|
||||
|
||||
void notifyActivated() override
|
||||
{
|
||||
prevScanner = pp->parseContext.getScanner();
|
||||
pp->parseContext.setScanner(&scanner);
|
||||
pp->push_include(includedFile_);
|
||||
}
|
||||
|
||||
void notifyDeleted() override
|
||||
{
|
||||
pp->parseContext.setScanner(prevScanner);
|
||||
pp->pop_include();
|
||||
}
|
||||
|
||||
private:
|
||||
TokenizableIncludeFile& operator=(const TokenizableIncludeFile&);
|
||||
|
||||
// Stores the prologue for this string.
|
||||
const std::string prologue_;
|
||||
|
||||
// Stores the epilogue for this string.
|
||||
const std::string epilogue_;
|
||||
|
||||
// Points to the IncludeResult that this TokenizableIncludeFile represents.
|
||||
TShader::Includer::IncludeResult* includedFile_;
|
||||
|
||||
// Will point to prologue_, includedFile_->file_data and epilogue_
|
||||
// This is passed to scanner constructor.
|
||||
// These do not own the storage and it must remain valid until this
|
||||
// object has been destroyed.
|
||||
const char* strings[3];
|
||||
// Length of str_, passed to scanner constructor.
|
||||
size_t lengths[3];
|
||||
// String names
|
||||
const char* names[3];
|
||||
// Scans over str_.
|
||||
TInputScanner scanner;
|
||||
// The previous effective scanner before the scanner in this instance
|
||||
// has been activated.
|
||||
TInputScanner* prevScanner;
|
||||
// Delegate object implementing the tInput interface.
|
||||
tStringInput stringInput;
|
||||
};
|
||||
|
||||
int InitScanner();
|
||||
int ScanFromString(char* s);
|
||||
void missingEndifCheck();
|
||||
int lFloatConst(int len, int ch, TPpToken* ppToken);
|
||||
|
||||
void push_include(TShader::Includer::IncludeResult* result)
|
||||
{
|
||||
currentSourceFile = result->file_name;
|
||||
includeStack.push(result);
|
||||
}
|
||||
|
||||
void pop_include()
|
||||
{
|
||||
TShader::Includer::IncludeResult* include = includeStack.top();
|
||||
includeStack.pop();
|
||||
includer.releaseInclude(include);
|
||||
if (includeStack.empty()) {
|
||||
currentSourceFile = rootFileName;
|
||||
} else {
|
||||
currentSourceFile = includeStack.top()->file_name;
|
||||
}
|
||||
}
|
||||
|
||||
bool inComment;
|
||||
|
||||
//
|
||||
// From PpAtom.cpp
|
||||
//
|
||||
typedef TUnorderedMap<TString, int> TAtomMap;
|
||||
typedef TVector<const TString*> TStringMap;
|
||||
|
||||
TAtomMap atomMap;
|
||||
TStringMap stringMap;
|
||||
std::stack<TShader::Includer::IncludeResult*> includeStack;
|
||||
std::string currentSourceFile;
|
||||
std::string rootFileName;
|
||||
int nextAtom;
|
||||
void InitAtomTable();
|
||||
void AddAtomFixed(const char* s, int atom);
|
||||
int LookUpAddString(const char* s);
|
||||
const char* GetAtomString(int atom);
|
||||
|
||||
//
|
||||
// From PpMemory.cpp
|
||||
//
|
||||
MemoryPool *mem_CreatePool(size_t chunksize, unsigned align);
|
||||
void mem_FreePool(MemoryPool*);
|
||||
void *mem_Alloc(MemoryPool* p, size_t size);
|
||||
int mem_AddCleanup(MemoryPool* p, void (*fn)(void *, void*), void* arg1, void* arg2);
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // PPCONTEXT_H
|
|
@ -0,0 +1,162 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "PpContext.h"
|
||||
|
||||
// default alignment and chunksize, if called with 0 arguments
|
||||
#define CHUNKSIZE (64*1024)
|
||||
#define ALIGN 8
|
||||
|
||||
namespace glslang {
|
||||
|
||||
struct chunk {
|
||||
struct chunk *next;
|
||||
};
|
||||
|
||||
TPpContext::MemoryPool* TPpContext::mem_CreatePool(size_t chunksize, unsigned int align)
|
||||
{
|
||||
if (align == 0)
|
||||
align = ALIGN;
|
||||
if (chunksize == 0)
|
||||
chunksize = CHUNKSIZE;
|
||||
if (align & (align - 1))
|
||||
return nullptr;
|
||||
if (chunksize < sizeof(MemoryPool))
|
||||
return nullptr;
|
||||
if (chunksize & (align - 1))
|
||||
return nullptr;
|
||||
|
||||
MemoryPool *pool = (MemoryPool*)malloc(chunksize);
|
||||
if (! pool)
|
||||
return nullptr;
|
||||
|
||||
pool->next = 0;
|
||||
pool->chunksize = chunksize;
|
||||
pool->alignmask = (uintptr_t)(align) - 1;
|
||||
pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask;
|
||||
pool->end = (uintptr_t)pool + chunksize;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
void TPpContext::mem_FreePool(MemoryPool *pool)
|
||||
{
|
||||
struct chunk *p, *next;
|
||||
|
||||
for (p = (struct chunk *)pool; p; p = next) {
|
||||
next = p->next;
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
void* TPpContext::mem_Alloc(MemoryPool *pool, size_t size)
|
||||
{
|
||||
struct chunk *ch;
|
||||
void *rv = (void *)pool->free;
|
||||
size = (size + pool->alignmask) & ~pool->alignmask;
|
||||
if (size <= 0) size = pool->alignmask;
|
||||
pool->free += size;
|
||||
if (pool->free > pool->end || pool->free < (uintptr_t)rv) {
|
||||
size_t minreq = (size + sizeof(struct chunk) + pool->alignmask) & ~pool->alignmask;
|
||||
pool->free = (uintptr_t)rv;
|
||||
if (minreq >= pool->chunksize) {
|
||||
// request size is too big for the chunksize, so allocate it as
|
||||
// a single chunk of the right size
|
||||
ch = (struct chunk*)malloc(minreq);
|
||||
if (! ch)
|
||||
return nullptr;
|
||||
} else {
|
||||
ch = (struct chunk*)malloc(pool->chunksize);
|
||||
if (! ch)
|
||||
return nullptr;
|
||||
pool->free = (uintptr_t)ch + minreq;
|
||||
pool->end = (uintptr_t)ch + pool->chunksize;
|
||||
}
|
||||
ch->next = pool->next;
|
||||
pool->next = ch;
|
||||
rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,778 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
//
|
||||
// scanner.c
|
||||
//
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "PpContext.h"
|
||||
#include "PpTokens.h"
|
||||
#include "../Scan.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
int TPpContext::InitScanner()
|
||||
{
|
||||
// Add various atoms needed by the CPP line scanner:
|
||||
if (!InitCPP())
|
||||
return 0;
|
||||
|
||||
previous_token = '\n';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////// Floating point constants: /////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* lFloatConst() - Scan a single- or double-precision floating point constant. Assumes that the scanner
|
||||
* has seen at least one digit, followed by either a decimal '.' or the
|
||||
* letter 'e', or a precision ending (e.g., F or LF).
|
||||
*/
|
||||
|
||||
int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
|
||||
{
|
||||
bool HasDecimalOrExponent = false;
|
||||
int declen;
|
||||
int str_len;
|
||||
int isDouble = 0;
|
||||
|
||||
declen = 0;
|
||||
|
||||
str_len=len;
|
||||
char* str = ppToken->name;
|
||||
if (ch == '.') {
|
||||
HasDecimalOrExponent = true;
|
||||
str[len++] = (char)ch;
|
||||
ch = getChar();
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
if (len < MaxTokenLength) {
|
||||
declen++;
|
||||
if (len > 0 || ch != '0') {
|
||||
str[len] = (char)ch;
|
||||
len++;
|
||||
str_len++;
|
||||
}
|
||||
ch = getChar();
|
||||
} else {
|
||||
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
|
||||
len = 1;
|
||||
str_len = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exponent:
|
||||
|
||||
if (ch == 'e' || ch == 'E') {
|
||||
HasDecimalOrExponent = true;
|
||||
if (len >= MaxTokenLength) {
|
||||
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
|
||||
len = 1;
|
||||
str_len = 1;
|
||||
} else {
|
||||
str[len++] = (char)ch;
|
||||
ch = getChar();
|
||||
if (ch == '+') {
|
||||
str[len++] = (char)ch;
|
||||
ch = getChar();
|
||||
} else if (ch == '-') {
|
||||
str[len++] = (char)ch;
|
||||
ch = getChar();
|
||||
}
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
if (len < MaxTokenLength) {
|
||||
str[len++] = (char)ch;
|
||||
ch = getChar();
|
||||
} else {
|
||||
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
|
||||
len = 1;
|
||||
str_len = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
ppToken->dval = 0.0;
|
||||
strcpy(str, "0.0");
|
||||
} else {
|
||||
if (ch == 'l' || ch == 'L') {
|
||||
parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
|
||||
if (! HasDecimalOrExponent)
|
||||
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
|
||||
int ch2 = getChar();
|
||||
if (ch2 != 'f' && ch2 != 'F') {
|
||||
ungetChar();
|
||||
ungetChar();
|
||||
} else {
|
||||
if (len < MaxTokenLength) {
|
||||
str[len++] = (char)ch;
|
||||
str[len++] = (char)ch2;
|
||||
isDouble = 1;
|
||||
} else {
|
||||
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
|
||||
len = 1,str_len=1;
|
||||
}
|
||||
}
|
||||
} else if (ch == 'f' || ch == 'F') {
|
||||
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
|
||||
if (! parseContext.relaxedErrors())
|
||||
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
|
||||
if (! HasDecimalOrExponent)
|
||||
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
|
||||
if (len < MaxTokenLength)
|
||||
str[len++] = (char)ch;
|
||||
else {
|
||||
parseContext.ppError(ppToken->loc, "float literal too long", "", "");
|
||||
len = 1,str_len=1;
|
||||
}
|
||||
} else
|
||||
ungetChar();
|
||||
|
||||
str[len]='\0';
|
||||
|
||||
ppToken->dval = strtod(str, nullptr);
|
||||
}
|
||||
|
||||
if (isDouble)
|
||||
return PpAtomConstDouble;
|
||||
else
|
||||
return PpAtomConstFloat;
|
||||
}
|
||||
|
||||
//
|
||||
// Scanner used to tokenize source stream.
|
||||
//
|
||||
int TPpContext::tStringInput::scan(TPpToken* ppToken)
|
||||
{
|
||||
char* tokenText = ppToken->name;
|
||||
int AlreadyComplained = 0;
|
||||
int len = 0;
|
||||
int ch = 0;
|
||||
int ii = 0;
|
||||
unsigned long long ival = 0;
|
||||
bool enableInt64 = pp->parseContext.version >= 450 && pp->parseContext.extensionTurnedOn(E_GL_ARB_gpu_shader_int64);
|
||||
|
||||
ppToken->ival = 0;
|
||||
ppToken->i64val = 0;
|
||||
ppToken->space = false;
|
||||
ch = getch();
|
||||
for (;;) {
|
||||
while (ch == ' ' || ch == '\t') {
|
||||
ppToken->space = true;
|
||||
ch = getch();
|
||||
}
|
||||
|
||||
ppToken->loc = pp->parseContext.getCurrentLoc();
|
||||
len = 0;
|
||||
switch (ch) {
|
||||
default:
|
||||
// Single character token, including EndOfInput, '#' and '\' (escaped newlines are handled at a lower level, so this is just a '\' token)
|
||||
return ch;
|
||||
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E':
|
||||
case 'F': case 'G': case 'H': case 'I': case 'J':
|
||||
case 'K': case 'L': case 'M': case 'N': case 'O':
|
||||
case 'P': case 'Q': case 'R': case 'S': case 'T':
|
||||
case 'U': case 'V': case 'W': case 'X': case 'Y':
|
||||
case 'Z': case '_':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e':
|
||||
case 'f': case 'g': case 'h': case 'i': case 'j':
|
||||
case 'k': case 'l': case 'm': case 'n': case 'o':
|
||||
case 'p': case 'q': case 'r': case 's': case 't':
|
||||
case 'u': case 'v': case 'w': case 'x': case 'y':
|
||||
case 'z':
|
||||
do {
|
||||
if (len < MaxTokenLength) {
|
||||
tokenText[len++] = (char)ch;
|
||||
ch = getch();
|
||||
} else {
|
||||
if (! AlreadyComplained) {
|
||||
pp->parseContext.ppError(ppToken->loc, "name too long", "", "");
|
||||
AlreadyComplained = 1;
|
||||
}
|
||||
ch = getch();
|
||||
}
|
||||
} while ((ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') ||
|
||||
ch == '_');
|
||||
|
||||
// line continuation with no token before or after makes len == 0, and need to start over skipping white space, etc.
|
||||
if (len == 0)
|
||||
continue;
|
||||
|
||||
tokenText[len] = '\0';
|
||||
ungetch();
|
||||
ppToken->atom = pp->LookUpAddString(tokenText);
|
||||
return PpAtomIdentifier;
|
||||
case '0':
|
||||
ppToken->name[len++] = (char)ch;
|
||||
ch = getch();
|
||||
if (ch == 'x' || ch == 'X') {
|
||||
// must be hexidecimal
|
||||
|
||||
bool isUnsigned = false;
|
||||
bool isInt64 = false;
|
||||
ppToken->name[len++] = (char)ch;
|
||||
ch = getch();
|
||||
if ((ch >= '0' && ch <= '9') ||
|
||||
(ch >= 'A' && ch <= 'F') ||
|
||||
(ch >= 'a' && ch <= 'f')) {
|
||||
|
||||
ival = 0;
|
||||
do {
|
||||
if (ival <= 0x0fffffff || (enableInt64 && ival <= 0x0fffffffffffffffull)) {
|
||||
ppToken->name[len++] = (char)ch;
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
ii = ch - '0';
|
||||
} else if (ch >= 'A' && ch <= 'F') {
|
||||
ii = ch - 'A' + 10;
|
||||
} else if (ch >= 'a' && ch <= 'f') {
|
||||
ii = ch - 'a' + 10;
|
||||
} else
|
||||
pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
|
||||
ival = (ival << 4) | ii;
|
||||
} else {
|
||||
if (! AlreadyComplained) {
|
||||
pp->parseContext.ppError(ppToken->loc, "hexidecimal literal too big", "", "");
|
||||
AlreadyComplained = 1;
|
||||
}
|
||||
ival = 0xffffffffffffffffull;
|
||||
}
|
||||
ch = getch();
|
||||
} while ((ch >= '0' && ch <= '9') ||
|
||||
(ch >= 'A' && ch <= 'F') ||
|
||||
(ch >= 'a' && ch <= 'f'));
|
||||
} else {
|
||||
pp->parseContext.ppError(ppToken->loc, "bad digit in hexidecimal literal", "", "");
|
||||
}
|
||||
if (ch == 'u' || ch == 'U') {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
isUnsigned = true;
|
||||
|
||||
if (enableInt64) {
|
||||
int nextCh = getch();
|
||||
if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)nextCh;
|
||||
isInt64 = true;
|
||||
} else
|
||||
ungetch();
|
||||
}
|
||||
}
|
||||
else if (enableInt64 && (ch == 'l' || ch == 'L')) {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
isInt64 = true;
|
||||
} else
|
||||
ungetch();
|
||||
ppToken->name[len] = '\0';
|
||||
|
||||
if (isInt64) {
|
||||
ppToken->i64val = ival;
|
||||
return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
|
||||
} else {
|
||||
ppToken->ival = (int)ival;
|
||||
return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
|
||||
}
|
||||
} else {
|
||||
// could be octal integer or floating point, speculative pursue octal until it must be floating point
|
||||
|
||||
bool isUnsigned = false;
|
||||
bool isInt64 = false;
|
||||
bool octalOverflow = false;
|
||||
bool nonOctal = false;
|
||||
ival = 0;
|
||||
|
||||
// see how much octal-like stuff we can read
|
||||
while (ch >= '0' && ch <= '7') {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
else if (! AlreadyComplained) {
|
||||
pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
|
||||
AlreadyComplained = 1;
|
||||
}
|
||||
if (ival <= 0x1fffffff || (enableInt64 && ival <= 0x1fffffffffffffffull)) {
|
||||
ii = ch - '0';
|
||||
ival = (ival << 3) | ii;
|
||||
} else
|
||||
octalOverflow = true;
|
||||
ch = getch();
|
||||
}
|
||||
|
||||
// could be part of a float...
|
||||
if (ch == '8' || ch == '9') {
|
||||
nonOctal = true;
|
||||
do {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
else if (! AlreadyComplained) {
|
||||
pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
|
||||
AlreadyComplained = 1;
|
||||
}
|
||||
ch = getch();
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
}
|
||||
if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F')
|
||||
return pp->lFloatConst(len, ch, ppToken);
|
||||
|
||||
// wasn't a float, so must be octal...
|
||||
if (nonOctal)
|
||||
pp->parseContext.ppError(ppToken->loc, "octal literal digit too large", "", "");
|
||||
|
||||
if (ch == 'u' || ch == 'U') {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
isUnsigned = true;
|
||||
|
||||
if (enableInt64) {
|
||||
int nextCh = getch();
|
||||
if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)nextCh;
|
||||
isInt64 = true;
|
||||
} else
|
||||
ungetch();
|
||||
}
|
||||
}
|
||||
else if (enableInt64 && (ch == 'l' || ch == 'L')) {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
isInt64 = true;
|
||||
} else
|
||||
ungetch();
|
||||
ppToken->name[len] = '\0';
|
||||
|
||||
if (octalOverflow)
|
||||
pp->parseContext.ppError(ppToken->loc, "octal literal too big", "", "");
|
||||
|
||||
if (isInt64) {
|
||||
ppToken->i64val = ival;
|
||||
return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
|
||||
} else {
|
||||
ppToken->ival = (int)ival;
|
||||
return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
// can't be hexidecimal or octal, is either decimal or floating point
|
||||
|
||||
do {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
else if (! AlreadyComplained) {
|
||||
pp->parseContext.ppError(ppToken->loc, "numeric literal too long", "", "");
|
||||
AlreadyComplained = 1;
|
||||
}
|
||||
ch = getch();
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'E' || ch == 'F') {
|
||||
return pp->lFloatConst(len, ch, ppToken);
|
||||
} else {
|
||||
// Finish handling signed and unsigned integers
|
||||
int numericLen = len;
|
||||
bool isUnsigned = false;
|
||||
bool isInt64 = false;
|
||||
if (ch == 'u' || ch == 'U') {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
isUnsigned = true;
|
||||
|
||||
if (enableInt64) {
|
||||
int nextCh = getch();
|
||||
if ((ch == 'u' && nextCh == 'l') || (ch == 'U' && nextCh == 'L')) {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)nextCh;
|
||||
isInt64 = true;
|
||||
} else
|
||||
ungetch();
|
||||
}
|
||||
} else if (enableInt64 && (ch == 'l' || ch == 'L')) {
|
||||
if (len < MaxTokenLength)
|
||||
ppToken->name[len++] = (char)ch;
|
||||
isInt64 = true;
|
||||
} else
|
||||
ungetch();
|
||||
|
||||
ppToken->name[len] = '\0';
|
||||
ival = 0;
|
||||
const unsigned oneTenthMaxInt = 0xFFFFFFFFu / 10;
|
||||
const unsigned remainderMaxInt = 0xFFFFFFFFu - 10 * oneTenthMaxInt;
|
||||
const unsigned long long oneTenthMaxInt64 = 0xFFFFFFFFFFFFFFFFull / 10;
|
||||
const unsigned long long remainderMaxInt64 = 0xFFFFFFFFFFFFFFFFull - 10 * oneTenthMaxInt64;
|
||||
for (int i = 0; i < numericLen; i++) {
|
||||
ch = ppToken->name[i] - '0';
|
||||
if ((enableInt64 == false && ((ival > oneTenthMaxInt) || (ival == oneTenthMaxInt && (unsigned)ch > remainderMaxInt))) ||
|
||||
(enableInt64 && ((ival > oneTenthMaxInt64) || (ival == oneTenthMaxInt64 && (unsigned long long)ch > remainderMaxInt64)))) {
|
||||
pp->parseContext.ppError(ppToken->loc, "numeric literal too big", "", "");
|
||||
ival = 0xFFFFFFFFFFFFFFFFull;
|
||||
break;
|
||||
} else
|
||||
ival = ival * 10 + ch;
|
||||
}
|
||||
|
||||
if (isInt64) {
|
||||
ppToken->i64val = ival;
|
||||
return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64;
|
||||
} else {
|
||||
ppToken->ival = (int)ival;
|
||||
return isUnsigned ? PpAtomConstUint : PpAtomConstInt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
ch = getch();
|
||||
if (ch == '-') {
|
||||
return PpAtomDecrement;
|
||||
} else if (ch == '=') {
|
||||
return PpAtomSub;
|
||||
} else {
|
||||
ungetch();
|
||||
return '-';
|
||||
}
|
||||
case '+':
|
||||
ch = getch();
|
||||
if (ch == '+') {
|
||||
return PpAtomIncrement;
|
||||
} else if (ch == '=') {
|
||||
return PpAtomAdd;
|
||||
} else {
|
||||
ungetch();
|
||||
return '+';
|
||||
}
|
||||
case '*':
|
||||
ch = getch();
|
||||
if (ch == '=') {
|
||||
return PpAtomMul;
|
||||
} else {
|
||||
ungetch();
|
||||
return '*';
|
||||
}
|
||||
case '%':
|
||||
ch = getch();
|
||||
if (ch == '=') {
|
||||
return PpAtomMod;
|
||||
} else {
|
||||
ungetch();
|
||||
return '%';
|
||||
}
|
||||
case '^':
|
||||
ch = getch();
|
||||
if (ch == '^') {
|
||||
return PpAtomXor;
|
||||
} else {
|
||||
if (ch == '=')
|
||||
return PpAtomXorAssign;
|
||||
else{
|
||||
ungetch();
|
||||
return '^';
|
||||
}
|
||||
}
|
||||
|
||||
case '=':
|
||||
ch = getch();
|
||||
if (ch == '=') {
|
||||
return PpAtomEQ;
|
||||
} else {
|
||||
ungetch();
|
||||
return '=';
|
||||
}
|
||||
case '!':
|
||||
ch = getch();
|
||||
if (ch == '=') {
|
||||
return PpAtomNE;
|
||||
} else {
|
||||
ungetch();
|
||||
return '!';
|
||||
}
|
||||
case '|':
|
||||
ch = getch();
|
||||
if (ch == '|') {
|
||||
return PpAtomOr;
|
||||
} else if (ch == '=') {
|
||||
return PpAtomOrAssign;
|
||||
} else {
|
||||
ungetch();
|
||||
return '|';
|
||||
}
|
||||
case '&':
|
||||
ch = getch();
|
||||
if (ch == '&') {
|
||||
return PpAtomAnd;
|
||||
} else if (ch == '=') {
|
||||
return PpAtomAndAssign;
|
||||
} else {
|
||||
ungetch();
|
||||
return '&';
|
||||
}
|
||||
case '<':
|
||||
ch = getch();
|
||||
if (ch == '<') {
|
||||
ch = getch();
|
||||
if (ch == '=')
|
||||
return PpAtomLeftAssign;
|
||||
else {
|
||||
ungetch();
|
||||
return PpAtomLeft;
|
||||
}
|
||||
} else if (ch == '=') {
|
||||
return PpAtomLE;
|
||||
} else {
|
||||
ungetch();
|
||||
return '<';
|
||||
}
|
||||
case '>':
|
||||
ch = getch();
|
||||
if (ch == '>') {
|
||||
ch = getch();
|
||||
if (ch == '=')
|
||||
return PpAtomRightAssign;
|
||||
else {
|
||||
ungetch();
|
||||
return PpAtomRight;
|
||||
}
|
||||
} else if (ch == '=') {
|
||||
return PpAtomGE;
|
||||
} else {
|
||||
ungetch();
|
||||
return '>';
|
||||
}
|
||||
case '.':
|
||||
ch = getch();
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
ungetch();
|
||||
return pp->lFloatConst(0, '.', ppToken);
|
||||
} else {
|
||||
ungetch();
|
||||
return '.';
|
||||
}
|
||||
case '/':
|
||||
ch = getch();
|
||||
if (ch == '/') {
|
||||
pp->inComment = true;
|
||||
do {
|
||||
ch = getch();
|
||||
} while (ch != '\n' && ch != EndOfInput);
|
||||
ppToken->space = true;
|
||||
pp->inComment = false;
|
||||
|
||||
return ch;
|
||||
} else if (ch == '*') {
|
||||
ch = getch();
|
||||
do {
|
||||
while (ch != '*') {
|
||||
if (ch == EndOfInput) {
|
||||
pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
|
||||
return ch;
|
||||
}
|
||||
ch = getch();
|
||||
}
|
||||
ch = getch();
|
||||
if (ch == EndOfInput) {
|
||||
pp->parseContext.ppError(ppToken->loc, "End of input in comment", "comment", "");
|
||||
return ch;
|
||||
}
|
||||
} while (ch != '/');
|
||||
ppToken->space = true;
|
||||
// loop again to get the next token...
|
||||
break;
|
||||
} else if (ch == '=') {
|
||||
return PpAtomDiv;
|
||||
} else {
|
||||
ungetch();
|
||||
return '/';
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
ch = getch();
|
||||
while (ch != '"' && ch != '\n' && ch != EndOfInput) {
|
||||
if (len < MaxTokenLength) {
|
||||
tokenText[len] = (char)ch;
|
||||
len++;
|
||||
ch = getch();
|
||||
} else
|
||||
break;
|
||||
};
|
||||
tokenText[len] = '\0';
|
||||
if (ch != '"') {
|
||||
ungetch();
|
||||
pp->parseContext.ppError(ppToken->loc, "End of line in string", "string", "");
|
||||
}
|
||||
return PpAtomConstString;
|
||||
}
|
||||
|
||||
ch = getch();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The main functional entry-point into the preprocessor, which will
|
||||
// scan the source strings to figure out and return the next processing token.
|
||||
//
|
||||
// Return string pointer to next token.
|
||||
// Return 0 when no more tokens.
|
||||
//
|
||||
const char* TPpContext::tokenize(TPpToken* ppToken)
|
||||
{
|
||||
int token = '\n';
|
||||
|
||||
for(;;) {
|
||||
token = scanToken(ppToken);
|
||||
ppToken->token = token;
|
||||
if (token == EndOfInput) {
|
||||
missingEndifCheck();
|
||||
return nullptr;
|
||||
}
|
||||
if (token == '#') {
|
||||
if (previous_token == '\n') {
|
||||
token = readCPPline(ppToken);
|
||||
if (token == EndOfInput) {
|
||||
missingEndifCheck();
|
||||
return nullptr;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
parseContext.ppError(ppToken->loc, "preprocessor directive cannot be preceded by another token", "#", "");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
previous_token = token;
|
||||
|
||||
if (token == '\n')
|
||||
continue;
|
||||
|
||||
// expand macros
|
||||
if (token == PpAtomIdentifier && MacroExpand(ppToken->atom, ppToken, false, true) != 0)
|
||||
continue;
|
||||
|
||||
const char* tokenString = nullptr;
|
||||
switch (token) {
|
||||
case PpAtomIdentifier:
|
||||
case PpAtomConstInt:
|
||||
case PpAtomConstUint:
|
||||
case PpAtomConstFloat:
|
||||
case PpAtomConstInt64:
|
||||
case PpAtomConstUint64:
|
||||
case PpAtomConstDouble:
|
||||
tokenString = ppToken->name;
|
||||
break;
|
||||
case PpAtomConstString:
|
||||
parseContext.ppError(ppToken->loc, "string literals not supported", "\"\"", "");
|
||||
break;
|
||||
case '\'':
|
||||
parseContext.ppError(ppToken->loc, "character literals not supported", "\'", "");
|
||||
break;
|
||||
default:
|
||||
tokenString = GetAtomString(token);
|
||||
break;
|
||||
}
|
||||
|
||||
if (tokenString) {
|
||||
if (tokenString[0] != 0)
|
||||
parseContext.tokensBeforeEOF = 1;
|
||||
|
||||
return tokenString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if we've seen balanced #if...#endif
|
||||
void TPpContext::missingEndifCheck()
|
||||
{
|
||||
if (ifdepth > 0)
|
||||
parseContext.ppError(parseContext.getCurrentLoc(), "missing #endif", "", "");
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,135 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
//
|
||||
// symbols.c
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "PpContext.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////// Symbol Table Variables: ///////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace glslang {
|
||||
|
||||
/*
|
||||
* Allocate a new symbol node;
|
||||
*
|
||||
*/
|
||||
TPpContext::Symbol* TPpContext::NewSymbol(int atom)
|
||||
{
|
||||
Symbol* lSymb;
|
||||
char* pch;
|
||||
size_t ii;
|
||||
|
||||
lSymb = (Symbol *) mem_Alloc(pool, sizeof(Symbol));
|
||||
lSymb->atom = atom;
|
||||
|
||||
// Clear macro
|
||||
pch = (char*) &lSymb->mac;
|
||||
for (ii = 0; ii < sizeof(lSymb->mac); ii++)
|
||||
*pch++ = 0;
|
||||
|
||||
return lSymb;
|
||||
}
|
||||
|
||||
TPpContext::Symbol* TPpContext::AddSymbol(int atom)
|
||||
{
|
||||
Symbol *lSymb;
|
||||
|
||||
lSymb = NewSymbol(atom);
|
||||
symbols[lSymb->atom] = lSymb;
|
||||
|
||||
return lSymb;
|
||||
}
|
||||
|
||||
TPpContext::Symbol* TPpContext::LookUpSymbol(int atom)
|
||||
{
|
||||
TSymbolMap::iterator it = symbols.find(atom);
|
||||
if (it == symbols.end())
|
||||
return nullptr;
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,278 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
|
||||
//
|
||||
// For recording and playing back the stream of tokens in a macro definition.
|
||||
//
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "PpContext.h"
|
||||
#include "PpTokens.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
void TPpContext::lAddByte(TokenStream *fTok, unsigned char fVal)
|
||||
{
|
||||
fTok->data.push_back(fVal);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next byte from a stream.
|
||||
*/
|
||||
int TPpContext::lReadByte(TokenStream *pTok)
|
||||
{
|
||||
if (pTok->current < pTok->data.size())
|
||||
return pTok->data[pTok->current++];
|
||||
else
|
||||
return EndOfInput;
|
||||
}
|
||||
|
||||
void TPpContext::lUnreadByte(TokenStream *pTok)
|
||||
{
|
||||
if (pTok->current > 0)
|
||||
--pTok->current;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a token to the end of a list for later playback.
|
||||
*/
|
||||
void TPpContext::RecordToken(TokenStream *pTok, int token, TPpToken* ppToken)
|
||||
{
|
||||
const char* s;
|
||||
char* str = NULL;
|
||||
|
||||
if (token > PpAtomMaxSingle)
|
||||
lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80));
|
||||
else
|
||||
lAddByte(pTok, (unsigned char)(token & 0x7f));
|
||||
|
||||
switch (token) {
|
||||
case PpAtomIdentifier:
|
||||
case PpAtomConstString:
|
||||
s = ppToken->name;
|
||||
while (*s)
|
||||
lAddByte(pTok, (unsigned char) *s++);
|
||||
lAddByte(pTok, 0);
|
||||
break;
|
||||
case PpAtomConstInt:
|
||||
case PpAtomConstUint:
|
||||
case PpAtomConstInt64:
|
||||
case PpAtomConstUint64:
|
||||
case PpAtomConstFloat:
|
||||
case PpAtomConstDouble:
|
||||
str = ppToken->name;
|
||||
while (*str) {
|
||||
lAddByte(pTok, (unsigned char) *str);
|
||||
str++;
|
||||
}
|
||||
lAddByte(pTok, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset a token stream in preperation for reading.
|
||||
*/
|
||||
void TPpContext::RewindTokenStream(TokenStream *pTok)
|
||||
{
|
||||
pTok->current = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the next token from a token stream (not the source stream, but stream used to hold a tokenized macro).
|
||||
*/
|
||||
int TPpContext::ReadToken(TokenStream *pTok, TPpToken *ppToken)
|
||||
{
|
||||
char* tokenText = ppToken->name;
|
||||
int ltoken, len;
|
||||
int ch;
|
||||
|
||||
ltoken = lReadByte(pTok);
|
||||
ppToken->loc = parseContext.getCurrentLoc();
|
||||
if (ltoken > 127)
|
||||
ltoken += 128;
|
||||
switch (ltoken) {
|
||||
case '#':
|
||||
if (lReadByte(pTok) == '#') {
|
||||
parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)");
|
||||
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)");
|
||||
parseContext.error(ppToken->loc, "token pasting not implemented (internal error)", "##", "");
|
||||
//return PpAtomPaste;
|
||||
return ReadToken(pTok, ppToken);
|
||||
} else
|
||||
lUnreadByte(pTok);
|
||||
break;
|
||||
case PpAtomConstString:
|
||||
case PpAtomIdentifier:
|
||||
case PpAtomConstFloat:
|
||||
case PpAtomConstDouble:
|
||||
case PpAtomConstInt:
|
||||
case PpAtomConstUint:
|
||||
case PpAtomConstInt64:
|
||||
case PpAtomConstUint64:
|
||||
len = 0;
|
||||
ch = lReadByte(pTok);
|
||||
while (ch != 0 && ch != EndOfInput) {
|
||||
if (len < MaxTokenLength) {
|
||||
tokenText[len] = (char)ch;
|
||||
len++;
|
||||
ch = lReadByte(pTok);
|
||||
} else {
|
||||
parseContext.error(ppToken->loc, "token too long", "", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
tokenText[len] = 0;
|
||||
|
||||
switch (ltoken) {
|
||||
case PpAtomIdentifier:
|
||||
ppToken->atom = LookUpAddString(tokenText);
|
||||
break;
|
||||
case PpAtomConstString:
|
||||
break;
|
||||
case PpAtomConstFloat:
|
||||
case PpAtomConstDouble:
|
||||
ppToken->dval = atof(ppToken->name);
|
||||
break;
|
||||
case PpAtomConstInt:
|
||||
case PpAtomConstUint:
|
||||
if (len > 0 && tokenText[0] == '0') {
|
||||
if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
|
||||
ppToken->ival = strtol(ppToken->name, 0, 16);
|
||||
else
|
||||
ppToken->ival = strtol(ppToken->name, 0, 8);
|
||||
} else
|
||||
ppToken->ival = atoi(ppToken->name);
|
||||
break;
|
||||
case PpAtomConstInt64:
|
||||
case PpAtomConstUint64:
|
||||
if (len > 0 && tokenText[0] == '0') {
|
||||
if (len > 1 && (tokenText[1] == 'x' || tokenText[1] == 'X'))
|
||||
ppToken->i64val = strtoll(ppToken->name, nullptr, 16);
|
||||
else
|
||||
ppToken->i64val = strtoll(ppToken->name, nullptr, 8);
|
||||
} else
|
||||
ppToken->i64val = atoll(ppToken->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ltoken;
|
||||
}
|
||||
|
||||
int TPpContext::tTokenInput::scan(TPpToken* ppToken)
|
||||
{
|
||||
return pp->ReadToken(tokens, ppToken);
|
||||
}
|
||||
|
||||
void TPpContext::pushTokenStreamInput(TokenStream* ts)
|
||||
{
|
||||
pushInput(new tTokenInput(this, ts));
|
||||
RewindTokenStream(ts);
|
||||
}
|
||||
|
||||
int TPpContext::tUngotTokenInput::scan(TPpToken* ppToken)
|
||||
{
|
||||
if (done)
|
||||
return EndOfInput;
|
||||
|
||||
int ret = token;
|
||||
*ppToken = lval;
|
||||
done = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TPpContext::UngetToken(int token, TPpToken* ppToken)
|
||||
{
|
||||
pushInput(new tUngotTokenInput(this, token, ppToken));
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,171 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
/****************************************************************************\
|
||||
Copyright (c) 2002, NVIDIA Corporation.
|
||||
|
||||
NVIDIA Corporation("NVIDIA") supplies this software to you in
|
||||
consideration of your agreement to the following terms, and your use,
|
||||
installation, modification or redistribution of this NVIDIA software
|
||||
constitutes acceptance of these terms. If you do not agree with these
|
||||
terms, please do not use, install, modify or redistribute this NVIDIA
|
||||
software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and
|
||||
subject to these terms, NVIDIA grants you a personal, non-exclusive
|
||||
license, under NVIDIA's copyrights in this original NVIDIA software (the
|
||||
"NVIDIA Software"), to use, reproduce, modify and redistribute the
|
||||
NVIDIA Software, with or without modifications, in source and/or binary
|
||||
forms; provided that if you redistribute the NVIDIA Software, you must
|
||||
retain the copyright notice of NVIDIA, this notice and the following
|
||||
text and disclaimers in all such redistributions of the NVIDIA Software.
|
||||
Neither the name, trademarks, service marks nor logos of NVIDIA
|
||||
Corporation may be used to endorse or promote products derived from the
|
||||
NVIDIA Software without specific prior written permission from NVIDIA.
|
||||
Except as expressly stated in this notice, no other rights or licenses
|
||||
express or implied, are granted by NVIDIA herein, including but not
|
||||
limited to any patent rights that may be infringed by your derivative
|
||||
works or by other works in which the NVIDIA Software may be
|
||||
incorporated. No hardware is licensed hereunder.
|
||||
|
||||
THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
|
||||
INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
|
||||
ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
|
||||
PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
||||
INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
|
||||
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
|
||||
NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
\****************************************************************************/
|
||||
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// Multi-character tokens
|
||||
enum EFixedAtoms {
|
||||
PpAtomMaxSingle = 256, // single character tokens get their own char value as their token, skip them
|
||||
|
||||
// Operators
|
||||
|
||||
PpAtomAdd,
|
||||
PpAtomSub,
|
||||
PpAtomMul,
|
||||
PpAtomDiv,
|
||||
PpAtomMod,
|
||||
|
||||
PpAtomRight,
|
||||
PpAtomLeft,
|
||||
|
||||
PpAtomRightAssign,
|
||||
PpAtomLeftAssign,
|
||||
PpAtomAndAssign,
|
||||
PpAtomOrAssign,
|
||||
PpAtomXorAssign,
|
||||
|
||||
PpAtomAnd,
|
||||
PpAtomOr,
|
||||
PpAtomXor,
|
||||
|
||||
PpAtomEQ,
|
||||
PpAtomNE,
|
||||
PpAtomGE,
|
||||
PpAtomLE,
|
||||
|
||||
PpAtomDecrement,
|
||||
PpAtomIncrement,
|
||||
|
||||
PpAtomPaste,
|
||||
|
||||
// Constants
|
||||
|
||||
PpAtomConstInt,
|
||||
PpAtomConstUint,
|
||||
PpAtomConstInt64,
|
||||
PpAtomConstUint64,
|
||||
PpAtomConstFloat,
|
||||
PpAtomConstDouble,
|
||||
PpAtomConstString,
|
||||
|
||||
// Indentifiers
|
||||
PpAtomIdentifier,
|
||||
|
||||
// preprocessor "keywords"
|
||||
|
||||
PpAtomDefine,
|
||||
PpAtomDefined,
|
||||
PpAtomUndef,
|
||||
|
||||
PpAtomIf,
|
||||
PpAtomIfdef,
|
||||
PpAtomIfndef,
|
||||
PpAtomElse,
|
||||
PpAtomElif,
|
||||
PpAtomEndif,
|
||||
|
||||
PpAtomLine,
|
||||
PpAtomPragma,
|
||||
PpAtomError,
|
||||
|
||||
// #version ...
|
||||
PpAtomVersion,
|
||||
PpAtomCore,
|
||||
PpAtomCompatibility,
|
||||
PpAtomEs,
|
||||
|
||||
// #extension
|
||||
PpAtomExtension,
|
||||
|
||||
// __LINE__, __FILE__, __VERSION__
|
||||
|
||||
PpAtomLineMacro,
|
||||
PpAtomFileMacro,
|
||||
PpAtomVersionMacro,
|
||||
|
||||
// #include
|
||||
PpAtomInclude,
|
||||
|
||||
PpAtomLast,
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif /* not PARSER_H */
|
|
@ -0,0 +1,865 @@
|
|||
//
|
||||
// Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Visit the nodes in the glslang intermediate tree representation to
|
||||
// propagate the 'noContraction' qualifier.
|
||||
//
|
||||
|
||||
#include "propagateNoContraction.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "localintermediate.h"
|
||||
namespace {
|
||||
|
||||
// Use a string to hold the access chain information, as in most cases the
|
||||
// access chain is short and may contain only one element, which is the symbol
|
||||
// ID.
|
||||
// Example: struct {float a; float b;} s;
|
||||
// Object s.a will be represented with: <symbol ID of s>/0
|
||||
// Object s.b will be represented with: <symbol ID of s>/1
|
||||
// Object s will be represented with: <symbol ID of s>
|
||||
// For members of vector, matrix and arrays, they will be represented with the
|
||||
// same symbol ID of their container symbol objects. This is because their
|
||||
// preciseness is always the same as their container symbol objects.
|
||||
typedef std::string ObjectAccessChain;
|
||||
|
||||
// The delimiter used in the ObjectAccessChain string to separate symbol ID and
|
||||
// different level of struct indices.
|
||||
const char ObjectAccesschainDelimiter = '/';
|
||||
|
||||
// Mapping from Symbol IDs of symbol nodes, to their defining operation
|
||||
// nodes.
|
||||
typedef std::unordered_multimap<ObjectAccessChain, glslang::TIntermOperator*> NodeMapping;
|
||||
// Mapping from object nodes to their access chain info string.
|
||||
typedef std::unordered_map<glslang::TIntermTyped*, ObjectAccessChain> AccessChainMapping;
|
||||
|
||||
// Set of object IDs.
|
||||
typedef std::unordered_set<ObjectAccessChain> ObjectAccesschainSet;
|
||||
// Set of return branch nodes.
|
||||
typedef std::unordered_set<glslang::TIntermBranch*> ReturnBranchNodeSet;
|
||||
|
||||
// A helper function to tell whether a node is 'noContraction'. Returns true if
|
||||
// the node has 'noContraction' qualifier, otherwise false.
|
||||
bool isPreciseObjectNode(glslang::TIntermTyped* node)
|
||||
{
|
||||
return node->getType().getQualifier().noContraction;
|
||||
}
|
||||
|
||||
// Returns true if the opcode is a dereferencing one.
|
||||
bool isDereferenceOperation(glslang::TOperator op)
|
||||
{
|
||||
switch (op) {
|
||||
case glslang::EOpIndexDirect:
|
||||
case glslang::EOpIndexDirectStruct:
|
||||
case glslang::EOpIndexIndirect:
|
||||
case glslang::EOpVectorSwizzle:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the opcode leads to an assignment operation.
|
||||
bool isAssignOperation(glslang::TOperator op)
|
||||
{
|
||||
switch (op) {
|
||||
case glslang::EOpAssign:
|
||||
case glslang::EOpAddAssign:
|
||||
case glslang::EOpSubAssign:
|
||||
case glslang::EOpMulAssign:
|
||||
case glslang::EOpVectorTimesMatrixAssign:
|
||||
case glslang::EOpVectorTimesScalarAssign:
|
||||
case glslang::EOpMatrixTimesScalarAssign:
|
||||
case glslang::EOpMatrixTimesMatrixAssign:
|
||||
case glslang::EOpDivAssign:
|
||||
case glslang::EOpModAssign:
|
||||
case glslang::EOpAndAssign:
|
||||
case glslang::EOpLeftShiftAssign:
|
||||
case glslang::EOpRightShiftAssign:
|
||||
case glslang::EOpInclusiveOrAssign:
|
||||
case glslang::EOpExclusiveOrAssign:
|
||||
|
||||
case glslang::EOpPostIncrement:
|
||||
case glslang::EOpPostDecrement:
|
||||
case glslang::EOpPreIncrement:
|
||||
case glslang::EOpPreDecrement:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// A helper function to get the unsigned int from a given constant union node.
|
||||
// Note the node should only hold a uint scalar.
|
||||
unsigned getStructIndexFromConstantUnion(glslang::TIntermTyped* node)
|
||||
{
|
||||
assert(node->getAsConstantUnion() && node->getAsConstantUnion()->isScalar());
|
||||
unsigned struct_dereference_index = node->getAsConstantUnion()->getConstArray()[0].getUConst();
|
||||
return struct_dereference_index;
|
||||
}
|
||||
|
||||
// A helper function to generate symbol_label.
|
||||
ObjectAccessChain generateSymbolLabel(glslang::TIntermSymbol* node)
|
||||
{
|
||||
ObjectAccessChain symbol_id =
|
||||
std::to_string(node->getId()) + "(" + node->getName().c_str() + ")";
|
||||
return symbol_id;
|
||||
}
|
||||
|
||||
// Returns true if the operation is an arithmetic operation and valid for
|
||||
// the 'NoContraction' decoration.
|
||||
bool isArithmeticOperation(glslang::TOperator op)
|
||||
{
|
||||
switch (op) {
|
||||
case glslang::EOpAddAssign:
|
||||
case glslang::EOpSubAssign:
|
||||
case glslang::EOpMulAssign:
|
||||
case glslang::EOpVectorTimesMatrixAssign:
|
||||
case glslang::EOpVectorTimesScalarAssign:
|
||||
case glslang::EOpMatrixTimesScalarAssign:
|
||||
case glslang::EOpMatrixTimesMatrixAssign:
|
||||
case glslang::EOpDivAssign:
|
||||
case glslang::EOpModAssign:
|
||||
|
||||
case glslang::EOpNegative:
|
||||
|
||||
case glslang::EOpAdd:
|
||||
case glslang::EOpSub:
|
||||
case glslang::EOpMul:
|
||||
case glslang::EOpDiv:
|
||||
case glslang::EOpMod:
|
||||
|
||||
case glslang::EOpVectorTimesScalar:
|
||||
case glslang::EOpVectorTimesMatrix:
|
||||
case glslang::EOpMatrixTimesVector:
|
||||
case glslang::EOpMatrixTimesScalar:
|
||||
case glslang::EOpMatrixTimesMatrix:
|
||||
|
||||
case glslang::EOpDot:
|
||||
|
||||
case glslang::EOpPostIncrement:
|
||||
case glslang::EOpPostDecrement:
|
||||
case glslang::EOpPreIncrement:
|
||||
case glslang::EOpPreDecrement:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// A helper class to help manage the populating_initial_no_contraction_ flag.
|
||||
template <typename T> class StateSettingGuard {
|
||||
public:
|
||||
StateSettingGuard(T* state_ptr, T new_state_value)
|
||||
: state_ptr_(state_ptr), previous_state_(*state_ptr)
|
||||
{
|
||||
*state_ptr = new_state_value;
|
||||
}
|
||||
StateSettingGuard(T* state_ptr) : state_ptr_(state_ptr), previous_state_(*state_ptr) {}
|
||||
void setState(T new_state_value) { *state_ptr_ = new_state_value; }
|
||||
~StateSettingGuard() { *state_ptr_ = previous_state_; }
|
||||
|
||||
private:
|
||||
T* state_ptr_;
|
||||
T previous_state_;
|
||||
};
|
||||
|
||||
// A helper function to get the front element from a given ObjectAccessChain
|
||||
ObjectAccessChain getFrontElement(const ObjectAccessChain& chain)
|
||||
{
|
||||
size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter);
|
||||
return pos_delimiter == std::string::npos ? chain : chain.substr(0, pos_delimiter);
|
||||
}
|
||||
|
||||
// A helper function to get the access chain starting from the second element.
|
||||
ObjectAccessChain subAccessChainFromSecondElement(const ObjectAccessChain& chain)
|
||||
{
|
||||
size_t pos_delimiter = chain.find(ObjectAccesschainDelimiter);
|
||||
return pos_delimiter == std::string::npos ? "" : chain.substr(pos_delimiter + 1);
|
||||
}
|
||||
|
||||
// A helper function to get the access chain after removing a given prefix.
|
||||
ObjectAccessChain getSubAccessChainAfterPrefix(const ObjectAccessChain& chain,
|
||||
const ObjectAccessChain& prefix)
|
||||
{
|
||||
size_t pos = chain.find(prefix);
|
||||
if (pos != 0)
|
||||
return chain;
|
||||
return chain.substr(prefix.length() + sizeof(ObjectAccesschainDelimiter));
|
||||
}
|
||||
|
||||
//
|
||||
// A traverser which traverses the whole AST and populates:
|
||||
// 1) A mapping from symbol nodes' IDs to their defining operation nodes.
|
||||
// 2) A set of access chains of the initial precise object nodes.
|
||||
//
|
||||
class TSymbolDefinitionCollectingTraverser : public glslang::TIntermTraverser {
|
||||
public:
|
||||
TSymbolDefinitionCollectingTraverser(NodeMapping* symbol_definition_mapping,
|
||||
AccessChainMapping* accesschain_mapping,
|
||||
ObjectAccesschainSet* precise_objects,
|
||||
ReturnBranchNodeSet* precise_return_nodes);
|
||||
|
||||
bool visitUnary(glslang::TVisit, glslang::TIntermUnary*) override;
|
||||
bool visitBinary(glslang::TVisit, glslang::TIntermBinary*) override;
|
||||
void visitSymbol(glslang::TIntermSymbol*) override;
|
||||
bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*) override;
|
||||
bool visitBranch(glslang::TVisit, glslang::TIntermBranch*) override;
|
||||
|
||||
protected:
|
||||
TSymbolDefinitionCollectingTraverser& operator=(const TSymbolDefinitionCollectingTraverser&);
|
||||
|
||||
// The mapping from symbol node IDs to their defining nodes. This should be
|
||||
// populated along traversing the AST.
|
||||
NodeMapping& symbol_definition_mapping_;
|
||||
// The set of symbol node IDs for precise symbol nodes, the ones marked as
|
||||
// 'noContraction'.
|
||||
ObjectAccesschainSet& precise_objects_;
|
||||
// The set of precise return nodes.
|
||||
ReturnBranchNodeSet& precise_return_nodes_;
|
||||
// A temporary cache of the symbol node whose defining node is to be found
|
||||
// currently along traversing the AST.
|
||||
ObjectAccessChain current_object_;
|
||||
// A map from object node to its access chain. This traverser stores
|
||||
// the built access chains into this map for each object node it has
|
||||
// visited.
|
||||
AccessChainMapping& accesschain_mapping_;
|
||||
// The pointer to the Function Definition node, so we can get the
|
||||
// preciseness of the return expression from it when we traverse the
|
||||
// return branch node.
|
||||
glslang::TIntermAggregate* current_function_definition_node_;
|
||||
};
|
||||
|
||||
TSymbolDefinitionCollectingTraverser::TSymbolDefinitionCollectingTraverser(
|
||||
NodeMapping* symbol_definition_mapping, AccessChainMapping* accesschain_mapping,
|
||||
ObjectAccesschainSet* precise_objects,
|
||||
std::unordered_set<glslang::TIntermBranch*>* precise_return_nodes)
|
||||
: TIntermTraverser(true, false, false), symbol_definition_mapping_(*symbol_definition_mapping),
|
||||
precise_objects_(*precise_objects), current_object_(),
|
||||
accesschain_mapping_(*accesschain_mapping), current_function_definition_node_(nullptr),
|
||||
precise_return_nodes_(*precise_return_nodes) {}
|
||||
|
||||
// Visits a symbol node, set the current_object_ to the
|
||||
// current node symbol ID, and record a mapping from this node to the current
|
||||
// current_object_, which is the just obtained symbol
|
||||
// ID.
|
||||
void TSymbolDefinitionCollectingTraverser::visitSymbol(glslang::TIntermSymbol* node)
|
||||
{
|
||||
current_object_ = generateSymbolLabel(node);
|
||||
accesschain_mapping_[node] = current_object_;
|
||||
}
|
||||
|
||||
// Visits an aggregate node, traverses all of its children.
|
||||
bool TSymbolDefinitionCollectingTraverser::visitAggregate(glslang::TVisit,
|
||||
glslang::TIntermAggregate* node)
|
||||
{
|
||||
// This aggregate node might be a function definition node, in which case we need to
|
||||
// cache this node, so we can get the preciseness information of the return value
|
||||
// of this function later.
|
||||
StateSettingGuard<glslang::TIntermAggregate*> current_function_definition_node_setting_guard(
|
||||
¤t_function_definition_node_);
|
||||
if (node->getOp() == glslang::EOpFunction) {
|
||||
// This is function definition node, we need to cache this node so that we can
|
||||
// get the preciseness of the return value later.
|
||||
current_function_definition_node_setting_guard.setState(node);
|
||||
}
|
||||
// Traverse the items in the sequence.
|
||||
glslang::TIntermSequence& seq = node->getSequence();
|
||||
for (int i = 0; i < (int)seq.size(); ++i) {
|
||||
current_object_.clear();
|
||||
seq[i]->traverse(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TSymbolDefinitionCollectingTraverser::visitBranch(glslang::TVisit,
|
||||
glslang::TIntermBranch* node)
|
||||
{
|
||||
if (node->getFlowOp() == glslang::EOpReturn && node->getExpression() &&
|
||||
current_function_definition_node_ &&
|
||||
current_function_definition_node_->getType().getQualifier().noContraction) {
|
||||
// This node is a return node with an expression, and its function has a
|
||||
// precise return value. We need to find the involved objects in its
|
||||
// expression and add them to the set of initial precise objects.
|
||||
precise_return_nodes_.insert(node);
|
||||
node->getExpression()->traverse(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Visits a unary node. This might be an implicit assignment like i++, i--. etc.
|
||||
bool TSymbolDefinitionCollectingTraverser::visitUnary(glslang::TVisit /* visit */,
|
||||
glslang::TIntermUnary* node)
|
||||
{
|
||||
current_object_.clear();
|
||||
node->getOperand()->traverse(this);
|
||||
if (isAssignOperation(node->getOp())) {
|
||||
// We should always be able to get an access chain of the operand node.
|
||||
assert(!current_object_.empty());
|
||||
|
||||
// If the operand node object is 'precise', we collect its access chain
|
||||
// for the initial set of 'precise' objects.
|
||||
if (isPreciseObjectNode(node->getOperand())) {
|
||||
// The operand node is an 'precise' object node, add its
|
||||
// access chain to the set of 'precise' objects. This is to collect
|
||||
// the initial set of 'precise' objects.
|
||||
precise_objects_.insert(current_object_);
|
||||
}
|
||||
// Gets the symbol ID from the object's access chain.
|
||||
ObjectAccessChain id_symbol = getFrontElement(current_object_);
|
||||
// Add a mapping from the symbol ID to this assignment operation node.
|
||||
symbol_definition_mapping_.insert(std::make_pair(id_symbol, node));
|
||||
}
|
||||
// A unary node is not a dereference node, so we clear the access chain which
|
||||
// is under construction.
|
||||
current_object_.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Visits a binary node and updates the mapping from symbol IDs to the definition
|
||||
// nodes. Also collects the access chains for the initial precise objects.
|
||||
bool TSymbolDefinitionCollectingTraverser::visitBinary(glslang::TVisit /* visit */,
|
||||
glslang::TIntermBinary* node)
|
||||
{
|
||||
// Traverses the left node to build the access chain info for the object.
|
||||
current_object_.clear();
|
||||
node->getLeft()->traverse(this);
|
||||
|
||||
if (isAssignOperation(node->getOp())) {
|
||||
// We should always be able to get an access chain for the left node.
|
||||
assert(!current_object_.empty());
|
||||
|
||||
// If the left node object is 'precise', it is an initial precise object
|
||||
// specified in the shader source. Adds it to the initial work list to
|
||||
// process later.
|
||||
if (isPreciseObjectNode(node->getLeft())) {
|
||||
// The left node is an 'precise' object node, add its access chain to
|
||||
// the set of 'precise' objects. This is to collect the initial set
|
||||
// of 'precise' objects.
|
||||
precise_objects_.insert(current_object_);
|
||||
}
|
||||
// Gets the symbol ID from the object access chain, which should be the
|
||||
// first element recorded in the access chain.
|
||||
ObjectAccessChain id_symbol = getFrontElement(current_object_);
|
||||
// Adds a mapping from the symbol ID to this assignment operation node.
|
||||
symbol_definition_mapping_.insert(std::make_pair(id_symbol, node));
|
||||
|
||||
// Traverses the right node, there may be other 'assignment'
|
||||
// operations in the right.
|
||||
current_object_.clear();
|
||||
node->getRight()->traverse(this);
|
||||
|
||||
} else if (isDereferenceOperation(node->getOp())) {
|
||||
// The left node (parent node) is a struct type object. We need to
|
||||
// record the access chain information of the current node into its
|
||||
// object id.
|
||||
if (node->getOp() == glslang::EOpIndexDirectStruct) {
|
||||
unsigned struct_dereference_index = getStructIndexFromConstantUnion(node->getRight());
|
||||
current_object_.push_back(ObjectAccesschainDelimiter);
|
||||
current_object_.append(std::to_string(struct_dereference_index));
|
||||
}
|
||||
accesschain_mapping_[node] = current_object_;
|
||||
|
||||
// For a dereference node, there is no need to traverse the right child
|
||||
// node as the right node should always be an integer type object.
|
||||
|
||||
} else {
|
||||
// For other binary nodes, still traverse the right node.
|
||||
current_object_.clear();
|
||||
node->getRight()->traverse(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Traverses the AST and returns a tuple of four members:
|
||||
// 1) a mapping from symbol IDs to the definition nodes (aka. assignment nodes) of these symbols.
|
||||
// 2) a mapping from object nodes in the AST to the access chains of these objects.
|
||||
// 3) a set of access chains of precise objects.
|
||||
// 4) a set of return nodes with precise expressions.
|
||||
std::tuple<NodeMapping, AccessChainMapping, ObjectAccesschainSet, ReturnBranchNodeSet>
|
||||
getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& intermediate)
|
||||
{
|
||||
auto result_tuple = std::make_tuple(NodeMapping(), AccessChainMapping(), ObjectAccesschainSet(),
|
||||
ReturnBranchNodeSet());
|
||||
|
||||
TIntermNode* root = intermediate.getTreeRoot();
|
||||
if (root == 0)
|
||||
return result_tuple;
|
||||
|
||||
NodeMapping& symbol_definition_mapping = std::get<0>(result_tuple);
|
||||
AccessChainMapping& accesschain_mapping = std::get<1>(result_tuple);
|
||||
ObjectAccesschainSet& precise_objects = std::get<2>(result_tuple);
|
||||
ReturnBranchNodeSet& precise_return_nodes = std::get<3>(result_tuple);
|
||||
|
||||
// Traverses the AST and populate the results.
|
||||
TSymbolDefinitionCollectingTraverser collector(&symbol_definition_mapping, &accesschain_mapping,
|
||||
&precise_objects, &precise_return_nodes);
|
||||
root->traverse(&collector);
|
||||
|
||||
return result_tuple;
|
||||
}
|
||||
|
||||
//
|
||||
// A traverser that determine whether the left node (or operand node for unary
|
||||
// node) of an assignment node is 'precise', containing 'precise' or not,
|
||||
// according to the access chain a given precise object which share the same
|
||||
// symbol as the left node.
|
||||
//
|
||||
// Post-orderly traverses the left node subtree of an binary assignment node and:
|
||||
//
|
||||
// 1) Propagates the 'precise' from the left object nodes to this object node.
|
||||
//
|
||||
// 2) Builds object access chain along the traversal, and also compares with
|
||||
// the access chain of the given 'precise' object along with the traversal to
|
||||
// tell if the node to be defined is 'precise' or not.
|
||||
//
|
||||
class TNoContractionAssigneeCheckingTraverser : public glslang::TIntermTraverser {
|
||||
|
||||
enum DecisionStatus {
|
||||
// The object node to be assigned to may contain 'precise' objects and also not 'precise' objects.
|
||||
Mixed = 0,
|
||||
// The object node to be assigned to is either a 'precise' object or a struct objects whose members are all 'precise'.
|
||||
Precise = 1,
|
||||
// The object node to be assigned to is not a 'precise' object.
|
||||
NotPreicse = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
TNoContractionAssigneeCheckingTraverser(const AccessChainMapping& accesschain_mapping)
|
||||
: TIntermTraverser(true, false, false), accesschain_mapping_(accesschain_mapping),
|
||||
precise_object_(nullptr) {}
|
||||
|
||||
// Checks the preciseness of a given assignment node with a precise object
|
||||
// represented as access chain. The precise object shares the same symbol
|
||||
// with the assignee of the given assignment node. Return a tuple of two:
|
||||
//
|
||||
// 1) The preciseness of the assignee node of this assignment node. True
|
||||
// if the assignee contains 'precise' objects or is 'precise', false if
|
||||
// the assignee is not 'precise' according to the access chain of the given
|
||||
// precise object.
|
||||
//
|
||||
// 2) The incremental access chain from the assignee node to its nested
|
||||
// 'precise' object, according to the access chain of the given precise
|
||||
// object. This incremental access chain can be empty, which means the
|
||||
// assignee is 'precise'. Otherwise it shows the path to the nested
|
||||
// precise object.
|
||||
std::tuple<bool, ObjectAccessChain>
|
||||
getPrecisenessAndRemainedAccessChain(glslang::TIntermOperator* node,
|
||||
const ObjectAccessChain& precise_object)
|
||||
{
|
||||
assert(isAssignOperation(node->getOp()));
|
||||
precise_object_ = &precise_object;
|
||||
ObjectAccessChain assignee_object;
|
||||
if (glslang::TIntermBinary* BN = node->getAsBinaryNode()) {
|
||||
// This is a binary assignment node, we need to check the
|
||||
// preciseness of the left node.
|
||||
assert(accesschain_mapping_.count(BN->getLeft()));
|
||||
// The left node (assignee node) is an object node, traverse the
|
||||
// node to let the 'precise' of nesting objects being transfered to
|
||||
// nested objects.
|
||||
BN->getLeft()->traverse(this);
|
||||
// After traversing the left node, if the left node is 'precise',
|
||||
// we can conclude this assignment should propagate 'precise'.
|
||||
if (isPreciseObjectNode(BN->getLeft())) {
|
||||
return make_tuple(true, ObjectAccessChain());
|
||||
}
|
||||
// If the preciseness of the left node (assignee node) can not
|
||||
// be determined by now, we need to compare the access chain string
|
||||
// of the assignee object with the given precise object.
|
||||
assignee_object = accesschain_mapping_.at(BN->getLeft());
|
||||
|
||||
} else if (glslang::TIntermUnary* UN = node->getAsUnaryNode()) {
|
||||
// This is a unary assignment node, we need to check the
|
||||
// preciseness of the operand node. For unary assignment node, the
|
||||
// operand node should always be an object node.
|
||||
assert(accesschain_mapping_.count(UN->getOperand()));
|
||||
// Traverse the operand node to let the 'precise' being propagated
|
||||
// from lower nodes to upper nodes.
|
||||
UN->getOperand()->traverse(this);
|
||||
// After traversing the operand node, if the operand node is
|
||||
// 'precise', this assignment should propagate 'precise'.
|
||||
if (isPreciseObjectNode(UN->getOperand())) {
|
||||
return make_tuple(true, ObjectAccessChain());
|
||||
}
|
||||
// If the preciseness of the operand node (assignee node) can not
|
||||
// be determined by now, we need to compare the access chain string
|
||||
// of the assignee object with the given precise object.
|
||||
assignee_object = accesschain_mapping_.at(UN->getOperand());
|
||||
} else {
|
||||
// Not a binary or unary node, should not happen.
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Compare the access chain string of the assignee node with the given
|
||||
// precise object to determine if this assignment should propagate
|
||||
// 'precise'.
|
||||
if (assignee_object.find(precise_object) == 0) {
|
||||
// The access chain string of the given precise object is a prefix
|
||||
// of assignee's access chain string. The assignee should be
|
||||
// 'precise'.
|
||||
return make_tuple(true, ObjectAccessChain());
|
||||
} else if (precise_object.find(assignee_object) == 0) {
|
||||
// The assignee's access chain string is a prefix of the given
|
||||
// precise object, the assignee object contains 'precise' object,
|
||||
// and we need to pass the remained access chain to the object nodes
|
||||
// in the right.
|
||||
return make_tuple(true, getSubAccessChainAfterPrefix(precise_object, assignee_object));
|
||||
} else {
|
||||
// The access chain strings do not match, the assignee object can
|
||||
// not be labeled as 'precise' according to the given precise
|
||||
// object.
|
||||
return make_tuple(false, ObjectAccessChain());
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
TNoContractionAssigneeCheckingTraverser& operator=(const TNoContractionAssigneeCheckingTraverser&);
|
||||
|
||||
bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override;
|
||||
void visitSymbol(glslang::TIntermSymbol* node) override;
|
||||
|
||||
// A map from object nodes to their access chain string (used as object ID).
|
||||
const AccessChainMapping& accesschain_mapping_;
|
||||
// A given precise object, represented in it access chain string. This
|
||||
// precise object is used to be compared with the assignee node to tell if
|
||||
// the assignee node is 'precise', contains 'precise' object or not
|
||||
// 'precise'.
|
||||
const ObjectAccessChain* precise_object_;
|
||||
};
|
||||
|
||||
// Visits a binary node. If the node is an object node, it must be a dereference
|
||||
// node. In such cases, if the left node is 'precise', this node should also be
|
||||
// 'precise'.
|
||||
bool TNoContractionAssigneeCheckingTraverser::visitBinary(glslang::TVisit,
|
||||
glslang::TIntermBinary* node)
|
||||
{
|
||||
// Traverses the left so that we transfer the 'precise' from nesting object
|
||||
// to its nested object.
|
||||
node->getLeft()->traverse(this);
|
||||
// If this binary node is an object node, we should have it in the
|
||||
// accesschain_mapping_.
|
||||
if (accesschain_mapping_.count(node)) {
|
||||
// A binary object node must be a dereference node.
|
||||
assert(isDereferenceOperation(node->getOp()));
|
||||
// If the left node is 'precise', this node should also be precise,
|
||||
// otherwise, compare with the given precise_object_. If the
|
||||
// access chain of this node matches with the given precise_object_,
|
||||
// this node should be marked as 'precise'.
|
||||
if (isPreciseObjectNode(node->getLeft())) {
|
||||
node->getWritableType().getQualifier().noContraction = true;
|
||||
} else if (accesschain_mapping_.at(node) == *precise_object_) {
|
||||
node->getWritableType().getQualifier().noContraction = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Visits a symbol node, if the symbol node ID (its access chain string) matches
|
||||
// with the given precise object, this node should be 'precise'.
|
||||
void TNoContractionAssigneeCheckingTraverser::visitSymbol(glslang::TIntermSymbol* node)
|
||||
{
|
||||
// A symbol node should always be an object node, and should have been added
|
||||
// to the map from object nodes to their access chain strings.
|
||||
assert(accesschain_mapping_.count(node));
|
||||
if (accesschain_mapping_.at(node) == *precise_object_) {
|
||||
node->getWritableType().getQualifier().noContraction = true;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// A traverser that only traverses the right side of binary assignment nodes
|
||||
// and the operand node of unary assignment nodes.
|
||||
//
|
||||
// 1) Marks arithmetic operations as 'NoContraction'.
|
||||
//
|
||||
// 2) Find the object which should be marked as 'precise' in the right and
|
||||
// update the 'precise' object work list.
|
||||
//
|
||||
class TNoContractionPropagator : public glslang::TIntermTraverser {
|
||||
public:
|
||||
TNoContractionPropagator(ObjectAccesschainSet* precise_objects,
|
||||
const AccessChainMapping& accesschain_mapping)
|
||||
: TIntermTraverser(true, false, false), remained_accesschain_(),
|
||||
precise_objects_(*precise_objects), accesschain_mapping_(accesschain_mapping),
|
||||
added_precise_object_ids_() {}
|
||||
|
||||
// Propagates 'precise' in the right nodes of a given assignment node with
|
||||
// access chain record from the assignee node to a 'precise' object it
|
||||
// contains.
|
||||
void
|
||||
propagateNoContractionInOneExpression(glslang::TIntermTyped* defining_node,
|
||||
const ObjectAccessChain& assignee_remained_accesschain)
|
||||
{
|
||||
remained_accesschain_ = assignee_remained_accesschain;
|
||||
if (glslang::TIntermBinary* BN = defining_node->getAsBinaryNode()) {
|
||||
assert(isAssignOperation(BN->getOp()));
|
||||
BN->getRight()->traverse(this);
|
||||
if (isArithmeticOperation(BN->getOp())) {
|
||||
BN->getWritableType().getQualifier().noContraction = true;
|
||||
}
|
||||
} else if (glslang::TIntermUnary* UN = defining_node->getAsUnaryNode()) {
|
||||
assert(isAssignOperation(UN->getOp()));
|
||||
UN->getOperand()->traverse(this);
|
||||
if (isArithmeticOperation(UN->getOp())) {
|
||||
UN->getWritableType().getQualifier().noContraction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Propagates 'precise' in a given precise return node.
|
||||
void propagateNoContractionInReturnNode(glslang::TIntermBranch* return_node)
|
||||
{
|
||||
remained_accesschain_ = "";
|
||||
assert(return_node->getFlowOp() == glslang::EOpReturn && return_node->getExpression());
|
||||
return_node->getExpression()->traverse(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
TNoContractionPropagator& operator=(const TNoContractionPropagator&);
|
||||
|
||||
// Visits an aggregate node. The node can be a initializer list, in which
|
||||
// case we need to find the 'precise' or 'precise' containing object node
|
||||
// with the access chain record. In other cases, just need to traverse all
|
||||
// the children nodes.
|
||||
bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate* node) override
|
||||
{
|
||||
if (!remained_accesschain_.empty() && node->getOp() == glslang::EOpConstructStruct) {
|
||||
// This is a struct initializer node, and the remained
|
||||
// access chain is not empty, we need to refer to the
|
||||
// assignee_remained_access_chain_ to find the nested
|
||||
// 'precise' object. And we don't need to visit other nodes in this
|
||||
// aggregate node.
|
||||
|
||||
// Gets the struct dereference index that leads to 'precise' object.
|
||||
ObjectAccessChain precise_accesschain_index_str =
|
||||
getFrontElement(remained_accesschain_);
|
||||
unsigned precise_accesschain_index = strtoul(precise_accesschain_index_str.c_str(), nullptr, 10);
|
||||
// Gets the node pointed by the access chain index extracted before.
|
||||
glslang::TIntermTyped* potential_precise_node =
|
||||
node->getSequence()[precise_accesschain_index]->getAsTyped();
|
||||
assert(potential_precise_node);
|
||||
// Pop the front access chain index from the path, and visit the nested node.
|
||||
{
|
||||
ObjectAccessChain next_level_accesschain =
|
||||
subAccessChainFromSecondElement(remained_accesschain_);
|
||||
StateSettingGuard<ObjectAccessChain> setup_remained_accesschain_for_next_level(
|
||||
&remained_accesschain_, next_level_accesschain);
|
||||
potential_precise_node->traverse(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Visits a binary node. A binary node can be an object node, e.g. a dereference node.
|
||||
// As only the top object nodes in the right side of an assignment needs to be visited
|
||||
// and added to 'precise' work list, this traverser won't visit the children nodes of
|
||||
// an object node. If the binary node does not represent an object node, it should
|
||||
// go on to traverse its children nodes and if it is an arithmetic operation node, this
|
||||
// operation should be marked as 'noContraction'.
|
||||
bool visitBinary(glslang::TVisit, glslang::TIntermBinary* node) override
|
||||
{
|
||||
if (isDereferenceOperation(node->getOp())) {
|
||||
// This binary node is an object node. Need to update the precise
|
||||
// object set with the access chain of this node + remained
|
||||
// access chain .
|
||||
ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node);
|
||||
if (remained_accesschain_.empty()) {
|
||||
node->getWritableType().getQualifier().noContraction = true;
|
||||
} else {
|
||||
new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_;
|
||||
}
|
||||
// Cache the access chain as added precise object, so we won't add the
|
||||
// same object to the work list again.
|
||||
if (!added_precise_object_ids_.count(new_precise_accesschain)) {
|
||||
precise_objects_.insert(new_precise_accesschain);
|
||||
added_precise_object_ids_.insert(new_precise_accesschain);
|
||||
}
|
||||
// Only the upper-most object nodes should be visited, so do not
|
||||
// visit children of this object node.
|
||||
return false;
|
||||
}
|
||||
// If this is an arithmetic operation, marks this node as 'noContraction'.
|
||||
if (isArithmeticOperation(node->getOp()) && node->getBasicType() != glslang::EbtInt) {
|
||||
node->getWritableType().getQualifier().noContraction = true;
|
||||
}
|
||||
// As this node is not an object node, need to traverse the children nodes.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Visits a unary node. A unary node can not be an object node. If the operation
|
||||
// is an arithmetic operation, need to mark this node as 'noContraction'.
|
||||
bool visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) override
|
||||
{
|
||||
// If this is an arithmetic operation, marks this with 'noContraction'
|
||||
if (isArithmeticOperation(node->getOp())) {
|
||||
node->getWritableType().getQualifier().noContraction = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Visits a symbol node. A symbol node is always an object node. So we
|
||||
// should always be able to find its in our collected mapping from object
|
||||
// nodes to access chains. As an object node, a symbol node can be either
|
||||
// 'precise' or containing 'precise' objects according to unused
|
||||
// access chain information we have when we visit this node.
|
||||
void visitSymbol(glslang::TIntermSymbol* node) override
|
||||
{
|
||||
// Symbol nodes are object nodes and should always have an
|
||||
// access chain collected before matches with it.
|
||||
assert(accesschain_mapping_.count(node));
|
||||
ObjectAccessChain new_precise_accesschain = accesschain_mapping_.at(node);
|
||||
// If the unused access chain is empty, this symbol node should be
|
||||
// marked as 'precise'. Otherwise, the unused access chain should be
|
||||
// appended to the symbol ID to build a new access chain which points to
|
||||
// the nested 'precise' object in this symbol object.
|
||||
if (remained_accesschain_.empty()) {
|
||||
node->getWritableType().getQualifier().noContraction = true;
|
||||
} else {
|
||||
new_precise_accesschain += ObjectAccesschainDelimiter + remained_accesschain_;
|
||||
}
|
||||
// Add the new 'precise' access chain to the work list and make sure we
|
||||
// don't visit it again.
|
||||
if (!added_precise_object_ids_.count(new_precise_accesschain)) {
|
||||
precise_objects_.insert(new_precise_accesschain);
|
||||
added_precise_object_ids_.insert(new_precise_accesschain);
|
||||
}
|
||||
}
|
||||
|
||||
// A set of precise objects, represented as access chains.
|
||||
ObjectAccesschainSet& precise_objects_;
|
||||
// Visited symbol nodes, should not revisit these nodes.
|
||||
ObjectAccesschainSet added_precise_object_ids_;
|
||||
// The left node of an assignment operation might be an parent of 'precise' objects.
|
||||
// This means the left node might not be an 'precise' object node, but it may contains
|
||||
// 'precise' qualifier which should be propagated to the corresponding child node in
|
||||
// the right. So we need the path from the left node to its nested 'precise' node to
|
||||
// tell us how to find the corresponding 'precise' node in the right.
|
||||
ObjectAccessChain remained_accesschain_;
|
||||
// A map from node pointers to their access chains.
|
||||
const AccessChainMapping& accesschain_mapping_;
|
||||
};
|
||||
}
|
||||
|
||||
namespace glslang {
|
||||
|
||||
void PropagateNoContraction(const glslang::TIntermediate& intermediate)
|
||||
{
|
||||
// First, traverses the AST, records symbols with their defining operations
|
||||
// and collects the initial set of precise symbols (symbol nodes that marked
|
||||
// as 'noContraction') and precise return nodes.
|
||||
auto mappings_and_precise_objects =
|
||||
getSymbolToDefinitionMappingAndPreciseSymbolIDs(intermediate);
|
||||
|
||||
// The mapping of symbol node IDs to their defining nodes. This enables us
|
||||
// to get the defining node directly from a given symbol ID without
|
||||
// traversing the tree again.
|
||||
NodeMapping& symbol_definition_mapping = std::get<0>(mappings_and_precise_objects);
|
||||
|
||||
// The mapping of object nodes to their access chains recorded.
|
||||
AccessChainMapping& accesschain_mapping = std::get<1>(mappings_and_precise_objects);
|
||||
|
||||
// The initial set of 'precise' objects which are represented as the
|
||||
// access chain toward them.
|
||||
ObjectAccesschainSet& precise_object_accesschains = std::get<2>(mappings_and_precise_objects);
|
||||
|
||||
// The set of 'precise' return nodes.
|
||||
ReturnBranchNodeSet& precise_return_nodes = std::get<3>(mappings_and_precise_objects);
|
||||
|
||||
// Second, uses the initial set of precise objects as a work list, pops an
|
||||
// access chain, extract the symbol ID from it. Then:
|
||||
// 1) Check the assignee object, see if it is 'precise' object node or
|
||||
// contains 'precise' object. Obtain the incremental access chain from the
|
||||
// assignee node to its nested 'precise' node (if any).
|
||||
// 2) If the assignee object node is 'precise' or it contains 'precise'
|
||||
// objects, traverses the right side of the assignment operation
|
||||
// expression to mark arithmetic operations as 'noContration' and update
|
||||
// 'precise' access chain work list with new found object nodes.
|
||||
// Repeat above steps until the work list is empty.
|
||||
TNoContractionAssigneeCheckingTraverser checker(accesschain_mapping);
|
||||
TNoContractionPropagator propagator(&precise_object_accesschains, accesschain_mapping);
|
||||
|
||||
// We have two initial precise work lists to handle:
|
||||
// 1) precise return nodes
|
||||
// 2) precise object access chains
|
||||
// We should process the precise return nodes first and the involved
|
||||
// objects in the return expression should be added to the precise object
|
||||
// access chain set.
|
||||
while (!precise_return_nodes.empty()) {
|
||||
glslang::TIntermBranch* precise_return_node = *precise_return_nodes.begin();
|
||||
propagator.propagateNoContractionInReturnNode(precise_return_node);
|
||||
precise_return_nodes.erase(precise_return_node);
|
||||
}
|
||||
|
||||
while (!precise_object_accesschains.empty()) {
|
||||
// Get the access chain of a precise object from the work list.
|
||||
ObjectAccessChain precise_object_accesschain = *precise_object_accesschains.begin();
|
||||
// Get the symbol id from the access chain.
|
||||
ObjectAccessChain symbol_id = getFrontElement(precise_object_accesschain);
|
||||
// Get all the defining nodes of that symbol ID.
|
||||
std::pair<NodeMapping::iterator, NodeMapping::iterator> range =
|
||||
symbol_definition_mapping.equal_range(symbol_id);
|
||||
// Visits all the assignment nodes of that symbol ID and
|
||||
// 1) Check if the assignee node is 'precise' or contains 'precise'
|
||||
// objects.
|
||||
// 2) Propagate the 'precise' to the top layer object nodes
|
||||
// in the right side of the assignment operation, update the 'precise'
|
||||
// work list with new access chains representing the new 'precise'
|
||||
// objects, and mark arithmetic operations as 'noContraction'.
|
||||
for (NodeMapping::iterator defining_node_iter = range.first;
|
||||
defining_node_iter != range.second; defining_node_iter++) {
|
||||
TIntermOperator* defining_node = defining_node_iter->second;
|
||||
// Check the assignee node.
|
||||
auto checker_result = checker.getPrecisenessAndRemainedAccessChain(
|
||||
defining_node, precise_object_accesschain);
|
||||
bool& contain_precise = std::get<0>(checker_result);
|
||||
ObjectAccessChain& remained_accesschain = std::get<1>(checker_result);
|
||||
// If the assignee node is 'precise' or contains 'precise', propagate the
|
||||
// 'precise' to the right. Otherwise just skip this assignment node.
|
||||
if (contain_precise) {
|
||||
propagator.propagateNoContractionInOneExpression(defining_node,
|
||||
remained_accesschain);
|
||||
}
|
||||
}
|
||||
// Remove the last processed 'precise' object from the work list.
|
||||
precise_object_accesschains.erase(precise_object_accesschain);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Copyright (C) 2015-2016 Google, Inc.
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
//
|
||||
// Visit the nodes in the glslang intermediate tree representation to
|
||||
// propagate 'noContraction' qualifier.
|
||||
//
|
||||
|
||||
#include "../Include/intermediate.h"
|
||||
|
||||
namespace glslang {
|
||||
|
||||
// Propagates the 'precise' qualifier for objects (objects marked with
|
||||
// 'noContraction' qualifier) from the shader source specified 'precise'
|
||||
// variables to all the involved objects, and add 'noContraction' qualifier for
|
||||
// the involved arithmetic operations.
|
||||
// Note that the same qualifier: 'noContraction' is used in both object nodes
|
||||
// and arithmetic operation nodes, but has different meaning. For object nodes,
|
||||
// 'noContraction' means the object is 'precise'; and for arithmetic operation
|
||||
// nodes, it means the operation should not be contracted.
|
||||
void PropagateNoContraction(const glslang::TIntermediate& intermediate);
|
||||
};
|
|
@ -0,0 +1,761 @@
|
|||
//
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "../Include/Common.h"
|
||||
#include "reflection.h"
|
||||
#include "localintermediate.h"
|
||||
|
||||
#include "gl_types.h"
|
||||
|
||||
//
|
||||
// Grow the reflection database through a friend traverser class of TReflection and a
|
||||
// collection of functions to do a liveness traversal that note what uniforms are used
|
||||
// in semantically non-dead code.
|
||||
//
|
||||
// Can be used multiple times, once per stage, to grow a program reflection.
|
||||
//
|
||||
// High-level algorithm for one stage:
|
||||
//
|
||||
// 1. Put main() on list of live functions.
|
||||
//
|
||||
// 2. Traverse any live function, while skipping if-tests with a compile-time constant
|
||||
// condition of false, and while adding any encountered function calls to the live
|
||||
// function list.
|
||||
//
|
||||
// Repeat until the live function list is empty.
|
||||
//
|
||||
// 3. Add any encountered uniform variables and blocks to the reflection database.
|
||||
//
|
||||
// Can be attempted with a failed link, but will return false if recursion had been detected, or
|
||||
// there wasn't exactly one main.
|
||||
//
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// The traverser: mostly pass through, except
|
||||
// - processing function-call nodes to push live functions onto the stack of functions to process
|
||||
// - processing binary nodes to see if they are dereferences of an aggregates to track
|
||||
// - processing symbol nodes to see if they are non-aggregate objects to track
|
||||
// - processing selection nodes to trim semantically dead code
|
||||
//
|
||||
// This is in the glslang namespace directly so it can be a friend of TReflection.
|
||||
//
|
||||
|
||||
class TLiveTraverser : public TIntermTraverser {
|
||||
public:
|
||||
TLiveTraverser(const TIntermediate& i, TReflection& r) : intermediate(i), reflection(r) { }
|
||||
|
||||
virtual bool visitAggregate(TVisit, TIntermAggregate* node);
|
||||
virtual bool visitBinary(TVisit, TIntermBinary* node);
|
||||
virtual void visitSymbol(TIntermSymbol* base);
|
||||
virtual bool visitSelection(TVisit, TIntermSelection* node);
|
||||
|
||||
// Track live funtions as well as uniforms, so that we don't visit dead functions
|
||||
// and only visit each function once.
|
||||
void addFunctionCall(TIntermAggregate* call)
|
||||
{
|
||||
// just use the map to ensure we process each function at most once
|
||||
if (reflection.nameToIndex.find(call->getName()) == reflection.nameToIndex.end()) {
|
||||
reflection.nameToIndex[call->getName()] = -1;
|
||||
pushFunction(call->getName());
|
||||
}
|
||||
}
|
||||
|
||||
// Add a simple reference to a uniform variable to the uniform database, no dereference involved.
|
||||
// However, no dereference doesn't mean simple... it could be a complex aggregate.
|
||||
void addUniform(const TIntermSymbol& base)
|
||||
{
|
||||
if (processedDerefs.find(&base) == processedDerefs.end()) {
|
||||
processedDerefs.insert(&base);
|
||||
|
||||
// Use a degenerate (empty) set of dereferences to immediately put as at the end of
|
||||
// the dereference change expected by blowUpActiveAggregate.
|
||||
TList<TIntermBinary*> derefs;
|
||||
blowUpActiveAggregate(base.getType(), base.getName(), derefs, derefs.end(), -1, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void addAttribute(const TIntermSymbol& base)
|
||||
{
|
||||
if (processedDerefs.find(&base) == processedDerefs.end()) {
|
||||
processedDerefs.insert(&base);
|
||||
|
||||
const TString &name = base.getName();
|
||||
const TType &type = base.getType();
|
||||
|
||||
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
|
||||
if (it == reflection.nameToIndex.end()) {
|
||||
reflection.nameToIndex[name] = (int)reflection.indexToAttribute.size();
|
||||
reflection.indexToAttribute.push_back(TObjectReflection(name, 0, mapToGlType(type), 0, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup or calculate the offset of a block member, using the recursively
|
||||
// defined block offset rules.
|
||||
int getOffset(const TType& type, int index)
|
||||
{
|
||||
const TTypeList& memberList = *type.getStruct();
|
||||
|
||||
// Don't calculate offset if one is present, it could be user supplied
|
||||
// and different than what would be calculated. That is, this is faster,
|
||||
// but not just an optimization.
|
||||
if (memberList[index].type->getQualifier().hasOffset())
|
||||
return memberList[index].type->getQualifier().layoutOffset;
|
||||
|
||||
int memberSize;
|
||||
int dummyStride;
|
||||
int offset = 0;
|
||||
for (int m = 0; m <= index; ++m) {
|
||||
// modify just the children's view of matrix layout, if there is one for this member
|
||||
TLayoutMatrix subMatrixLayout = memberList[m].type->getQualifier().layoutMatrix;
|
||||
int memberAlignment = intermediate.getBaseAlignment(*memberList[m].type, memberSize, dummyStride, type.getQualifier().layoutPacking == ElpStd140,
|
||||
subMatrixLayout != ElmNone ? subMatrixLayout == ElmRowMajor : type.getQualifier().layoutMatrix == ElmRowMajor);
|
||||
RoundToPow2(offset, memberAlignment);
|
||||
if (m < index)
|
||||
offset += memberSize;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// Calculate the block data size.
|
||||
// Block arrayness is not taken into account, each element is backed by a separate buffer.
|
||||
int getBlockSize(const TType& blockType)
|
||||
{
|
||||
const TTypeList& memberList = *blockType.getStruct();
|
||||
int lastIndex = (int)memberList.size() - 1;
|
||||
int lastOffset = getOffset(blockType, lastIndex);
|
||||
|
||||
int lastMemberSize;
|
||||
int dummyStride;
|
||||
intermediate.getBaseAlignment(*memberList[lastIndex].type, lastMemberSize, dummyStride, blockType.getQualifier().layoutPacking == ElpStd140,
|
||||
blockType.getQualifier().layoutMatrix == ElmRowMajor);
|
||||
|
||||
return lastOffset + lastMemberSize;
|
||||
}
|
||||
|
||||
// Traverse the provided deref chain, including the base, and
|
||||
// - build a full reflection-granularity name, array size, etc. entry out of it, if it goes down to that granularity
|
||||
// - recursively expand any variable array index in the middle of that traversal
|
||||
// - recursively expand what's left at the end if the deref chain did not reach down to reflection granularity
|
||||
//
|
||||
// arraySize tracks, just for the final dereference in the chain, if there was a specific known size.
|
||||
// A value of 0 for arraySize will mean to use the full array's size.
|
||||
void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList<TIntermBinary*>& derefs,
|
||||
TList<TIntermBinary*>::const_iterator deref, int offset, int blockIndex, int arraySize)
|
||||
{
|
||||
// process the part of the derefence chain that was explicit in the shader
|
||||
TString name = baseName;
|
||||
const TType* terminalType = &baseType;
|
||||
for (; deref != derefs.end(); ++deref) {
|
||||
TIntermBinary* visitNode = *deref;
|
||||
terminalType = &visitNode->getType();
|
||||
int index;
|
||||
switch (visitNode->getOp()) {
|
||||
case EOpIndexIndirect:
|
||||
// Visit all the indices of this array, and for each one add on the remaining dereferencing
|
||||
for (int i = 0; i < visitNode->getLeft()->getType().getOuterArraySize(); ++i) {
|
||||
TString newBaseName = name;
|
||||
if (baseType.getBasicType() != EbtBlock)
|
||||
newBaseName.append(TString("[") + String(i) + "]");
|
||||
TList<TIntermBinary*>::const_iterator nextDeref = deref;
|
||||
++nextDeref;
|
||||
TType derefType(*terminalType, 0);
|
||||
blowUpActiveAggregate(derefType, newBaseName, derefs, nextDeref, offset, blockIndex, arraySize);
|
||||
}
|
||||
|
||||
// it was all completed in the recursive calls above
|
||||
return;
|
||||
case EOpIndexDirect:
|
||||
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
if (baseType.getBasicType() != EbtBlock)
|
||||
name.append(TString("[") + String(index) + "]");
|
||||
break;
|
||||
case EOpIndexDirectStruct:
|
||||
index = visitNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
if (offset >= 0)
|
||||
offset += getOffset(visitNode->getLeft()->getType(), index);
|
||||
if (name.size() > 0)
|
||||
name.append(".");
|
||||
name.append((*visitNode->getLeft()->getType().getStruct())[index].type->getFieldName());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if the terminalType is still too coarse a granularity, this is still an aggregate to expand, expand it...
|
||||
if (! isReflectionGranularity(*terminalType)) {
|
||||
if (terminalType->isArray()) {
|
||||
// Visit all the indices of this array, and for each one,
|
||||
// fully explode the remaining aggregate to dereference
|
||||
for (int i = 0; i < terminalType->getOuterArraySize(); ++i) {
|
||||
TString newBaseName = name;
|
||||
newBaseName.append(TString("[") + String(i) + "]");
|
||||
TType derefType(*terminalType, 0);
|
||||
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
|
||||
}
|
||||
} else {
|
||||
// Visit all members of this aggregate, and for each one,
|
||||
// fully explode the remaining aggregate to dereference
|
||||
const TTypeList& typeList = *terminalType->getStruct();
|
||||
for (int i = 0; i < (int)typeList.size(); ++i) {
|
||||
TString newBaseName = name;
|
||||
newBaseName.append(TString(".") + typeList[i].type->getFieldName());
|
||||
TType derefType(*terminalType, i);
|
||||
blowUpActiveAggregate(derefType, newBaseName, derefs, derefs.end(), offset, blockIndex, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// it was all completed in the recursive calls above
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, add a full string to the reflection database, and update the array size if necessary.
|
||||
// If the derefenced entity to record is an array, compute the size and update the maximum size.
|
||||
|
||||
// there might not be a final array dereference, it could have been copied as an array object
|
||||
if (arraySize == 0)
|
||||
arraySize = mapToGlArraySize(*terminalType);
|
||||
|
||||
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
|
||||
if (it == reflection.nameToIndex.end()) {
|
||||
reflection.nameToIndex[name] = (int)reflection.indexToUniform.size();
|
||||
reflection.indexToUniform.push_back(TObjectReflection(name, offset, mapToGlType(*terminalType), arraySize, blockIndex));
|
||||
} else if (arraySize > 1) {
|
||||
int& reflectedArraySize = reflection.indexToUniform[it->second].size;
|
||||
reflectedArraySize = std::max(arraySize, reflectedArraySize);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a uniform dereference where blocks/struct/arrays are involved in the access.
|
||||
// Handles the situation where the left node is at the correct or too coarse a
|
||||
// granularity for reflection. (That is, further dereferences up the tree will be
|
||||
// skipped.) Earlier dereferences, down the tree, will be handled
|
||||
// at the same time, and logged to prevent reprocessing as the tree is traversed.
|
||||
//
|
||||
// Note: Other things like the following must be caught elsewhere:
|
||||
// - a simple non-array, non-struct variable (no dereference even conceivable)
|
||||
// - an aggregrate consumed en masse, without a dereference
|
||||
//
|
||||
// So, this code is for cases like
|
||||
// - a struct/block dereferencing a member (whether the member is array or not)
|
||||
// - an array of struct
|
||||
// - structs/arrays containing the above
|
||||
//
|
||||
void addDereferencedUniform(TIntermBinary* topNode)
|
||||
{
|
||||
// See if too fine-grained to process (wait to get further down the tree)
|
||||
const TType& leftType = topNode->getLeft()->getType();
|
||||
if ((leftType.isVector() || leftType.isMatrix()) && ! leftType.isArray())
|
||||
return;
|
||||
|
||||
// We have an array or structure or block dereference, see if it's a uniform
|
||||
// based dereference (if not, skip it).
|
||||
TIntermSymbol* base = findBase(topNode);
|
||||
if (! base || ! base->getQualifier().isUniformOrBuffer())
|
||||
return;
|
||||
|
||||
// See if we've already processed this (e.g., in the middle of something
|
||||
// we did earlier), and if so skip it
|
||||
if (processedDerefs.find(topNode) != processedDerefs.end())
|
||||
return;
|
||||
|
||||
// Process this uniform dereference
|
||||
|
||||
int offset = -1;
|
||||
int blockIndex = -1;
|
||||
bool anonymous = false;
|
||||
|
||||
// See if we need to record the block itself
|
||||
bool block = base->getBasicType() == EbtBlock;
|
||||
if (block) {
|
||||
offset = 0;
|
||||
anonymous = IsAnonymous(base->getName());
|
||||
if (base->getType().isArray()) {
|
||||
assert(! anonymous);
|
||||
for (int e = 0; e < base->getType().getCumulativeArraySize(); ++e)
|
||||
blockIndex = addBlockName(base->getType().getTypeName() + "[" + String(e) + "]", getBlockSize(base->getType()));
|
||||
} else
|
||||
blockIndex = addBlockName(base->getType().getTypeName(), getBlockSize(base->getType()));
|
||||
}
|
||||
|
||||
// Process the dereference chain, backward, accumulating the pieces for later forward traversal.
|
||||
// If the topNode is a reflection-granularity-array dereference, don't include that last dereference.
|
||||
TList<TIntermBinary*> derefs;
|
||||
for (TIntermBinary* visitNode = topNode; visitNode; visitNode = visitNode->getLeft()->getAsBinaryNode()) {
|
||||
if (isReflectionGranularity(visitNode->getLeft()->getType()))
|
||||
continue;
|
||||
|
||||
derefs.push_front(visitNode);
|
||||
processedDerefs.insert(visitNode);
|
||||
}
|
||||
processedDerefs.insert(base);
|
||||
|
||||
// See if we have a specific array size to stick to while enumerating the explosion of the aggregate
|
||||
int arraySize = 0;
|
||||
if (isReflectionGranularity(topNode->getLeft()->getType()) && topNode->getLeft()->isArray()) {
|
||||
if (topNode->getOp() == EOpIndexDirect)
|
||||
arraySize = topNode->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst() + 1;
|
||||
}
|
||||
|
||||
// Put the dereference chain together, forward
|
||||
TString baseName;
|
||||
if (! anonymous) {
|
||||
if (block)
|
||||
baseName = base->getType().getTypeName();
|
||||
else
|
||||
baseName = base->getName();
|
||||
}
|
||||
blowUpActiveAggregate(base->getType(), baseName, derefs, derefs.begin(), offset, blockIndex, arraySize);
|
||||
}
|
||||
|
||||
int addBlockName(const TString& name, int size)
|
||||
{
|
||||
int blockIndex;
|
||||
TReflection::TNameToIndex::const_iterator it = reflection.nameToIndex.find(name);
|
||||
if (reflection.nameToIndex.find(name) == reflection.nameToIndex.end()) {
|
||||
blockIndex = (int)reflection.indexToUniformBlock.size();
|
||||
reflection.nameToIndex[name] = blockIndex;
|
||||
reflection.indexToUniformBlock.push_back(TObjectReflection(name, -1, -1, size, -1));
|
||||
} else
|
||||
blockIndex = it->second;
|
||||
|
||||
return blockIndex;
|
||||
}
|
||||
|
||||
//
|
||||
// Given a function name, find its subroot in the tree, and push it onto the stack of
|
||||
// functions left to process.
|
||||
//
|
||||
void pushFunction(const TString& name)
|
||||
{
|
||||
TIntermSequence& globals = intermediate.getTreeRoot()->getAsAggregate()->getSequence();
|
||||
for (unsigned int f = 0; f < globals.size(); ++f) {
|
||||
TIntermAggregate* candidate = globals[f]->getAsAggregate();
|
||||
if (candidate && candidate->getOp() == EOpFunction && candidate->getName() == name) {
|
||||
functions.push_back(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Are we at a level in a dereference chain at which individual active uniform queries are made?
|
||||
bool isReflectionGranularity(const TType& type)
|
||||
{
|
||||
return type.getBasicType() != EbtBlock && type.getBasicType() != EbtStruct;
|
||||
}
|
||||
|
||||
// For a binary operation indexing into an aggregate, chase down the base of the aggregate.
|
||||
// Return 0 if the topology does not fit this situation.
|
||||
TIntermSymbol* findBase(const TIntermBinary* node)
|
||||
{
|
||||
TIntermSymbol *base = node->getLeft()->getAsSymbolNode();
|
||||
if (base)
|
||||
return base;
|
||||
TIntermBinary* left = node->getLeft()->getAsBinaryNode();
|
||||
if (! left)
|
||||
return nullptr;
|
||||
|
||||
return findBase(left);
|
||||
}
|
||||
|
||||
//
|
||||
// Translate a glslang sampler type into the GL API #define number.
|
||||
//
|
||||
int mapSamplerToGlType(TSampler sampler)
|
||||
{
|
||||
if (! sampler.image) {
|
||||
// a sampler...
|
||||
switch (sampler.type) {
|
||||
case EbtFloat:
|
||||
switch ((int)sampler.dim) {
|
||||
case Esd1D:
|
||||
switch ((int)sampler.shadow) {
|
||||
case false: return sampler.arrayed ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D;
|
||||
case true: return sampler.arrayed ? GL_SAMPLER_1D_ARRAY_SHADOW : GL_SAMPLER_1D_SHADOW;
|
||||
}
|
||||
case Esd2D:
|
||||
switch ((int)sampler.ms) {
|
||||
case false:
|
||||
switch ((int)sampler.shadow) {
|
||||
case false: return sampler.arrayed ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D;
|
||||
case true: return sampler.arrayed ? GL_SAMPLER_2D_ARRAY_SHADOW : GL_SAMPLER_2D_SHADOW;
|
||||
}
|
||||
case true: return sampler.arrayed ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_SAMPLER_2D_MULTISAMPLE;
|
||||
}
|
||||
case Esd3D:
|
||||
return GL_SAMPLER_3D;
|
||||
case EsdCube:
|
||||
switch ((int)sampler.shadow) {
|
||||
case false: return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE;
|
||||
case true: return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW : GL_SAMPLER_CUBE_SHADOW;
|
||||
}
|
||||
case EsdRect:
|
||||
return sampler.shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT;
|
||||
case EsdBuffer:
|
||||
return GL_SAMPLER_BUFFER;
|
||||
}
|
||||
case EbtInt:
|
||||
switch ((int)sampler.dim) {
|
||||
case Esd1D:
|
||||
return sampler.arrayed ? GL_INT_SAMPLER_1D_ARRAY : GL_INT_SAMPLER_1D;
|
||||
case Esd2D:
|
||||
switch ((int)sampler.ms) {
|
||||
case false: return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D;
|
||||
case true: return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_INT_SAMPLER_2D_MULTISAMPLE;
|
||||
}
|
||||
case Esd3D:
|
||||
return GL_INT_SAMPLER_3D;
|
||||
case EsdCube:
|
||||
return sampler.arrayed ? GL_INT_SAMPLER_CUBE_MAP_ARRAY : GL_INT_SAMPLER_CUBE;
|
||||
case EsdRect:
|
||||
return GL_INT_SAMPLER_2D_RECT;
|
||||
case EsdBuffer:
|
||||
return GL_INT_SAMPLER_BUFFER;
|
||||
}
|
||||
case EbtUint:
|
||||
switch ((int)sampler.dim) {
|
||||
case Esd1D:
|
||||
return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_1D_ARRAY : GL_UNSIGNED_INT_SAMPLER_1D;
|
||||
case Esd2D:
|
||||
switch ((int)sampler.ms) {
|
||||
case false: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D;
|
||||
case true: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE;
|
||||
}
|
||||
case Esd3D:
|
||||
return GL_UNSIGNED_INT_SAMPLER_3D;
|
||||
case EsdCube:
|
||||
return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_SAMPLER_CUBE;
|
||||
case EsdRect:
|
||||
return GL_UNSIGNED_INT_SAMPLER_2D_RECT;
|
||||
case EsdBuffer:
|
||||
return GL_UNSIGNED_INT_SAMPLER_BUFFER;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// an image...
|
||||
switch (sampler.type) {
|
||||
case EbtFloat:
|
||||
switch ((int)sampler.dim) {
|
||||
case Esd1D:
|
||||
return sampler.arrayed ? GL_IMAGE_1D_ARRAY : GL_IMAGE_1D;
|
||||
case Esd2D:
|
||||
switch ((int)sampler.ms) {
|
||||
case false: return sampler.arrayed ? GL_IMAGE_2D_ARRAY : GL_IMAGE_2D;
|
||||
case true: return sampler.arrayed ? GL_IMAGE_2D_MULTISAMPLE_ARRAY : GL_IMAGE_2D_MULTISAMPLE;
|
||||
}
|
||||
case Esd3D:
|
||||
return GL_IMAGE_3D;
|
||||
case EsdCube:
|
||||
return sampler.arrayed ? GL_IMAGE_CUBE_MAP_ARRAY : GL_IMAGE_CUBE;
|
||||
case EsdRect:
|
||||
return GL_IMAGE_2D_RECT;
|
||||
case EsdBuffer:
|
||||
return GL_IMAGE_BUFFER;
|
||||
}
|
||||
case EbtInt:
|
||||
switch ((int)sampler.dim) {
|
||||
case Esd1D:
|
||||
return sampler.arrayed ? GL_INT_IMAGE_1D_ARRAY : GL_INT_IMAGE_1D;
|
||||
case Esd2D:
|
||||
switch ((int)sampler.ms) {
|
||||
case false: return sampler.arrayed ? GL_INT_IMAGE_2D_ARRAY : GL_INT_IMAGE_2D;
|
||||
case true: return sampler.arrayed ? GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_INT_IMAGE_2D_MULTISAMPLE;
|
||||
}
|
||||
case Esd3D:
|
||||
return GL_INT_IMAGE_3D;
|
||||
case EsdCube:
|
||||
return sampler.arrayed ? GL_INT_IMAGE_CUBE_MAP_ARRAY : GL_INT_IMAGE_CUBE;
|
||||
case EsdRect:
|
||||
return GL_INT_IMAGE_2D_RECT;
|
||||
case EsdBuffer:
|
||||
return GL_INT_IMAGE_BUFFER;
|
||||
}
|
||||
case EbtUint:
|
||||
switch ((int)sampler.dim) {
|
||||
case Esd1D:
|
||||
return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_1D_ARRAY : GL_UNSIGNED_INT_IMAGE_1D;
|
||||
case Esd2D:
|
||||
switch ((int)sampler.ms) {
|
||||
case false: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D;
|
||||
case true: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE;
|
||||
}
|
||||
case Esd3D:
|
||||
return GL_UNSIGNED_INT_IMAGE_3D;
|
||||
case EsdCube:
|
||||
return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY : GL_UNSIGNED_INT_IMAGE_CUBE;
|
||||
case EsdRect:
|
||||
return GL_UNSIGNED_INT_IMAGE_2D_RECT;
|
||||
case EsdBuffer:
|
||||
return GL_UNSIGNED_INT_IMAGE_BUFFER;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Translate a glslang type into the GL API #define number.
|
||||
// Ignores arrayness.
|
||||
//
|
||||
int mapToGlType(const TType& type)
|
||||
{
|
||||
switch (type.getBasicType()) {
|
||||
case EbtSampler:
|
||||
return mapSamplerToGlType(type.getSampler());
|
||||
case EbtStruct:
|
||||
case EbtBlock:
|
||||
case EbtVoid:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (type.isVector()) {
|
||||
int offset = type.getVectorSize() - 2;
|
||||
switch (type.getBasicType()) {
|
||||
case EbtFloat: return GL_FLOAT_VEC2 + offset;
|
||||
case EbtDouble: return GL_DOUBLE_VEC2 + offset;
|
||||
case EbtInt: return GL_INT_VEC2 + offset;
|
||||
case EbtUint: return GL_UNSIGNED_INT_VEC2 + offset;
|
||||
case EbtInt64: return GL_INT64_ARB + offset;
|
||||
case EbtUint64: return GL_UNSIGNED_INT64_ARB + offset;
|
||||
case EbtBool: return GL_BOOL_VEC2 + offset;
|
||||
case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER + offset;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
if (type.isMatrix()) {
|
||||
switch (type.getBasicType()) {
|
||||
case EbtFloat:
|
||||
switch (type.getMatrixCols()) {
|
||||
case 2:
|
||||
switch (type.getMatrixRows()) {
|
||||
case 2: return GL_FLOAT_MAT2;
|
||||
case 3: return GL_FLOAT_MAT2x3;
|
||||
case 4: return GL_FLOAT_MAT2x4;
|
||||
default: return 0;
|
||||
}
|
||||
case 3:
|
||||
switch (type.getMatrixRows()) {
|
||||
case 2: return GL_FLOAT_MAT3x2;
|
||||
case 3: return GL_FLOAT_MAT3;
|
||||
case 4: return GL_FLOAT_MAT3x4;
|
||||
default: return 0;
|
||||
}
|
||||
case 4:
|
||||
switch (type.getMatrixRows()) {
|
||||
case 2: return GL_FLOAT_MAT4x2;
|
||||
case 3: return GL_FLOAT_MAT4x3;
|
||||
case 4: return GL_FLOAT_MAT4;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
case EbtDouble:
|
||||
switch (type.getMatrixCols()) {
|
||||
case 2:
|
||||
switch (type.getMatrixRows()) {
|
||||
case 2: return GL_DOUBLE_MAT2;
|
||||
case 3: return GL_DOUBLE_MAT2x3;
|
||||
case 4: return GL_DOUBLE_MAT2x4;
|
||||
default: return 0;
|
||||
}
|
||||
case 3:
|
||||
switch (type.getMatrixRows()) {
|
||||
case 2: return GL_DOUBLE_MAT3x2;
|
||||
case 3: return GL_DOUBLE_MAT3;
|
||||
case 4: return GL_DOUBLE_MAT3x4;
|
||||
default: return 0;
|
||||
}
|
||||
case 4:
|
||||
switch (type.getMatrixRows()) {
|
||||
case 2: return GL_DOUBLE_MAT4x2;
|
||||
case 3: return GL_DOUBLE_MAT4x3;
|
||||
case 4: return GL_DOUBLE_MAT4;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (type.getVectorSize() == 1) {
|
||||
switch (type.getBasicType()) {
|
||||
case EbtFloat: return GL_FLOAT;
|
||||
case EbtDouble: return GL_DOUBLE;
|
||||
case EbtInt: return GL_INT;
|
||||
case EbtUint: return GL_UNSIGNED_INT;
|
||||
case EbtInt64: return GL_INT64_ARB;
|
||||
case EbtUint64: return GL_UNSIGNED_INT64_ARB;
|
||||
case EbtBool: return GL_BOOL;
|
||||
case EbtAtomicUint: return GL_UNSIGNED_INT_ATOMIC_COUNTER;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mapToGlArraySize(const TType& type)
|
||||
{
|
||||
return type.isArray() ? type.getOuterArraySize() : 1;
|
||||
}
|
||||
|
||||
typedef std::list<TIntermAggregate*> TFunctionStack;
|
||||
TFunctionStack functions;
|
||||
const TIntermediate& intermediate;
|
||||
TReflection& reflection;
|
||||
std::set<const TIntermNode*> processedDerefs;
|
||||
|
||||
protected:
|
||||
TLiveTraverser(TLiveTraverser&);
|
||||
TLiveTraverser& operator=(TLiveTraverser&);
|
||||
};
|
||||
|
||||
//
|
||||
// Implement the traversal functions of interest.
|
||||
//
|
||||
|
||||
// To catch which function calls are not dead, and hence which functions must be visited.
|
||||
bool TLiveTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node)
|
||||
{
|
||||
if (node->getOp() == EOpFunctionCall)
|
||||
addFunctionCall(node);
|
||||
|
||||
return true; // traverse this subtree
|
||||
}
|
||||
|
||||
// To catch dereferenced aggregates that must be reflected.
|
||||
// This catches them at the highest level possible in the tree.
|
||||
bool TLiveTraverser::visitBinary(TVisit /* visit */, TIntermBinary* node)
|
||||
{
|
||||
switch (node->getOp()) {
|
||||
case EOpIndexDirect:
|
||||
case EOpIndexIndirect:
|
||||
case EOpIndexDirectStruct:
|
||||
addDereferencedUniform(node);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// still need to visit everything below, which could contain sub-expressions
|
||||
// containing different uniforms
|
||||
return true;
|
||||
}
|
||||
|
||||
// To reflect non-dereferenced objects.
|
||||
void TLiveTraverser::visitSymbol(TIntermSymbol* base)
|
||||
{
|
||||
if (base->getQualifier().storage == EvqUniform)
|
||||
addUniform(*base);
|
||||
|
||||
if (intermediate.getStage() == EShLangVertex && base->getQualifier().isPipeInput())
|
||||
addAttribute(*base);
|
||||
}
|
||||
|
||||
// To prune semantically dead paths.
|
||||
bool TLiveTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node)
|
||||
{
|
||||
TIntermConstantUnion* constant = node->getCondition()->getAsConstantUnion();
|
||||
if (constant) {
|
||||
// cull the path that is dead
|
||||
if (constant->getConstArray()[0].getBConst() == true && node->getTrueBlock())
|
||||
node->getTrueBlock()->traverse(this);
|
||||
if (constant->getConstArray()[0].getBConst() == false && node->getFalseBlock())
|
||||
node->getFalseBlock()->traverse(this);
|
||||
|
||||
return false; // don't traverse any more, we did it all above
|
||||
} else
|
||||
return true; // traverse the whole subtree
|
||||
}
|
||||
|
||||
//
|
||||
// Implement TReflection methods.
|
||||
//
|
||||
|
||||
// Merge live symbols from 'intermediate' into the existing reflection database.
|
||||
//
|
||||
// Returns false if the input is too malformed to do this.
|
||||
bool TReflection::addStage(EShLanguage, const TIntermediate& intermediate)
|
||||
{
|
||||
if (intermediate.getNumMains() != 1 || intermediate.isRecursive())
|
||||
return false;
|
||||
|
||||
TLiveTraverser it(intermediate, *this);
|
||||
|
||||
// put main() on functions to process
|
||||
it.pushFunction("main(");
|
||||
|
||||
// process all the functions
|
||||
while (! it.functions.empty()) {
|
||||
TIntermNode* function = it.functions.back();
|
||||
it.functions.pop_back();
|
||||
function->traverse(&it);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TReflection::dump()
|
||||
{
|
||||
printf("Uniform reflection:\n");
|
||||
for (size_t i = 0; i < indexToUniform.size(); ++i)
|
||||
indexToUniform[i].dump();
|
||||
printf("\n");
|
||||
|
||||
printf("Uniform block reflection:\n");
|
||||
for (size_t i = 0; i < indexToUniformBlock.size(); ++i)
|
||||
indexToUniformBlock[i].dump();
|
||||
printf("\n");
|
||||
|
||||
printf("Vertex attribute reflection:\n");
|
||||
for (size_t i = 0; i < indexToAttribute.size(); ++i)
|
||||
indexToAttribute[i].dump();
|
||||
printf("\n");
|
||||
|
||||
//printf("Live names\n");
|
||||
//for (TNameToIndex::const_iterator it = nameToIndex.begin(); it != nameToIndex.end(); ++it)
|
||||
// printf("%s: %d\n", it->first.c_str(), it->second);
|
||||
//printf("\n");
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
//Copyright (C) 2013 LunarG, Inc.
|
||||
//
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef _REFLECTION_INCLUDED
|
||||
#define _REFLECTION_INCLUDED
|
||||
|
||||
#include "../Public/ShaderLang.h"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
//
|
||||
// A reflection database and its interface, consistent with the OpenGL API reflection queries.
|
||||
//
|
||||
|
||||
namespace glslang {
|
||||
|
||||
class TIntermediate;
|
||||
class TIntermAggregate;
|
||||
class TLiveTraverser;
|
||||
|
||||
// Data needed for just a single object at the granularity exchanged by the reflection API
|
||||
class TObjectReflection {
|
||||
public:
|
||||
TObjectReflection(const TString& pName, int pOffset, int pGLDefineType, int pSize, int pIndex) :
|
||||
name(pName), offset(pOffset), glDefineType(pGLDefineType), size(pSize), index(pIndex) { }
|
||||
void dump() const { printf("%s: offset %d, type %x, size %d, index %d\n", name.c_str(), offset, glDefineType, size, index); }
|
||||
TString name;
|
||||
int offset;
|
||||
int glDefineType;
|
||||
int size; // data size in bytes for a block, array size for a (non-block) object that's an array
|
||||
int index;
|
||||
};
|
||||
|
||||
// The full reflection database
|
||||
class TReflection {
|
||||
public:
|
||||
TReflection() : badReflection("__bad__", -1, -1, -1, -1) {}
|
||||
virtual ~TReflection() {}
|
||||
|
||||
// grow the reflection stage by stage
|
||||
bool addStage(EShLanguage, const TIntermediate&);
|
||||
|
||||
// for mapping a uniform index to a uniform object's description
|
||||
int getNumUniforms() { return (int)indexToUniform.size(); }
|
||||
const TObjectReflection& getUniform(int i) const
|
||||
{
|
||||
if (i >= 0 && i < (int)indexToUniform.size())
|
||||
return indexToUniform[i];
|
||||
else
|
||||
return badReflection;
|
||||
}
|
||||
|
||||
// for mapping a block index to the block's description
|
||||
int getNumUniformBlocks() const { return (int)indexToUniformBlock.size(); }
|
||||
const TObjectReflection& getUniformBlock(int i) const
|
||||
{
|
||||
if (i >= 0 && i < (int)indexToUniformBlock.size())
|
||||
return indexToUniformBlock[i];
|
||||
else
|
||||
return badReflection;
|
||||
}
|
||||
|
||||
// for mapping an attribute index to the attribute's description
|
||||
int getNumAttributes() { return (int)indexToAttribute.size(); }
|
||||
const TObjectReflection& getAttribute(int i) const
|
||||
{
|
||||
if (i >= 0 && i < (int)indexToAttribute.size())
|
||||
return indexToAttribute[i];
|
||||
else
|
||||
return badReflection;
|
||||
}
|
||||
|
||||
// for mapping any name to its index (block names, uniform names and attribute names)
|
||||
int getIndex(const char* name) const
|
||||
{
|
||||
TNameToIndex::const_iterator it = nameToIndex.find(name);
|
||||
if (it == nameToIndex.end())
|
||||
return -1;
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void dump();
|
||||
|
||||
protected:
|
||||
friend class glslang::TLiveTraverser;
|
||||
|
||||
// Need a TString hash: typedef std::unordered_map<TString, int> TNameToIndex;
|
||||
typedef std::map<TString, int> TNameToIndex;
|
||||
typedef std::vector<TObjectReflection> TMapIndexToReflection;
|
||||
|
||||
TObjectReflection badReflection; // return for queries of -1 or generally out of range; has expected descriptions with in it for this
|
||||
TNameToIndex nameToIndex; // maps names to indexes; can hold all types of data: uniform/buffer and which function names have been processed
|
||||
TMapIndexToReflection indexToUniform;
|
||||
TMapIndexToReflection indexToUniformBlock;
|
||||
TMapIndexToReflection indexToAttribute;
|
||||
};
|
||||
|
||||
} // end namespace glslang
|
||||
|
||||
#endif // _REFLECTION_INCLUDED
|
|
@ -0,0 +1,5 @@
|
|||
add_library(OSDependent STATIC ossource.cpp ../osinclude.h)
|
||||
set_property(TARGET OSDependent PROPERTY FOLDER glslang)
|
||||
|
||||
install(TARGETS OSDependent
|
||||
ARCHIVE DESTINATION lib)
|
|
@ -0,0 +1,190 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
//
|
||||
// This file contains the Linux-specific functions
|
||||
//
|
||||
#include "../osinclude.h"
|
||||
#include "../../../OGLCompilersDLL/InitializeDll.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace glslang {
|
||||
|
||||
//
|
||||
// Thread cleanup
|
||||
//
|
||||
|
||||
//
|
||||
// Wrapper for Linux call to DetachThread. This is required as pthread_cleanup_push() expects
|
||||
// the cleanup routine to return void.
|
||||
//
|
||||
static void DetachThreadLinux(void *)
|
||||
{
|
||||
DetachThread();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Registers cleanup handler, sets cancel type and state, and executes the thread specific
|
||||
// cleanup handler. This function will be called in the Standalone.cpp for regression
|
||||
// testing. When OpenGL applications are run with the driver code, Linux OS does the
|
||||
// thread cleanup.
|
||||
//
|
||||
void OS_CleanupThreadData(void)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
DetachThreadLinux(NULL);
|
||||
#else
|
||||
int old_cancel_state, old_cancel_type;
|
||||
void *cleanupArg = NULL;
|
||||
|
||||
//
|
||||
// Set thread cancel state and push cleanup handler.
|
||||
//
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
|
||||
pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg);
|
||||
|
||||
//
|
||||
// Put the thread in deferred cancellation mode.
|
||||
//
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type);
|
||||
|
||||
//
|
||||
// Pop cleanup handler and execute it prior to unregistering the cleanup handler.
|
||||
//
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
//
|
||||
// Restore the thread's previous cancellation mode.
|
||||
//
|
||||
pthread_setcanceltype(old_cancel_state, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Thread Local Storage Operations
|
||||
//
|
||||
inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key)
|
||||
{
|
||||
return (OS_TLSIndex)((uintptr_t)key + 1);
|
||||
}
|
||||
|
||||
inline pthread_key_t TLSIndexToPthreadKey(OS_TLSIndex nIndex)
|
||||
{
|
||||
return (pthread_key_t)((uintptr_t)nIndex - 1);
|
||||
}
|
||||
|
||||
OS_TLSIndex OS_AllocTLSIndex()
|
||||
{
|
||||
pthread_key_t pPoolIndex;
|
||||
|
||||
//
|
||||
// Create global pool key.
|
||||
//
|
||||
if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
|
||||
assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
|
||||
return OS_INVALID_TLS_INDEX;
|
||||
}
|
||||
else
|
||||
return PthreadKeyToTLSIndex(pPoolIndex);
|
||||
}
|
||||
|
||||
|
||||
bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
|
||||
{
|
||||
if (nIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pthread_setspecific(TLSIndexToPthreadKey(nIndex), lpvValue) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void* OS_GetTLSValue(OS_TLSIndex nIndex)
|
||||
{
|
||||
//
|
||||
// This function should return 0 if nIndex is invalid.
|
||||
//
|
||||
assert(nIndex != OS_INVALID_TLS_INDEX);
|
||||
return pthread_getspecific(TLSIndexToPthreadKey(nIndex));
|
||||
}
|
||||
|
||||
bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
|
||||
{
|
||||
if (nIndex == OS_INVALID_TLS_INDEX) {
|
||||
assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Delete the global pool key.
|
||||
//
|
||||
if (pthread_key_delete(TLSIndexToPthreadKey(nIndex)) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: non-windows: if we need these on linux, flesh them out
|
||||
void InitGlobalLock() { }
|
||||
void GetGlobalLock() { }
|
||||
void ReleaseGlobalLock() { }
|
||||
|
||||
void* OS_CreateThread(TThreadEntrypoint entry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OS_WaitForAllThreads(void* threads, int numThreads)
|
||||
{
|
||||
}
|
||||
|
||||
void OS_Sleep(int milliseconds)
|
||||
{
|
||||
}
|
||||
|
||||
void OS_DumpMemoryCounters()
|
||||
{
|
||||
}
|
||||
|
||||
} // end namespace glslang
|
|
@ -0,0 +1,17 @@
|
|||
set(SOURCES ossource.cpp ../osinclude.h)
|
||||
|
||||
add_library(OSDependent STATIC ${SOURCES})
|
||||
set_property(TARGET OSDependent PROPERTY FOLDER glslang)
|
||||
|
||||
# MinGW GCC complains about function pointer casts to void*.
|
||||
# Turn that off with -fpermissive.
|
||||
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
|
||||
target_compile_options(OSDependent PRIVATE -fpermissive)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
source_group("Source" FILES ${SOURCES})
|
||||
endif(WIN32)
|
||||
|
||||
install(TARGETS OSDependent
|
||||
ARCHIVE DESTINATION lib)
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
|
||||
//All rights reserved.
|
||||
//
|
||||
//Redistribution and use in source and binary forms, with or without
|
||||
//modification, are permitted provided that the following conditions
|
||||
//are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
//
|
||||
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
//"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
//LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
//FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
//COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
//INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
//CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
//ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
//POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "InitializeDll.h"
|
||||
|
||||
#define STRICT
|
||||
#define VC_EXTRALEAN 1
|
||||
#include <windows.h>
|
||||
#include <assert.h>
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
|
||||
if (! glslang::InitProcess())
|
||||
return FALSE;
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
|
||||
if (! glslang::InitThread())
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
|
||||
if (! glslang::DetachThread())
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
|
||||
glslang::DetachProcess();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0 && "DllMain(): Reason for calling DLL Main is unknown");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue