Add validation for execution modes

* Check rules from Execution Mode tables, 2.16.2 and the Vulkan
environment spec

* Allows MeshNV execution model with the following execution modes
 * LocalSize, LocalSizeId, OutputPoints and OutputVertices
 * Done to not break their validation
This commit is contained in:
Alan Baker 2018-09-28 16:41:56 -04:00
parent 146eb3bdcf
commit a77bb2e54b
33 changed files with 1317 additions and 18 deletions

View File

@ -17,6 +17,7 @@
#include <algorithm>
#include "source/opcode.h"
#include "source/spirv_target_env.h"
#include "source/val/instruction.h"
#include "source/val/validation_state.h"
@ -53,6 +54,171 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) {
<< "OpEntryPoint Entry Point <id> '" << _.getIdName(entry_point_id)
<< "'s function return type is not void.";
}
const auto* execution_modes = _.GetExecutionModes(entry_point_id);
if (_.HasCapability(SpvCapabilityShader)) {
switch (execution_model) {
case SpvExecutionModelFragment:
if (execution_modes &&
execution_modes->count(SpvExecutionModeOriginUpperLeft) &&
execution_modes->count(SpvExecutionModeOriginLowerLeft)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Fragment execution model entry points can only specify "
"one of OriginUpperLeft or OriginLowerLeft execution "
"modes.";
}
if (!execution_modes ||
(!execution_modes->count(SpvExecutionModeOriginUpperLeft) &&
!execution_modes->count(SpvExecutionModeOriginLowerLeft))) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Fragment execution model entry points require either an "
"OriginUpperLeft or OriginLowerLeft execution mode.";
}
if (execution_modes &&
1 < std::count_if(execution_modes->begin(), execution_modes->end(),
[](const SpvExecutionMode& mode) {
switch (mode) {
case SpvExecutionModeDepthGreater:
case SpvExecutionModeDepthLess:
case SpvExecutionModeDepthUnchanged:
return true;
default:
return false;
}
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Fragment execution model entry points can specify at most "
"one of DepthGreater, DepthLess or DepthUnchanged "
"execution modes.";
}
break;
case SpvExecutionModelTessellationControl:
case SpvExecutionModelTessellationEvaluation:
if (execution_modes &&
1 < std::count_if(execution_modes->begin(), execution_modes->end(),
[](const SpvExecutionMode& mode) {
switch (mode) {
case SpvExecutionModeSpacingEqual:
case SpvExecutionModeSpacingFractionalEven:
case SpvExecutionModeSpacingFractionalOdd:
return true;
default:
return false;
}
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Tessellation execution model entry points can specify at "
"most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes.";
}
if (execution_modes &&
1 < std::count_if(execution_modes->begin(), execution_modes->end(),
[](const SpvExecutionMode& mode) {
switch (mode) {
case SpvExecutionModeTriangles:
case SpvExecutionModeQuads:
case SpvExecutionModeIsolines:
return true;
default:
return false;
}
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Tessellation execution model entry points can specify at "
"most one of Triangles, Quads or Isolines execution modes.";
}
if (execution_modes &&
1 < std::count_if(execution_modes->begin(), execution_modes->end(),
[](const SpvExecutionMode& mode) {
switch (mode) {
case SpvExecutionModeVertexOrderCw:
case SpvExecutionModeVertexOrderCcw:
return true;
default:
return false;
}
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Tessellation execution model entry points can specify at "
"most one of VertexOrderCw or VertexOrderCcw execution "
"modes.";
}
break;
case SpvExecutionModelGeometry:
if (!execution_modes ||
1 != std::count_if(execution_modes->begin(), execution_modes->end(),
[](const SpvExecutionMode& mode) {
switch (mode) {
case SpvExecutionModeInputPoints:
case SpvExecutionModeInputLines:
case SpvExecutionModeInputLinesAdjacency:
case SpvExecutionModeTriangles:
case SpvExecutionModeInputTrianglesAdjacency:
return true;
default:
return false;
}
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Geometry execution model entry points must specify "
"exactly one of InputPoints, InputLines, "
"InputLinesAdjacency, Triangles or InputTrianglesAdjacency "
"execution modes.";
}
if (!execution_modes ||
1 != std::count_if(execution_modes->begin(), execution_modes->end(),
[](const SpvExecutionMode& mode) {
switch (mode) {
case SpvExecutionModeOutputPoints:
case SpvExecutionModeOutputLineStrip:
case SpvExecutionModeOutputTriangleStrip:
return true;
default:
return false;
}
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Geometry execution model entry points must specify "
"exactly one of OutputPoints, OutputLineStrip or "
"OutputTriangleStrip execution modes.";
}
break;
default:
break;
}
}
if (spvIsVulkanEnv(_.context()->target_env)) {
switch (execution_model) {
case SpvExecutionModelGLCompute:
if (!execution_modes ||
!execution_modes->count(SpvExecutionModeLocalSize)) {
bool ok = false;
for (auto& i : _.ordered_instructions()) {
if (i.opcode() == SpvOpDecorate) {
if (i.operands().size() > 2) {
if (i.GetOperandAs<SpvDecoration>(1) == SpvDecorationBuiltIn &&
i.GetOperandAs<SpvBuiltIn>(2) == SpvBuiltInWorkgroupSize) {
ok = true;
break;
}
}
}
}
if (!ok) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "In the Vulkan environment, GLCompute execution model "
"entry points require either the LocalSize execution "
"mode or an object decorated with WorkgroupSize must be "
"specified.";
}
}
break;
default:
break;
}
}
return SPV_SUCCESS;
}
@ -68,6 +234,182 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _,
<< "' is not the Entry Point "
"operand of an OpEntryPoint.";
}
const auto mode = inst->GetOperandAs<SpvExecutionMode>(1);
const auto* models = _.GetExecutionModels(entry_point_id);
switch (mode) {
case SpvExecutionModeInvocations:
case SpvExecutionModeInputPoints:
case SpvExecutionModeInputLines:
case SpvExecutionModeInputLinesAdjacency:
case SpvExecutionModeInputTrianglesAdjacency:
case SpvExecutionModeOutputLineStrip:
case SpvExecutionModeOutputTriangleStrip:
if (!std::all_of(models->begin(), models->end(),
[](const SpvExecutionModel& model) {
return model == SpvExecutionModelGeometry;
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with the Geometry execution "
"model.";
}
break;
case SpvExecutionModeOutputPoints:
if (!std::all_of(models->begin(), models->end(),
[&_](const SpvExecutionModel& model) {
switch (model) {
case SpvExecutionModelGeometry:
return true;
case SpvExecutionModelMeshNV:
return _.HasCapability(SpvCapabilityMeshShadingNV);
default:
return false;
}
})) {
if (_.HasCapability(SpvCapabilityMeshShadingNV)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with the Geometry or "
"MeshNV execution model.";
} else {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with the Geometry "
"execution "
"model.";
}
}
break;
case SpvExecutionModeSpacingEqual:
case SpvExecutionModeSpacingFractionalEven:
case SpvExecutionModeSpacingFractionalOdd:
case SpvExecutionModeVertexOrderCw:
case SpvExecutionModeVertexOrderCcw:
case SpvExecutionModePointMode:
case SpvExecutionModeQuads:
case SpvExecutionModeIsolines:
if (!std::all_of(
models->begin(), models->end(),
[](const SpvExecutionModel& model) {
return (model == SpvExecutionModelTessellationControl) ||
(model == SpvExecutionModelTessellationEvaluation);
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with a tessellation "
"execution model.";
}
break;
case SpvExecutionModeTriangles:
if (!std::all_of(models->begin(), models->end(),
[](const SpvExecutionModel& model) {
switch (model) {
case SpvExecutionModelGeometry:
case SpvExecutionModelTessellationControl:
case SpvExecutionModelTessellationEvaluation:
return true;
default:
return false;
}
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with a Geometry or "
"tessellation execution model.";
}
break;
case SpvExecutionModeOutputVertices:
if (!std::all_of(models->begin(), models->end(),
[&_](const SpvExecutionModel& model) {
switch (model) {
case SpvExecutionModelGeometry:
case SpvExecutionModelTessellationControl:
case SpvExecutionModelTessellationEvaluation:
return true;
case SpvExecutionModelMeshNV:
return _.HasCapability(SpvCapabilityMeshShadingNV);
default:
return false;
}
})) {
if (_.HasCapability(SpvCapabilityMeshShadingNV)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with a Geometry, "
"tessellation or MeshNV execution model.";
} else {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with a Geometry or "
"tessellation execution model.";
}
}
break;
case SpvExecutionModePixelCenterInteger:
case SpvExecutionModeOriginUpperLeft:
case SpvExecutionModeOriginLowerLeft:
case SpvExecutionModeEarlyFragmentTests:
case SpvExecutionModeDepthReplacing:
case SpvExecutionModeDepthLess:
case SpvExecutionModeDepthUnchanged:
if (!std::all_of(models->begin(), models->end(),
[](const SpvExecutionModel& model) {
return model == SpvExecutionModelFragment;
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with the Fragment execution "
"model.";
}
break;
case SpvExecutionModeLocalSizeHint:
case SpvExecutionModeVecTypeHint:
case SpvExecutionModeContractionOff:
case SpvExecutionModeLocalSizeHintId:
if (!std::all_of(models->begin(), models->end(),
[](const SpvExecutionModel& model) {
return model == SpvExecutionModelKernel;
})) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with the Kernel execution "
"model.";
}
break;
case SpvExecutionModeLocalSize:
case SpvExecutionModeLocalSizeId:
if (!std::all_of(models->begin(), models->end(),
[&_](const SpvExecutionModel& model) {
switch (model) {
case SpvExecutionModelKernel:
case SpvExecutionModelGLCompute:
return true;
case SpvExecutionModelMeshNV:
return _.HasCapability(SpvCapabilityMeshShadingNV);
default:
return false;
}
})) {
if (_.HasCapability(SpvCapabilityMeshShadingNV)) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with a Kernel, GLCompute "
"or MeshNV execution model.";
} else {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Execution mode can only be used with a Kernel or "
"GLCompute "
"execution model.";
}
}
default:
break;
}
if (spvIsVulkanEnv(_.context()->target_env)) {
if (mode == SpvExecutionModeOriginLowerLeft) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "In the Vulkan environment, the OriginLowerLeft execution mode "
"must not be used.";
}
if (mode == SpvExecutionModePixelCenterInteger) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "In the Vulkan environment, the PixelCenterInteger execution "
"mode must not be used.";
}
}
return SPV_SUCCESS;
}
@ -79,6 +421,7 @@ spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) {
if (auto error = ValidateEntryPoint(_, inst)) return error;
break;
case SpvOpExecutionMode:
case SpvOpExecutionModeId:
if (auto error = ValidateExecutionMode(_, inst)) return error;
break;
default:

View File

@ -5523,6 +5523,7 @@ TEST_F(AggressiveDCETest, SafelyRemoveDecorateString) {
OpExtension "SPV_GOOGLE_hlsl_functionality1"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "main"
OpExecutionMode %1 OriginUpperLeft
)";
const std::string body_before =

View File

@ -287,6 +287,7 @@ TEST_F(BlockMergeTest, PhiInSuccessorOfMergedBlock) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -324,6 +325,7 @@ TEST_F(BlockMergeTest, UpdateMergeInstruction) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -358,6 +360,7 @@ TEST_F(BlockMergeTest, TwoMergeBlocksCannotBeMerged) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -398,6 +401,7 @@ TEST_F(BlockMergeTest, MergeContinue) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -431,6 +435,7 @@ TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -532,6 +537,7 @@ TEST_F(BlockMergeTest, DontMergeKill) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%functy = OpTypeFunction %void
@ -564,6 +570,7 @@ TEST_F(BlockMergeTest, DontMergeUnreachable) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%functy = OpTypeFunction %void
@ -596,6 +603,7 @@ TEST_F(BlockMergeTest, DontMergeReturn) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%functy = OpTypeFunction %void
@ -628,6 +636,7 @@ TEST_F(BlockMergeTest, DontMergeSwitch) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%int = OpTypeInt 32 1
@ -664,6 +673,7 @@ TEST_F(BlockMergeTest, DontMergeReturnValue) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%functy = OpTypeFunction %void
@ -705,6 +715,7 @@ TEST_F(BlockMergeTest, MergeHeaders) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%functy = OpTypeFunction %void

View File

@ -589,6 +589,7 @@ TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func" %in
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%int = OpTypeInt 32 1
@ -743,6 +744,7 @@ TEST_F(CCPTest, NullBranchCondition) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%int = OpTypeInt 32 1
@ -774,6 +776,7 @@ TEST_F(CCPTest, UndefBranchCondition) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%int = OpTypeInt 32 1
@ -805,6 +808,7 @@ TEST_F(CCPTest, NullSwitchCondition) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%int = OpTypeInt 32 1
%null = OpConstantNull %int
@ -835,6 +839,7 @@ TEST_F(CCPTest, UndefSwitchCondition) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%int = OpTypeInt 32 1
%undef = OpUndef %int
@ -865,6 +870,7 @@ TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func" %in
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%int = OpTypeInt 32 1
%bool = OpTypeBool

View File

@ -91,6 +91,7 @@ TEST_F(CFGCleanupTest, RemoveDecorations) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %x "x"
OpName %dead "dead"
@ -123,6 +124,7 @@ TEST_F(CFGCleanupTest, RemoveDecorations) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %x "x"
OpDecorate %x RelaxedPrecision
@ -153,6 +155,7 @@ TEST_F(CFGCleanupTest, UpdatePhis) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %y %outparm
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %y "y"
OpName %outparm "outparm"
@ -194,6 +197,7 @@ TEST_F(CFGCleanupTest, UpdatePhis) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %y %outparm
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %y "y"
OpName %outparm "outparm"
@ -272,6 +276,7 @@ TEST_F(CFGCleanupTest, RemovePhiArgsFromFarBlocks) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %y %outparm
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %y "y"
OpName %outparm "outparm"
@ -319,6 +324,7 @@ TEST_F(CFGCleanupTest, RemovePhiArgsFromFarBlocks) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %y %outparm
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %y "y"
OpName %outparm "outparm"
@ -370,6 +376,7 @@ TEST_F(CFGCleanupTest, RemovePhiConstantArgs) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %y %outparm
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %y "y"
OpName %outparm "outparm"
@ -410,6 +417,7 @@ TEST_F(CFGCleanupTest, RemovePhiConstantArgs) {
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %y %outparm
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %y "y"
OpName %outparm "outparm"

View File

@ -38,6 +38,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -71,6 +72,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -104,6 +106,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -139,6 +142,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -177,6 +181,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -219,6 +224,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -255,6 +261,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -289,6 +296,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -326,6 +334,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -361,6 +370,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -399,6 +409,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -435,6 +446,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -468,6 +480,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -505,6 +518,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -543,6 +557,7 @@ OpCapability Addresses
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -579,6 +594,7 @@ OpCapability Addresses
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -616,6 +632,7 @@ OpCapability Addresses
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -646,6 +663,7 @@ TEST_F(CombineAccessChainsTest, NoIndexAccessChains) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%ptr_Workgroup_uint = OpTypePointer Workgroup %uint
@ -673,6 +691,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -700,6 +719,7 @@ OpCapability VariablePointers
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
@ -729,6 +749,7 @@ OpCapability Addresses
OpExtension "SPV_KHR_variable_pointers"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%int = OpTypeInt 32 1

View File

@ -2018,6 +2018,7 @@ TEST_F(DeadBranchElimTest, ReorderBlocks) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -2045,6 +2046,7 @@ TEST_F(DeadBranchElimTest, ReorderBlocksMultiple) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -2073,6 +2075,7 @@ TEST_F(DeadBranchElimTest, ReorderBlocksMultiple2) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool

View File

@ -31,6 +31,7 @@ std::string PreambleAssembly() {
R"(OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %hue %saturation %value
OpExecutionMode %main OriginUpperLeft
OpName %main "main"
OpName %void_fn "void_fn"
OpName %hue "hue"

View File

@ -2601,6 +2601,7 @@ TEST_F(InlineTest, OpKill) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%voidfuncty = OpTypeFunction %void
%main = OpFunction %void None %voidfuncty
@ -2630,6 +2631,7 @@ TEST_F(InlineTest, OpKillWithTrailingInstructions) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -2679,6 +2681,7 @@ TEST_F(InlineTest, OpKillInIf) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -2731,6 +2734,7 @@ TEST_F(InlineTest, OpKillInLoop) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool

View File

@ -1084,7 +1084,7 @@ TEST_F(VectorDCETest, VectorIntoCompositeConstruct) {
const std::string text = R"(OpCapability Linkage
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %1 "EntryPoint_Main" %2 %3
OpEntryPoint Fragment %1 "EntryPoint_Main" %2 %3
OpExecutionMode %1 OriginUpperLeft
OpDecorate %2 Location 0
OpDecorate %_struct_4 Block

View File

@ -54,6 +54,7 @@ add_spvtools_unittest(TARGET val_ijklmnop
val_layout_test.cpp
val_literals_test.cpp
val_logicals_test.cpp
val_modes_test.cpp
val_non_uniform_test.cpp
val_primitives_test.cpp
${VAL_TEST_COMMON_SRCS}

View File

@ -34,6 +34,7 @@ TEST_F(ValidateAdjacency, OpPhiBeginsModuleFail) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -60,6 +61,7 @@ TEST_F(ValidateAdjacency, OpLoopMergeEndsModuleFail) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%main = OpFunction %void None %func
@ -80,6 +82,7 @@ TEST_F(ValidateAdjacency, OpSelectionMergeEndsModuleFail) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%main = OpFunction %void None %func
@ -103,6 +106,9 @@ std::string GenerateShaderCode(
ss << capabilities_and_extensions << "\n";
ss << "OpMemoryModel Logical GLSL450\n";
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
}
ss << R"(
%string = OpString ""

View File

@ -39,6 +39,7 @@ OpCapability Matrix
%ext_inst = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool

View File

@ -41,6 +41,7 @@ OpCapability Int64
ss << R"(
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool

View File

@ -41,6 +41,14 @@ OpCapability Int64
ss << capabilities_and_extensions;
ss << "OpMemoryModel Logical GLSL450\n";
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
} else if (execution_model == "Geometry") {
ss << "OpExecutionMode %main InputPoints\n";
ss << "OpExecutionMode %main OutputPoints\n";
} else if (execution_model == "GLCompute") {
ss << "OpExecutionMode %main LocalSize 1 1 1\n";
}
ss << R"(
%void = OpTypeVoid

View File

@ -42,6 +42,7 @@ OpCapability Float64)";
R"(
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool

View File

@ -243,10 +243,20 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) {
if (0 == std::strcmp(execution_model, "Fragment")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OriginUpperLeft\n";
if (0 == std::strcmp(built_in, "FragDepth")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
}
}
if (0 == std::strcmp(built_in, "FragDepth")) {
if (0 == std::strcmp(execution_model, "Geometry")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
<< " InputPoints\n";
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OutputPoints\n";
}
if (0 == std::strcmp(execution_model, "GLCompute")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " LocalSize 1 1 1\n";
}
entry_point.execution_modes = execution_modes.str();
@ -300,10 +310,20 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) {
if (0 == std::strcmp(execution_model, "Fragment")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OriginUpperLeft\n";
if (0 == std::strcmp(built_in, "FragDepth")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
}
}
if (0 == std::strcmp(built_in, "FragDepth")) {
if (0 == std::strcmp(execution_model, "Geometry")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
<< " InputPoints\n";
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OutputPoints\n";
}
if (0 == std::strcmp(execution_model, "GLCompute")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " LocalSize 1 1 1\n";
}
entry_point.execution_modes = execution_modes.str();
@ -366,10 +386,20 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) {
if (0 == std::strcmp(execution_model, "Fragment")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OriginUpperLeft\n";
if (0 == std::strcmp(built_in, "FragDepth")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
}
}
if (0 == std::strcmp(built_in, "FragDepth")) {
if (0 == std::strcmp(execution_model, "Geometry")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
<< " InputPoints\n";
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OutputPoints\n";
}
if (0 == std::strcmp(execution_model, "GLCompute")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " LocalSize 1 1 1\n";
}
entry_point.execution_modes = execution_modes.str();
@ -1542,10 +1572,20 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) {
if (0 == std::strcmp(execution_model, "Fragment")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OriginUpperLeft\n";
if (0 == std::strcmp(built_in, "FragDepth")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
}
}
if (0 == std::strcmp(built_in, "FragDepth")) {
if (0 == std::strcmp(execution_model, "Geometry")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " DepthReplacing\n";
<< " InputPoints\n";
execution_modes << "OpExecutionMode %" << entry_point.name
<< " OutputPoints\n";
}
if (0 == std::strcmp(execution_model, "GLCompute")) {
execution_modes << "OpExecutionMode %" << entry_point.name
<< " LocalSize 1 1 1\n";
}
entry_point.execution_modes = execution_modes.str();
@ -1869,6 +1909,8 @@ OpMemberDecorate %output_type 0 BuiltIn Position
OpStore %output_pos %pos
)";
generator.entry_points_.push_back(std::move(entry_point));
generator.entry_points_[0].execution_modes =
"OpExecutionMode %main InputPoints\nOpExecutionMode %main OutputPoints\n";
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@ -1904,6 +1946,8 @@ OpMemberDecorate %output_type 0 BuiltIn Position
OpStore %output_pos %pos
)";
generator.entry_points_.push_back(std::move(entry_point));
generator.entry_points_[0].execution_modes =
"OpExecutionMode %main InputPoints\nOpExecutionMode %main OutputPoints\n";
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
@ -1942,6 +1986,8 @@ OpMemberDecorate %output_type 0 BuiltIn FragCoord
OpStore %output_pos %pos
)";
generator.entry_points_.push_back(std::move(entry_point));
generator.entry_points_[0].execution_modes =
"OpExecutionMode %main InputPoints\nOpExecutionMode %main OutputPoints\n";
CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));

View File

@ -598,9 +598,12 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
std::string(kVoidFVoid), TessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
" OpEntryPoint Geometry %func \"shader\"" +
" OpExecutionMode %func InputPoints" +
" OpExecutionMode %func OutputPoints" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
" OpEntryPoint Fragment %func \"shader\"" +
" OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
" OpEntryPoint GLCompute %func \"shader\"" +
@ -659,6 +662,8 @@ INSTANTIATE_TEST_CASE_P(ExecutionMode, ValidateCapability,
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func Invocations 42" +
" OpExecutionMode %func InputPoints" +
" OpExecutionMode %func OutputPoints" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint TessellationControl %func \"shader\" "
@ -681,20 +686,22 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
"OpExecutionMode %func VertexOrderCcw" +
std::string(kVoidFVoid), TessellationDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func PixelCenterInteger" +
" OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func OriginLowerLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func EarlyFragmentTests" +
" OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint TessellationControl %func \"shader\" "
@ -705,20 +712,24 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
"OpExecutionMode %func Xfb" +
std::string(kVoidFVoid), std::vector<std::string>{"TransformFeedback"}),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func DepthReplacing" +
" OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func DepthGreater" +
" OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func DepthLess" +
" OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Vertex %func \"shader\" "
"OpEntryPoint Fragment %func \"shader\" "
"OpExecutionMode %func DepthUnchanged" +
" OpExecutionMode %func OriginUpperLeft" +
std::string(kVoidFVoid), ShaderDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Kernel %func \"shader\" "
@ -731,18 +742,22 @@ std::make_pair(std::string(kGLSL450MemoryModel) +
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func InputPoints" +
" OpExecutionMode %func OutputPoints" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func InputLines" +
" OpExecutionMode %func OutputLineStrip" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func InputLinesAdjacency" +
" OpExecutionMode %func OutputLineStrip" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func Triangles" +
" OpExecutionMode %func OutputTriangleStrip" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint TessellationControl %func \"shader\" "
@ -751,6 +766,7 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func InputTrianglesAdjacency" +
" OpExecutionMode %func OutputTriangleStrip" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint TessellationControl %func \"shader\" "
@ -763,6 +779,8 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func OutputVertices 42" +
" OpExecutionMode %func OutputPoints" +
" OpExecutionMode %func InputPoints" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint TessellationControl %func \"shader\" "
@ -771,14 +789,17 @@ std::make_pair(std::string(kOpenCLMemoryModel) +
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func OutputPoints" +
" OpExecutionMode %func InputPoints" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func OutputLineStrip" +
" OpExecutionMode %func InputLines" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kOpenCLMemoryModel) +
"OpEntryPoint Geometry %func \"shader\" "
"OpExecutionMode %func OutputTriangleStrip" +
" OpExecutionMode %func Triangles" +
std::string(kVoidFVoid), GeometryDependencies()),
std::make_pair(std::string(kGLSL450MemoryModel) +
"OpEntryPoint Kernel %func \"shader\" "

View File

@ -1206,6 +1206,7 @@ TEST_F(ValidateCFG, LoopWithZeroBackEdgesBad) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpName %loop "loop"
%voidt = OpTypeVoid
%funct = OpTypeFunction %voidt
@ -1231,6 +1232,7 @@ TEST_F(ValidateCFG, LoopWithBackEdgeFromUnreachableContinueConstructGood) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpName %loop "loop"
%voidt = OpTypeVoid
%funct = OpTypeFunction %voidt
@ -1465,6 +1467,7 @@ TEST_F(ValidateCFG, StructuredCFGBranchIntoSelectionBody) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool
@ -1779,6 +1782,7 @@ TEST_F(ValidateCFG, InvalidCaseExit) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "func"
OpExecutionMode %1 OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeInt 32 0
%4 = OpTypeFunction %2
@ -1811,6 +1815,7 @@ TEST_F(ValidateCFG, GoodCaseExitsToOuterConstructs) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%bool = OpTypeBool
%true = OpConstantTrue %bool

View File

@ -41,6 +41,9 @@ OpCapability Float64
ss << capabilities_and_extensions;
ss << "OpMemoryModel Logical GLSL450\n";
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
}
ss << R"(
%void = OpTypeVoid

View File

@ -42,6 +42,7 @@ OpCapability Float64)";
R"(
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool

View File

@ -90,6 +90,7 @@ TEST_F(ValidateDecorations, ValidateOpMemberDecorateOutOfBound) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "Main"
OpExecutionMode %1 OriginUpperLeft
OpMemberDecorate %_struct_2 1 RelaxedPrecision
%void = OpTypeVoid
%4 = OpTypeFunction %void
@ -286,6 +287,8 @@ TEST_F(ValidateDecorations, MultipleBuiltInObjectsConsumedByOpEntryPointBad) {
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %in_1 %in_2
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
OpMemberDecorate %struct_2 0 BuiltIn Position
%int = OpTypeInt 32 1
@ -318,6 +321,8 @@ TEST_F(ValidateDecorations,
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %in_1 %out_1
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
OpMemberDecorate %struct_2 0 BuiltIn Position
%int = OpTypeInt 32 1
@ -345,6 +350,8 @@ TEST_F(ValidateDecorations, NoBuiltInObjectsConsumedByOpEntryPointGood) {
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %in_1 %out_1
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
%int = OpTypeInt 32 1
%void = OpTypeVoid
%func = OpTypeFunction %void
@ -3037,6 +3044,7 @@ TEST_F(ValidateDecorations, EntryPointVariableWrongStorageClass) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "func" %var
OpExecutionMode %1 OriginUpperLeft
%void = OpTypeVoid
%int = OpTypeInt 32 0
%ptr_int_Workgroup = OpTypePointer Workgroup %int

View File

@ -44,6 +44,9 @@ OpCapability DerivativeControl
<< " %f32_var_input"
<< " %f32vec4_var_input"
<< "\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
}
ss << R"(
%void = OpTypeVoid

View File

@ -107,6 +107,9 @@ OpCapability Int64
<< " %u32vec2_input"
<< " %u64_input"
<< "\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
}
ss << R"(
%void = OpTypeVoid

View File

@ -424,6 +424,8 @@ TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceIsNotVariableTypeBad) {
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %ptr_builtin_1
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
%int = OpTypeInt 32 1
%void = OpTypeVoid
@ -448,6 +450,8 @@ TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceStorageClassBad) {
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %in_1
OpExecutionMode %main InputPoints
OpExecutionMode %main OutputPoints
OpMemberDecorate %struct_1 0 BuiltIn InvocationId
%int = OpTypeInt 32 1
%void = OpTypeVoid

View File

@ -56,6 +56,9 @@ OpCapability ImageBuffer
ss << capabilities_and_extensions;
ss << "OpMemoryModel Logical GLSL450\n";
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
}
ss << R"(
%void = OpTypeVoid
@ -374,7 +377,8 @@ OpMemoryModel Logical GLSL450
)";
if (include_entry_point) {
ss << "OpEntryPoint Fragment %main \"main\"";
ss << "OpEntryPoint Fragment %main \"main\"\n";
ss << "OpExecutionMode %main OriginUpperLeft";
}
ss << R"(
%void = OpTypeVoid

View File

@ -31,6 +31,7 @@ TEST_F(ValidateInterfacesTest, EntryPointMissingInput) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "func"
OpExecutionMode %1 OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeInt 32 0
%4 = OpTypePointer Input %3
@ -56,6 +57,7 @@ TEST_F(ValidateInterfacesTest, EntryPointMissingOutput) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "func"
OpExecutionMode %1 OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeInt 32 0
%4 = OpTypePointer Output %3
@ -81,6 +83,7 @@ TEST_F(ValidateInterfacesTest, InterfaceMissingUseInSubfunction) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "func"
OpExecutionMode %1 OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeInt 32 0
%4 = OpTypePointer Input %3
@ -112,6 +115,7 @@ OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "func" %2
OpEntryPoint Fragment %1 "func2"
OpExecutionMode %1 OriginUpperLeft
%3 = OpTypeVoid
%4 = OpTypeInt 32 0
%5 = OpTypePointer Input %4
@ -138,6 +142,7 @@ OpCapability Shader
OpCapability VariablePointers
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %1 "func"
OpExecutionMode %1 OriginUpperLeft
%2 = OpTypeVoid
%3 = OpTypeInt 32 0
%4 = OpTypePointer Input %3

View File

@ -481,6 +481,7 @@ TEST_F(ValidateEntryPoint, FunctionIsTargetOfEntryPointAndFunctionCallBad) {
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %foo "foo"
OpExecutionMode %foo OriginUpperLeft
%voidt = OpTypeVoid
%funct = OpTypeFunction %voidt
%foo = OpFunction %voidt None %funct

View File

@ -43,6 +43,7 @@ OpCapability Float64)";
%ext_inst = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%func = OpTypeFunction %void
%bool = OpTypeBool

770
test/val/val_modes_test.cpp Normal file
View File

@ -0,0 +1,770 @@
// Copyright (c) 2018 Google LLC.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sstream>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "source/spirv_target_env.h"
#include "test/test_fixture.h"
#include "test/unit_spirv.h"
#include "test/val/val_fixtures.h"
namespace spvtools {
namespace val {
namespace {
using ::testing::Combine;
using ::testing::HasSubstr;
using ::testing::Values;
using ::testing::ValuesIn;
using ValidateMode = spvtest::ValidateBase<bool>;
const std::string kVoidFunction = R"(%void = OpTypeVoid
%void_fn = OpTypeFunction %void
%main = OpFunction %void None %void_fn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
TEST_F(ValidateMode, GLComputeNoMode) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateMode, GLComputeNoModeVulkan) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
)" + kVoidFunction;
spv_target_env env = SPV_ENV_VULKAN_1_0;
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("In the Vulkan environment, GLCompute execution model entry "
"points require either the LocalSize execution mode or an "
"object decorated with WorkgroupSize must be specified."));
}
TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpDecorate %int3_1 BuiltIn WorkgroupSize
%int = OpTypeInt 32 0
%int3 = OpTypeVector %int 3
%int_1 = OpConstant %int 1
%int3_1 = OpConstantComposite %int3 %int_1 %int_1 %int_1
)" + kVoidFunction;
spv_target_env env = SPV_ENV_VULKAN_1_0;
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
}
TEST_F(ValidateMode, GLComputeVulkanLocalSize) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
)" + kVoidFunction;
spv_target_env env = SPV_ENV_VULKAN_1_0;
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
}
TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginLowerLeft
)" + kVoidFunction;
spv_target_env env = SPV_ENV_VULKAN_1_0;
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("In the Vulkan environment, the OriginLowerLeft "
"execution mode must not be used."));
}
TEST_F(ValidateMode, FragmentPixelCenterIntegerVulkan) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpExecutionMode %main PixelCenterInteger
)" + kVoidFunction;
spv_target_env env = SPV_ENV_VULKAN_1_0;
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("In the Vulkan environment, the PixelCenterInteger "
"execution mode must not be used."));
}
TEST_F(ValidateMode, GeometryNoOutputMode) {
const std::string spirv = R"(
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main"
OpExecutionMode %main InputPoints
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Geometry execution model entry points must specify "
"exactly one of OutputPoints, OutputLineStrip or "
"OutputTriangleStrip execution modes."));
}
TEST_F(ValidateMode, GeometryNoInputMode) {
const std::string spirv = R"(
OpCapability Geometry
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main"
OpExecutionMode %main OutputPoints
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Geometry execution model entry points must specify exactly "
"one of InputPoints, InputLines, InputLinesAdjacency, "
"Triangles or InputTrianglesAdjacency execution modes."));
}
TEST_F(ValidateMode, FragmentNoOrigin) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Fragment execution model entry points require either an "
"OriginUpperLeft or OriginLowerLeft execution mode."));
}
TEST_F(ValidateMode, FragmentBothOrigins) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpExecutionMode %main OriginLowerLeft
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Fragment execution model entry points can only specify one of "
"OriginUpperLeft or OriginLowerLeft execution modes."));
}
TEST_F(ValidateMode, FragmentDepthGreaterAndLess) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpExecutionMode %main DepthGreater
OpExecutionMode %main DepthLess
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Fragment execution model entry points can specify at "
"most one of DepthGreater, DepthLess or DepthUnchanged "
"execution modes."));
}
TEST_F(ValidateMode, FragmentDepthGreaterAndUnchanged) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpExecutionMode %main DepthGreater
OpExecutionMode %main DepthUnchanged
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Fragment execution model entry points can specify at "
"most one of DepthGreater, DepthLess or DepthUnchanged "
"execution modes."));
}
TEST_F(ValidateMode, FragmentDepthLessAndUnchanged) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpExecutionMode %main DepthLess
OpExecutionMode %main DepthUnchanged
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Fragment execution model entry points can specify at "
"most one of DepthGreater, DepthLess or DepthUnchanged "
"execution modes."));
}
TEST_F(ValidateMode, FragmentAllDepths) {
const std::string spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpExecutionMode %main DepthGreater
OpExecutionMode %main DepthLess
OpExecutionMode %main DepthUnchanged
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Fragment execution model entry points can specify at "
"most one of DepthGreater, DepthLess or DepthUnchanged "
"execution modes."));
}
TEST_F(ValidateMode, TessellationControlSpacingEqualAndFractionalOdd) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationControl %main "main"
OpExecutionMode %main SpacingEqual
OpExecutionMode %main SpacingFractionalOdd
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode, TessellationControlSpacingEqualAndSpacingFractionalEven) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationControl %main "main"
OpExecutionMode %main SpacingEqual
OpExecutionMode %main SpacingFractionalEven
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode,
TessellationControlSpacingFractionalOddAndSpacingFractionalEven) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationControl %main "main"
OpExecutionMode %main SpacingFractionalOdd
OpExecutionMode %main SpacingFractionalEven
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode, TessellationControlAllSpacing) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationControl %main "main"
OpExecutionMode %main SpacingEqual
OpExecutionMode %main SpacingFractionalOdd
OpExecutionMode %main SpacingFractionalEven
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode,
TessellationEvaluationSpacingEqualAndSpacingFractionalOdd) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationEvaluation %main "main"
OpExecutionMode %main SpacingEqual
OpExecutionMode %main SpacingFractionalOdd
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode,
TessellationEvaluationSpacingEqualAndSpacingFractionalEven) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationEvaluation %main "main"
OpExecutionMode %main SpacingEqual
OpExecutionMode %main SpacingFractionalEven
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode,
TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationEvaluation %main "main"
OpExecutionMode %main SpacingFractionalOdd
OpExecutionMode %main SpacingFractionalEven
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode, TessellationEvaluationAllSpacing) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationEvaluation %main "main"
OpExecutionMode %main SpacingEqual
OpExecutionMode %main SpacingFractionalOdd
OpExecutionMode %main SpacingFractionalEven
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify "
"at most one of SpacingEqual, SpacingFractionalOdd or "
"SpacingFractionalEven execution modes."));
}
TEST_F(ValidateMode, TessellationControlBothVertex) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationControl %main "main"
OpExecutionMode %main VertexOrderCw
OpExecutionMode %main VertexOrderCcw
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify at most "
"one of VertexOrderCw or VertexOrderCcw execution modes."));
}
TEST_F(ValidateMode, TessellationEvaluationBothVertex) {
const std::string spirv = R"(
OpCapability Tessellation
OpMemoryModel Logical GLSL450
OpEntryPoint TessellationEvaluation %main "main"
OpExecutionMode %main VertexOrderCw
OpExecutionMode %main VertexOrderCcw
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Tessellation execution model entry points can specify at most "
"one of VertexOrderCw or VertexOrderCcw execution modes."));
}
using ValidateModeGeometry = spvtest::ValidateBase<std::tuple<
std::tuple<std::string, std::string, std::string, std::string, std::string>,
std::tuple<std::string, std::string, std::string>>>;
TEST_P(ValidateModeGeometry, ExecutionMode) {
std::vector<std::string> input_modes;
std::vector<std::string> output_modes;
input_modes.push_back(std::get<0>(std::get<0>(GetParam())));
input_modes.push_back(std::get<1>(std::get<0>(GetParam())));
input_modes.push_back(std::get<2>(std::get<0>(GetParam())));
input_modes.push_back(std::get<3>(std::get<0>(GetParam())));
input_modes.push_back(std::get<4>(std::get<0>(GetParam())));
output_modes.push_back(std::get<0>(std::get<1>(GetParam())));
output_modes.push_back(std::get<1>(std::get<1>(GetParam())));
output_modes.push_back(std::get<2>(std::get<1>(GetParam())));
std::ostringstream sstr;
sstr << "OpCapability Geometry\n";
sstr << "OpMemoryModel Logical GLSL450\n";
sstr << "OpEntryPoint Geometry %main \"main\"\n";
size_t num_input_modes = 0;
for (auto input : input_modes) {
if (!input.empty()) {
num_input_modes++;
sstr << "OpExecutionMode %main " << input << "\n";
}
}
size_t num_output_modes = 0;
for (auto output : output_modes) {
if (!output.empty()) {
num_output_modes++;
sstr << "OpExecutionMode %main " << output << "\n";
}
}
sstr << "%void = OpTypeVoid\n";
sstr << "%void_fn = OpTypeFunction %void\n";
sstr << "%int = OpTypeInt 32 0\n";
sstr << "%int1 = OpConstant %int 1\n";
sstr << "%main = OpFunction %void None %void_fn\n";
sstr << "%entry = OpLabel\n";
sstr << "OpReturn\n";
sstr << "OpFunctionEnd\n";
CompileSuccessfully(sstr.str());
if (num_input_modes == 1 && num_output_modes == 1) {
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
} else {
EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions());
if (num_input_modes != 1) {
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Geometry execution model entry points must "
"specify exactly one of InputPoints, InputLines, "
"InputLinesAdjacency, Triangles or "
"InputTrianglesAdjacency execution modes."));
} else {
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Geometry execution model entry points must specify "
"exactly one of OutputPoints, OutputLineStrip or "
"OutputTriangleStrip execution modes."));
}
}
}
INSTANTIATE_TEST_CASE_P(
GeometryRequiredModes, ValidateModeGeometry,
Combine(Combine(Values("InputPoints", ""), Values("InputLines", ""),
Values("InputLinesAdjacency", ""), Values("Triangles", ""),
Values("InputTrianglesAdjacency", "")),
Combine(Values("OutputPoints", ""), Values("OutputLineStrip", ""),
Values("OutputTriangleStrip", ""))));
using ValidateModeExecution =
spvtest::ValidateBase<std::tuple<spv_result_t, std::string, std::string,
std::string, spv_target_env>>;
TEST_P(ValidateModeExecution, ExecutionMode) {
const spv_result_t expectation = std::get<0>(GetParam());
const std::string error = std::get<1>(GetParam());
const std::string model = std::get<2>(GetParam());
const std::string mode = std::get<3>(GetParam());
const spv_target_env env = std::get<4>(GetParam());
std::ostringstream sstr;
sstr << "OpCapability Shader\n";
sstr << "OpCapability Geometry\n";
sstr << "OpCapability Tessellation\n";
sstr << "OpCapability TransformFeedback\n";
if (!spvIsVulkanEnv(env)) {
sstr << "OpCapability Kernel\n";
if (env == SPV_ENV_UNIVERSAL_1_3) {
sstr << "OpCapability SubgroupDispatch\n";
}
}
sstr << "OpMemoryModel Logical GLSL450\n";
sstr << "OpEntryPoint " << model << " %main \"main\"\n";
if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 ||
mode.find("SubgroupsPerWorkgroupId") == 0) {
sstr << "OpExecutionModeId %main " << mode << "\n";
} else {
sstr << "OpExecutionMode %main " << mode << "\n";
}
if (model == "Geometry") {
if (!(mode.find("InputPoints") == 0 || mode.find("InputLines") == 0 ||
mode.find("InputLinesAdjacency") == 0 ||
mode.find("Triangles") == 0 ||
mode.find("InputTrianglesAdjacency") == 0)) {
// Exactly one of the above modes is required for Geometry shaders.
sstr << "OpExecutionMode %main InputPoints\n";
}
if (!(mode.find("OutputPoints") == 0 || mode.find("OutputLineStrip") == 0 ||
mode.find("OutputTriangleStrip") == 0)) {
// Exactly one of the above modes is required for Geometry shaders.
sstr << "OpExecutionMode %main OutputPoints\n";
}
} else if (model == "Fragment") {
if (!(mode.find("OriginUpperLeft") == 0 ||
mode.find("OriginLowerLeft") == 0)) {
// Exactly one of the above modes is required for Fragment shaders.
sstr << "OpExecutionMode %main OriginUpperLeft\n";
}
}
sstr << "%void = OpTypeVoid\n";
sstr << "%void_fn = OpTypeFunction %void\n";
sstr << "%int = OpTypeInt 32 0\n";
sstr << "%int1 = OpConstant %int 1\n";
sstr << "%main = OpFunction %void None %void_fn\n";
sstr << "%entry = OpLabel\n";
sstr << "OpReturn\n";
sstr << "OpFunctionEnd\n";
CompileSuccessfully(sstr.str(), env);
EXPECT_THAT(expectation, ValidateInstructions(env));
if (expectation != SPV_SUCCESS) {
EXPECT_THAT(getDiagnosticString(), HasSubstr(error));
}
}
INSTANTIATE_TEST_CASE_P(
ValidateModeGeometryOnlyGoodSpv10, ValidateModeExecution,
Combine(Values(SPV_SUCCESS), Values(""), Values("Geometry"),
Values("Invocations 3", "InputPoints", "InputLines",
"InputLinesAdjacency", "InputTrianglesAdjacency",
"OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(
ValidateModeGeometryOnlyBadSpv10, ValidateModeExecution,
Combine(Values(SPV_ERROR_INVALID_DATA),
Values("Execution mode can only be used with the Geometry "
"execution model."),
Values("Fragment", "TessellationEvaluation", "TessellationControl",
"GLCompute", "Vertex", "Kernel"),
Values("Invocations 3", "InputPoints", "InputLines",
"InputLinesAdjacency", "InputTrianglesAdjacency",
"OutputPoints", "OutputLineStrip", "OutputTriangleStrip"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(
ValidateModeTessellationOnlyGoodSpv10, ValidateModeExecution,
Combine(Values(SPV_SUCCESS), Values(""),
Values("TessellationControl", "TessellationEvaluation"),
Values("SpacingEqual", "SpacingFractionalEven",
"SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
"PointMode", "Quads", "Isolines"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(
ValidateModeTessellationOnlyBadSpv10, ValidateModeExecution,
Combine(Values(SPV_ERROR_INVALID_DATA),
Values("Execution mode can only be used with a tessellation "
"execution model."),
Values("Fragment", "Geometry", "GLCompute", "Vertex", "Kernel"),
Values("SpacingEqual", "SpacingFractionalEven",
"SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw",
"PointMode", "Quads", "Isolines"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(ValidateModeGeometryAndTessellationGoodSpv10,
ValidateModeExecution,
Combine(Values(SPV_SUCCESS), Values(""),
Values("TessellationControl",
"TessellationEvaluation", "Geometry"),
Values("Triangles", "OutputVertices 3"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(
ValidateModeGeometryAndTessellationBadSpv10, ValidateModeExecution,
Combine(Values(SPV_ERROR_INVALID_DATA),
Values("Execution mode can only be used with a Geometry or "
"tessellation execution model."),
Values("Fragment", "GLCompute", "Vertex", "Kernel"),
Values("Triangles", "OutputVertices 3"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(
ValidateModeFragmentOnlyGoodSpv10, ValidateModeExecution,
Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"),
Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
"EarlyFragmentTests", "DepthReplacing", "DepthLess",
"DepthUnchanged"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(
ValidateModeFragmentOnlyBadSpv10, ValidateModeExecution,
Combine(Values(SPV_ERROR_INVALID_DATA),
Values("Execution mode can only be used with the Fragment "
"execution model."),
Values("Geometry", "TessellationControl", "TessellationEvaluation",
"GLCompute", "Vertex", "Kernel"),
Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft",
"EarlyFragmentTests", "DepthReplacing", "DepthLess",
"DepthUnchanged"),
Values(SPV_ENV_UNIVERSAL_1_0)));
INSTANTIATE_TEST_CASE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution,
Combine(Values(SPV_SUCCESS), Values(""),
Values("Kernel"),
Values("LocalSizeHint 1 1 1", "VecTypeHint 4",
"ContractionOff",
"LocalSizeHintId %int1"),
Values(SPV_ENV_UNIVERSAL_1_3)));
INSTANTIATE_TEST_CASE_P(
ValidateModeKernelOnlyBadSpv13, ValidateModeExecution,
Combine(
Values(SPV_ERROR_INVALID_DATA),
Values(
"Execution mode can only be used with the Kernel execution model."),
Values("Geometry", "TessellationControl", "TessellationEvaluation",
"GLCompute", "Vertex", "Fragment"),
Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff",
"LocalSizeHintId %int1"),
Values(SPV_ENV_UNIVERSAL_1_3)));
INSTANTIATE_TEST_CASE_P(
ValidateModeGLComputeAndKernelGoodSpv13, ValidateModeExecution,
Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel", "GLCompute"),
Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
Values(SPV_ENV_UNIVERSAL_1_3)));
INSTANTIATE_TEST_CASE_P(
ValidateModeGLComputeAndKernelBadSpv13, ValidateModeExecution,
Combine(Values(SPV_ERROR_INVALID_DATA),
Values("Execution mode can only be used with a Kernel or GLCompute "
"execution model."),
Values("Geometry", "TessellationControl", "TessellationEvaluation",
"Fragment", "Vertex"),
Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"),
Values(SPV_ENV_UNIVERSAL_1_3)));
INSTANTIATE_TEST_CASE_P(
ValidateModeAllGoodSpv13, ValidateModeExecution,
Combine(Values(SPV_SUCCESS), Values(""),
Values("Kernel", "GLCompute", "Geometry", "TessellationControl",
"TessellationEvaluation", "Fragment", "Vertex"),
Values("Xfb", "Initializer", "Finalizer", "SubgroupSize 1",
"SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"),
Values(SPV_ENV_UNIVERSAL_1_3)));
TEST_F(ValidateModeExecution, MeshNVLocalSize) {
const std::string spirv = R"(
OpCapability Shader
OpCapability MeshShadingNV
OpExtension "SPV_NV_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshNV %main "main"
OpExecutionMode %main LocalSize 1 1 1
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateModeExecution, MeshNVOutputPoints) {
const std::string spirv = R"(
OpCapability Shader
OpCapability MeshShadingNV
OpExtension "SPV_NV_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshNV %main "main"
OpExecutionMode %main OutputPoints
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateModeExecution, MeshNVOutputVertices) {
const std::string spirv = R"(
OpCapability Shader
OpCapability MeshShadingNV
OpExtension "SPV_NV_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshNV %main "main"
OpExecutionMode %main OutputVertices 42
)" + kVoidFunction;
CompileSuccessfully(spirv);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateModeExecution, MeshNVLocalSizeId) {
const std::string spirv = R"(
OpCapability Shader
OpCapability MeshShadingNV
OpExtension "SPV_NV_mesh_shader"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshNV %main "main"
OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1
%int = OpTypeInt 32 0
%int_1 = OpConstant %int 1
)" + kVoidFunction;
spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
CompileSuccessfully(spirv, env);
EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -49,6 +49,9 @@ OpCapability GroupNonUniformQuad
ss << capabilities_and_extensions;
ss << "OpMemoryModel Logical GLSL450\n";
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
if (execution_model == "GLCompute") {
ss << "OpExecutionMode %main LocalSize 1 1 1\n";
}
ss << R"(
%void = OpTypeVoid

View File

@ -37,6 +37,10 @@ std::string GenerateShaderCode(
ss << capabilities_and_extensions << "\n";
ss << "OpMemoryModel Logical GLSL450\n";
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
if (execution_model == "Geometry") {
ss << "OpExecutionMode %main InputPoints\n";
ss << "OpExecutionMode %main OutputPoints\n";
}
ss << R"(
%void = OpTypeVoid

View File

@ -31,6 +31,7 @@ const std::string vulkan_spirv = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %func "func"
OpExecutionMode %func OriginUpperLeft
%void = OpTypeVoid
%functy = OpTypeFunction %void
%func = OpFunction %void None %functy