blob: 6d85b6b41f1074488edc0c837cef5587a0aa03a9 [file] [log] [blame]
/*
* Copyright (c) 2015-2025 The Khronos Group Inc.
* Copyright (c) 2015-2025 Valve Corporation
* Copyright (c) 2015-2025 LunarG, Inc.
* Copyright (c) 2015-2025 Google, Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* 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
*/
#include <vulkan/vulkan_core.h>
#include "../framework/layer_validation_tests.h"
#include "../framework/pipeline_helper.h"
#include "../framework/shader_object_helper.h"
#include "../framework/render_pass_helper.h"
#include "shader_helper.h"
class NegativeShaderInterface : public VkLayerTest {};
TEST_F(NegativeShaderInterface, MaxVertexComponentsWithBuiltins) {
TEST_DESCRIPTION("Test if the max componenets checks are being checked from OpMemberDecorate built-ins");
RETURN_IF_SKIP(InitFramework());
PFN_vkSetPhysicalDeviceLimitsEXT fpvkSetPhysicalDeviceLimitsEXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceLimitsEXT fpvkGetOriginalPhysicalDeviceLimitsEXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceLimitsEXT, fpvkGetOriginalPhysicalDeviceLimitsEXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
VkPhysicalDeviceProperties props;
fpvkGetOriginalPhysicalDeviceLimitsEXT(Gpu(), &props.limits);
props.limits.maxVertexOutputComponents = 128;
props.limits.maxFragmentInputComponents = 128;
fpvkSetPhysicalDeviceLimitsEXT(Gpu(), &props.limits);
RETURN_IF_SKIP(InitState());
InitRenderTarget();
// vec4 == 4 components
// This gives 124 which is just below the set max limit
const uint32_t numVec4 = 31;
std::string vsSourceStr =
"#version 450\n"
"layout(location = 0) out block {\n";
for (uint32_t i = 0; i < numVec4; i++) {
vsSourceStr += "vec4 v" + std::to_string(i) + ";\n";
}
vsSourceStr +=
"} outVs;\n"
"\n"
"void main() {\n"
" vec4 x = vec4(1.0);\n";
for (uint32_t i = 0; i < numVec4; i++) {
vsSourceStr += "outVs.v" + std::to_string(i) + " = x;\n";
}
// GLSL is defined to have a struct for the vertex shader built-in:
//
// out gl_PerVertex {
// vec4 gl_Position;
// float gl_PointSize;
// float gl_ClipDistance[];
// float gl_CullDistance[];
// } gl_out[];
//
// by including gl_Position here 7 extra vertex input components are added pushing it over the 128
// 124 + 7 > 128 limit
vsSourceStr += " gl_Position = x;\n";
vsSourceStr += "}";
std::string fsSourceStr =
"#version 450\n"
"layout(location = 0) in block {\n";
for (uint32_t i = 0; i < numVec4; i++) {
fsSourceStr += "vec4 v" + std::to_string(i) + ";\n";
}
fsSourceStr +=
"} inPs;\n"
"\n"
"layout(location=0) out vec4 color;\n"
"\n"
"void main(){\n"
" color = vec4(1);\n"
"}\n";
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj vs(*m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT);
m_errorMonitor->VerifyFound();
// maxFragmentInputComponents is not reached because GLSL should not be including any input fragment stage built-ins by default
// only maxVertexOutputComponents is reached
VkShaderObj fs(*m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT);
}
TEST_F(NegativeShaderInterface, MaxFragmentComponentsWithBuiltins) {
TEST_DESCRIPTION("Test if the max componenets checks are being checked from OpDecorate built-ins");
RETURN_IF_SKIP(InitFramework());
PFN_vkSetPhysicalDeviceLimitsEXT fpvkSetPhysicalDeviceLimitsEXT = nullptr;
PFN_vkGetOriginalPhysicalDeviceLimitsEXT fpvkGetOriginalPhysicalDeviceLimitsEXT = nullptr;
if (!LoadDeviceProfileLayer(fpvkSetPhysicalDeviceLimitsEXT, fpvkGetOriginalPhysicalDeviceLimitsEXT)) {
GTEST_SKIP() << "Failed to load device profile layer.";
}
VkPhysicalDeviceProperties props;
fpvkGetOriginalPhysicalDeviceLimitsEXT(Gpu(), &props.limits);
props.limits.maxVertexOutputComponents = 128;
props.limits.maxFragmentInputComponents = 128;
fpvkSetPhysicalDeviceLimitsEXT(Gpu(), &props.limits);
RETURN_IF_SKIP(InitState());
InitRenderTarget();
// vec4 == 4 components
// This gives 128 which is the max limit
const uint32_t numVec4 = 32; // 32 * 4 == 128
std::string vsSourceStr =
"#version 450\n"
"layout(location = 0) out block {\n";
for (uint32_t i = 0; i < numVec4; i++) {
vsSourceStr += "vec4 v" + std::to_string(i) + ";\n";
}
vsSourceStr +=
"} outVs;\n"
"\n"
"void main() {\n"
" vec4 x = vec4(1.0);\n";
for (uint32_t i = 0; i < numVec4; i++) {
vsSourceStr += "outVs.v" + std::to_string(i) + " = x;\n";
}
vsSourceStr += "}";
std::string fsSourceStr =
"#version 450\n"
"layout(location = 0) in block {\n";
for (uint32_t i = 0; i < numVec4; i++) {
fsSourceStr += "vec4 v" + std::to_string(i) + ";\n";
}
// By added gl_PointCoord it adds 2 more components to the fragment input stage
fsSourceStr +=
"} inPs;\n"
"\n"
"layout(location=0) out vec4 color;\n"
"\n"
"void main(){\n"
" color = vec4(1) * gl_PointCoord.x;\n"
"}\n";
// maxVertexOutputComponents is not reached because GLSL should not be including any output vertex stage built-ins
// only maxFragmentInputComponents is reached
VkShaderObj vs(*m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT);
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj fs(*m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, MaxVertexOutputComponents) {
TEST_DESCRIPTION(
"Test that an error is produced when the number of output components from the vertex stage exceeds the device limit");
RETURN_IF_SKIP(Init());
InitRenderTarget();
// overflow == 0: no overflow, 1: too many components, 2: location number too large
for (uint32_t overflow = 0; overflow < 3; ++overflow) {
m_errorMonitor->Reset();
const uint32_t maxVsOutComp = m_device->Physical().limits_.maxVertexOutputComponents + overflow;
std::string vsSourceStr = "#version 450\n\n";
const uint32_t numVec4 = maxVsOutComp / 4;
uint32_t location = 0;
if (overflow == 2) {
vsSourceStr += "layout(location=" + std::to_string(numVec4 + 1) + ") out vec4 vn;\n";
} else if (overflow == 1) {
for (uint32_t i = 0; i < numVec4; i++) {
vsSourceStr += "layout(location=" + std::to_string(location) + ") out vec4 v" + std::to_string(i) + ";\n";
location += 1;
}
const uint32_t remainder = maxVsOutComp % 4;
if (remainder != 0) {
if (remainder == 1) {
vsSourceStr += "layout(location=" + std::to_string(location) + ") out float" + " vn;\n";
} else {
vsSourceStr +=
"layout(location=" + std::to_string(location) + ") out vec" + std::to_string(remainder) + " vn;\n";
}
location += 1;
}
}
vsSourceStr +=
"void main(){\n"
"}\n";
switch (overflow) {
case 0: {
VkShaderObj vs(*m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT);
break;
}
case 1: {
// component and location limit (maxVertexOutputComponents)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj vs(*m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT);
m_errorMonitor->VerifyFound();
break;
}
case 2: {
// just component limit (maxVertexOutputComponents)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj vs(*m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT);
m_errorMonitor->VerifyFound();
break;
}
default: {
assert(0);
}
}
}
}
TEST_F(NegativeShaderInterface, MaxComponentsBlocks) {
TEST_DESCRIPTION("Test if the max componenets checks are done properly when in a single block");
RETURN_IF_SKIP(Init());
InitRenderTarget();
// To make the test simple, just make sure max is 128 or less (most HW is 64 or 128)
if (m_device->Physical().limits_.maxVertexOutputComponents > 128 ||
m_device->Physical().limits_.maxFragmentInputComponents > 128) {
GTEST_SKIP() << "maxVertexOutputComponents or maxFragmentInputComponents too high for test";
}
// vec4 == 4 components
// so this put the test over 128
const uint32_t numVec4 = 33;
std::string vsSourceStr =
"#version 450\n"
"layout(location = 0) out block {\n";
for (uint32_t i = 0; i < numVec4; i++) {
vsSourceStr += "vec4 v" + std::to_string(i) + ";\n";
}
vsSourceStr +=
"} outVs;\n"
"\n"
"void main() {\n"
" vec4 x = vec4(1.0);\n";
for (uint32_t i = 0; i < numVec4; i++) {
vsSourceStr += "outVs.v" + std::to_string(i) + " = x;\n";
}
vsSourceStr += "}";
std::string fsSourceStr =
"#version 450\n"
"layout(location = 0) in block {\n";
for (uint32_t i = 0; i < numVec4; i++) {
fsSourceStr += "vec4 v" + std::to_string(i) + ";\n";
}
fsSourceStr +=
"} inPs;\n"
"\n"
"layout(location=0) out vec4 color;\n"
"\n"
"void main(){\n"
" color = vec4(1);\n"
"}\n";
// maxVertexOutputComponents
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj vs(*m_device, vsSourceStr.c_str(), VK_SHADER_STAGE_VERTEX_BIT);
m_errorMonitor->VerifyFound();
// maxFragmentInputComponents
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj fs(*m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, MaxFragmentInputComponents) {
TEST_DESCRIPTION(
"Test that an error is produced when the number of input components from the fragment stage exceeds the device limit");
RETURN_IF_SKIP(Init());
InitRenderTarget();
// overflow == 0: no overflow, 1: too many components, 2: location number too large
for (uint32_t overflow = 0; overflow < 3; ++overflow) {
m_errorMonitor->Reset();
const uint32_t maxFsInComp = m_device->Physical().limits_.maxFragmentInputComponents + overflow;
std::string fsSourceStr = "#version 450\n\n";
const uint32_t numVec4 = maxFsInComp / 4;
uint32_t location = 0;
if (overflow == 2) {
fsSourceStr += "layout(location=" + std::to_string(numVec4 + 1) + ") in float" + " vn;\n";
} else {
for (uint32_t i = 0; i < numVec4; i++) {
fsSourceStr += "layout(location=" + std::to_string(location) + ") in vec4 v" + std::to_string(i) + ";\n";
location += 1;
}
const uint32_t remainder = maxFsInComp % 4;
if (remainder != 0) {
if (remainder == 1) {
fsSourceStr += "layout(location=" + std::to_string(location) + ") in float" + " vn;\n";
} else {
fsSourceStr +=
"layout(location=" + std::to_string(location) + ") in vec" + std::to_string(remainder) + " vn;\n";
}
location += 1;
}
}
fsSourceStr +=
"layout(location=0) out vec4 color;"
"\n"
"void main(){\n"
" color = vec4(1);\n"
"}\n";
switch (overflow) {
case 0: {
VkShaderObj fs(*m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT);
break;
}
case 1: {
// (maxFragmentInputComponents)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj fs(*m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT);
m_errorMonitor->VerifyFound();
break;
}
case 2: {
// (maxFragmentInputComponents)
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-Location-06272");
VkShaderObj fs(*m_device, fsSourceStr.c_str(), VK_SHADER_STAGE_FRAGMENT_BIT);
m_errorMonitor->VerifyFound();
break;
}
default: {
assert(0);
}
}
}
}
TEST_F(NegativeShaderInterface, FragmentInputNotProvided) {
TEST_DESCRIPTION(
"Test that an error is produced for a fragment shader input which is not present in the outputs of the previous stage");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"glsl(
#version 450
layout(location=0) in float x;
layout(location=0) out vec4 color;
void main(){
color = vec4(x);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, FragmentInputNotProvidedInBlock) {
TEST_DESCRIPTION(
"Test that an error is produced for a fragment shader input within an interface block, which is not present in the outputs "
"of the previous stage.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"glsl(
#version 450
in block { layout(location=0) float x; } ins;
layout(location=0) out vec4 color;
void main(){
color = vec4(ins.x);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatch) {
TEST_DESCRIPTION("Test that an error is produced for mismatched types across the vertex->fragment shader interface");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location=0) out int x;
void main(){
x = 0;
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location=0) in float x; /* VS writes int */
layout(location=0) out vec4 color;
void main(){
color = vec4(x);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatch2) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8443");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location=0) out int x;
void main(){
x = 0;
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location=0) in float x; /* VS writes int */
layout(location=0) out vec4 color;
void main(){
color = vec4(x);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
// Flipped here
helper.shader_stages_ = {fs.GetStageCreateInfo(), vs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchInBlock) {
TEST_DESCRIPTION(
"Test that an error is produced for mismatched types across the vertex->fragment shader interface, when the variable is "
"contained within an interface block");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
out block { layout(location=0) int x; } outs;
void main(){
outs.x = 0;
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
in block { layout(location=0) float x; } ins; /* VS writes int */
layout(location=0) out vec4 color;
void main(){
color = vec4(ins.x);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchVectorSize) {
TEST_DESCRIPTION("OpTypeVector has larger output than input");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddOptionalExtensions(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
void main(){
gl_Position = vec4(1.0);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location=0) in vec3 x;
layout(location=0) out vec4 color;
void main(){
color = vec4(1.0);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-maintenance4-06817");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockStruct) {
TEST_DESCRIPTION("Have a struct inside a block between shaders");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
int c; // difference
};
out block {
layout(location=0) float x;
layout(location=6) S y;
layout(location=10) int[4] z;
} outBlock;
void main() {
outBlock.y.a[1] = vec4(1);
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
float c; // difference
};
in block {
layout(location=0) float x;
layout(location=6) S y;
layout(location=10) int[4] z;
} inBlock;
layout(location=0) out vec4 color;
void main(){
color = inBlock.y.a[1];
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockStruct64bit) {
TEST_DESCRIPTION("Have a struct inside a block between shaders");
AddRequiredFeature(vkt::Feature::shaderFloat64);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_float64 : enable
struct S {
vec4 a[2];
float b;
f64vec3 c; // difference (takes 2 locations)
};
out block {
layout(location=0) S x[2];
layout(location=10) int y;
} outBlock;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
vec4 c; // difference
vec2 d;
};
in block {
layout(location=0) S x[2];
layout(location=10) int y;
} inBlock;
layout(location=0) out vec4 color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockArrayOfStruct) {
TEST_DESCRIPTION("Have an array of struct inside a block between shaders");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
int c; // difference
};
out block {
layout(location=0) float x;
layout(location=6) S[2] y; // each array is 4 locations slots
layout(location=14) int[4] z;
} outBlock;
void main() {
outBlock.y[1].a[1] = vec4(1);
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
float c; // difference
};
in block {
layout(location=0) float x;
layout(location=6) S[2] y;
layout(location=14) int[4] z;
} inBlock;
layout(location=0) out vec4 color;
void main(){
color = inBlock.y[1].a[1];
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockStructInnerArraySize) {
TEST_DESCRIPTION("Have an struct inside a block between shaders, array size is difference");
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (m_device->Physical().limits_.maxVertexOutputComponents <= 64) {
GTEST_SKIP() << "maxVertexOutputComponents is too low";
}
const char *vsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
int[2] c; // difference
};
out block {
layout(location=0) float x;
layout(location=6) S[2] y;
layout(location=18) int[4] z;
} outBlock;
void main() {
outBlock.y[1].a[1] = vec4(1);
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
int[3] c; // difference
};
in block {
layout(location=0) float x;
layout(location=6) S[2] y;
layout(location=18) int[4] z;
} inBlock;
layout(location=0) out vec4 color;
void main(){
color = inBlock.y[1].a[1];
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
// Both are errors, depending on compiler, the order of variables listed will hit one before the other
m_errorMonitor->SetUnexpectedError("VUID-RuntimeSpirv-OpEntryPoint-07754");
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockStructOuterArraySize) {
TEST_DESCRIPTION("Have an struct inside a block between shaders, array size is difference");
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (m_device->Physical().limits_.maxVertexOutputComponents <= 64) {
GTEST_SKIP() << "maxVertexOutputComponents is too low";
}
const char *vsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
float c;
};
out block {
layout(location=0) float x;
layout(location=6) S[2] y; // difference
layout(location=20) int[4] z;
} outBlock;
void main() {
outBlock.y[1].a[1] = vec4(1);
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
float c;
};
in block {
layout(location=0) float x;
layout(location=6) S[3] y; // difference
layout(location=20) int[4] z;
} inBlock;
layout(location=0) out vec4 color;
void main(){
color = inBlock.y[1].a[1];
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockStructArraySizeVertex) {
TEST_DESCRIPTION(
"Have an struct inside a block between shaders, array size is difference, but from the vertex shader being too large");
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (m_device->Physical().limits_.maxVertexOutputComponents <= 64) {
GTEST_SKIP() << "maxVertexOutputComponents is too low";
}
const char *vsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
int[3] c; // difference
};
out block {
layout(location=0) float x;
layout(location=6) S[2] y;
layout(location=18) int[4] z;
} outBlock;
void main() {
outBlock.y[1].a[1] = vec4(1);
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
int[2] c; // difference
};
in block {
layout(location=0) float x;
layout(location=6) S[2] y;
layout(location=18) int[4] z;
} inBlock;
layout(location=0) out vec4 color;
void main(){
color = inBlock.y[1].a[1];
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
// Both are errors, depending on compiler, the order of variables listed will hit one before the other
m_errorMonitor->SetUnexpectedError("VUID-RuntimeSpirv-OpEntryPoint-08743");
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockStructOuter2DArraySize) {
TEST_DESCRIPTION("Have an struct inside a block between shaders, array size is difference");
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (m_device->Physical().limits_.maxVertexOutputComponents <= 64) {
GTEST_SKIP() << "maxVertexOutputComponents is too low";
}
const char *vsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
};
out block {
layout(location=0) float x;
layout(location=2) S[2][2] y; // difference
layout(location=21) int[2] z;
} outBlock;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct S {
vec4 a[2];
float b;
};
in block {
layout(location=0) float x;
layout(location=2) S[2][3] y; // difference
layout(location=21) int[2] z;
} inBlock;
layout(location=0) out vec4 color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockNestedStructType64bit) {
TEST_DESCRIPTION("Have nested struct inside a block between shaders");
AddRequiredFeature(vkt::Feature::shaderFloat64);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_float64 : enable
struct A {
float a0_;
};
struct B {
f64vec3 b0_;
A b1_;
};
struct C {
A c1_;
B c2_;
};
out block {
layout(location=0) float x;
layout(location=1) C y;
} outBlock;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct A {
float a0_;
};
struct B {
vec3 b0_;
A b1_;
};
struct C {
A c1_;
B c2_;
};
in block {
layout(location=0) float x;
layout(location=1) C y;
} inBlock;
layout(location=0) out vec4 color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchBlockNestedStructArray) {
TEST_DESCRIPTION("Have nested struct inside a block between shaders");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
struct A {
float a0_;
};
struct B {
int b0_;
A b1_; // difference
};
struct C {
vec4 c0_[2];
A c1_;
B c2_;
};
out block {
layout(location=0) float x;
layout(location=1) C y;
} outBlock;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
struct A {
float a0_;
};
struct B {
int b0_;
A b1_[2]; // difference
};
struct C {
vec4 c0_[2];
A c1_;
B c2_;
};
in block {
layout(location=0) float x;
layout(location=1) C y;
} inBlock;
layout(location=0) out vec4 color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, VsFsMismatchByLocation) {
TEST_DESCRIPTION(
"Test that an error is produced for location mismatches across the vertex->fragment shader interface; This should manifest "
"as a not-written/not-consumed pair, but flushes out broken walking of the interfaces");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
out block { layout(location=1) float x; } outs;
void main(){
outs.x = 0;
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
in block { layout(location=0) float x; } ins;
layout(location=0) out vec4 color;
void main(){
color = vec4(ins.x);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, VsFsMismatchByComponent) {
TEST_DESCRIPTION(
"Test that an error is produced for component mismatches across the vertex->fragment shader interface. It's not enough to "
"have the same set of locations in use; matching is defined in terms of spirv variables.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
out block { layout(location=0, component=0) float x; } outs;
void main(){
outs.x = 0;
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
in block { layout(location=0, component=1) float x; } ins;
layout(location=0) out vec4 color;
void main(){
color = vec4(ins.x);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchShaderObject) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderObject);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location=0) out int x;
void main(){
x = 0;
gl_Position = vec4(1);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location=0) in float x; /* VS writes int */
layout(location=0) out vec4 color;
void main(){
color = vec4(x);
}
)glsl";
const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vsSource));
const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fsSource));
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
SetDefaultDynamicStatesExclude();
m_command_buffer.BindShaders(vertShader, fragShader);
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpEntryPoint-07754");
vk::CmdDraw(m_command_buffer, 4, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, VsFsTypeMismatchVectorSizeShaderObject) {
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderObject);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
void main(){
gl_Position = vec4(1.0);
}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location=0) in vec3 x;
layout(location=0) out vec4 color;
void main(){
color = vec4(1.0);
}
)glsl";
const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vsSource));
const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, fsSource));
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
SetDefaultDynamicStatesExclude();
m_command_buffer.BindShaders(vertShader, fragShader);
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-maintenance4-06817");
vk::CmdDraw(m_command_buffer, 4, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, InputOutputMismatch) {
TEST_DESCRIPTION("Test mismatch between vertex shader output and fragment shader input.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char vsSource[] = R"glsl(
#version 450
layout(location = 1) out int v;
void main() {
v = 1;
}
)glsl";
const char fsSource[] = R"glsl(
#version 450
layout(location = 0) out vec4 color;
layout(location = 1) in float v;
void main() {
color = vec4(v);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpEntryPoint-07754");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, VertexOutputNotConsumed) {
TEST_DESCRIPTION("Test that a warning is produced for a vertex output that is not consumed by the fragment stage");
SetTargetApiVersion(VK_API_VERSION_1_0);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location=0) out float x;
void main(){
gl_Position = vec4(1);
x = 0;
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), helper.fs_->GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kPerformanceWarningBit, "WARNING-Shader-OutputNotConsumed");
}
// Spec doesn't clarify if this is valid or not
// https://gitlab.khronos.org/vulkan/vulkan/-/issues/3293
TEST_F(NegativeShaderInterface, DISABLED_InputAndOutputComponents) {
TEST_DESCRIPTION("Test invalid shader layout in and out with different components.");
RETURN_IF_SKIP(Init());
InitRenderTarget();
{
const char *vsSource = R"glsl(
#version 450
layout(location = 0, component = 0) out float r;
layout(location = 0, component = 2) out float b;
void main() {
r = 0.25f;
b = 0.75f;
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
const char *fsSource = R"glsl(
#version 450
layout(location = 0) in vec3 rgb;
layout (location = 0) out vec4 color;
void main() {
color = vec4(rgb, 1.0f);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
{
const char *vsSource = R"glsl(
#version 450
layout(location = 0) out vec3 v;
void main() {
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
const char *fsSource = R"glsl(
#version 450
layout(location = 0, component = 0) in float a;
layout(location = 0, component = 2) in float b;
layout (location = 0) out vec4 color;
void main() {
color = vec4(1.0f);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kPerformanceWarningBit, "WARNING-Shader-OutputNotConsumed");
}
{
const char *vsSource = R"glsl(
#version 450
layout(location = 0) out vec3 v;
void main() {
v = vec3(1.0);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
const char *fsSource = R"glsl(
#version 450
layout(location = 0) in vec4 v;
layout (location = 0) out vec4 color;
void main() {
color = v;
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
{
const char *vsSource = R"glsl(
#version 450
layout(location = 0) out vec3 v;
void main() {
v = vec3(1.0);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
const char *fsSource = R"glsl(
#version 450
layout (location = 0) out vec4 color;
void main() {
color = vec4(1.0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit);
}
{
const char *vsSource = R"glsl(
#version 450
layout(location = 0) out vec3 v1;
layout(location = 1) out vec3 v2;
layout(location = 2) out vec3 v3;
void main() {
v1 = vec3(1.0);
v2 = vec3(2.0);
v3 = vec3(3.0);
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
const char *fsSource = R"glsl(
#version 450
layout (location = 0) in vec3 v1;
layout (location = 2) in vec3 v3;
layout (location = 0) out vec4 color;
void main() {
color = vec4(v1 * v3, 1.0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit);
}
}
TEST_F(NegativeShaderInterface, AlphaToCoverageOutputLocation0) {
TEST_DESCRIPTION("Test that an error is produced when alpha to coverage is enabled but no output at location 0 is declared.");
RETURN_IF_SKIP(Init());
InitRenderTarget(0u);
VkShaderObj fs(*m_device, kMinimalShaderGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state_ci.alphaToCoverageEnable = VK_TRUE;
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
helper.ms_ci_ = ms_state_ci;
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-alphaToCoverageEnable-08891");
}
TEST_F(NegativeShaderInterface, AlphaToCoverageOutputIndex1) {
TEST_DESCRIPTION("DualSource blend has two outputs at location zero, so Index 0 is the one that's required");
AddRequiredFeature(vkt::Feature::dualSrcBlend);
RETURN_IF_SKIP(Init());
InitRenderTarget(0u);
const char *fs_src = R"glsl(
#version 460
layout(location = 0, index = 1) out vec4 c0;
void main() {
c0 = vec4(0.0f);
}
)glsl";
VkShaderObj fs(*m_device, fs_src, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state_ci.alphaToCoverageEnable = VK_TRUE;
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
helper.ms_ci_ = ms_state_ci;
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-alphaToCoverageEnable-08891");
}
TEST_F(NegativeShaderInterface, AlphaToCoverageOutputNoAlpha) {
TEST_DESCRIPTION(
"Test that an error is produced when alpha to coverage is enabled but output at location 0 doesn't have alpha component.");
RETURN_IF_SKIP(Init());
InitRenderTarget(0u);
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec3 x;
void main(){
x = vec3(1);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state_ci.alphaToCoverageEnable = VK_TRUE;
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
helper.ms_ci_ = ms_state_ci;
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-alphaToCoverageEnable-08891");
}
TEST_F(NegativeShaderInterface, AlphaToCoverageArrayIndex) {
TEST_DESCRIPTION("Have array out outputs, but start at index 1");
RETURN_IF_SKIP(Init());
InitRenderTarget(0u);
const char *fsSource = R"glsl(
#version 450
layout(location=1) out vec4 fragData[3];
void main() {
fragData[0] = vec4(1.0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state_ci.alphaToCoverageEnable = VK_TRUE;
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
helper.ms_ci_ = ms_state_ci;
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-alphaToCoverageEnable-08891");
}
TEST_F(NegativeShaderInterface, AlphaToCoverageArrayVec3) {
TEST_DESCRIPTION("Have array out outputs, but not contain the alpha component");
RETURN_IF_SKIP(Init());
InitRenderTarget(0u);
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec3 fragData[4];
void main() {
fragData[0] = vec3(1.0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkPipelineMultisampleStateCreateInfo ms_state_ci = vku::InitStructHelper();
ms_state_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms_state_ci.alphaToCoverageEnable = VK_TRUE;
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
helper.ms_ci_ = ms_state_ci;
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-VkGraphicsPipelineCreateInfo-alphaToCoverageEnable-08891");
}
TEST_F(NegativeShaderInterface, MultidimensionalArray) {
TEST_DESCRIPTION("Make sure multidimensional arrays are handled");
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (m_device->Physical().limits_.maxVertexOutputComponents <= 64) {
GTEST_SKIP() << "maxVertexOutputComponents is too low";
}
const char *vsSource = R"glsl(
#version 450
layout(location=0) out float[4][2][2] x;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location=0) in float[4][3][2] x; // 2 extra Locations
layout(location=0) out float color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, MultidimensionalArrayDim) {
TEST_DESCRIPTION("Make sure multidimensional arrays are handled");
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (m_device->Physical().limits_.maxVertexOutputComponents <= 64) {
GTEST_SKIP() << "maxVertexOutputComponents is too low";
}
const char *vsSource = R"glsl(
#version 450
layout(location=0) out float[4][2][2] x;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location=0) in float[17] x; // 1 extra Locations
layout(location=0) out float color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, MultidimensionalArray64bit) {
TEST_DESCRIPTION("Make sure multidimensional arrays are handled for 64bits");
AddRequiredFeature(vkt::Feature::shaderFloat64);
RETURN_IF_SKIP(Init());
InitRenderTarget();
if (m_device->Physical().limits_.maxFragmentOutputAttachments < 25) {
GTEST_SKIP() << "maxFragmentOutputAttachments is too low";
}
const char *vsSource = R"glsl(
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_float64 : enable
layout(location=0) out f64vec3[2][2][2] x; // take 2 locations each (total 16)
layout(location=24) out float y;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_float64 : enable
layout(location=0) flat in f64vec3[2][3][2] x;
layout(location=24) out float color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
TEST_F(NegativeShaderInterface, PackingInsideArray) {
TEST_DESCRIPTION("From https://gitlab.khronos.org/vulkan/vulkan/-/issues/3558");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vsSource = R"glsl(
#version 450
layout(location = 0, component = 1) out float[2] x;
void main() {}
)glsl";
const char *fsSource = R"glsl(
#version 450
layout(location = 0, component = 1) in float x;
layout(location = 1, component = 0) in float y;
layout(location=0) out float color;
void main(){}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-08743");
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9616
TEST_F(NegativeShaderInterface, DISABLED_FragmentOutputNotWritten) {
TEST_DESCRIPTION(
"Test that an error is produced for a fragment shader which does not provide an output for one of the pipeline's color "
"attachments");
RETURN_IF_SKIP(Init());
InitRenderTarget();
// Nothing is written
VkShaderObj fs(*m_device, kMinimalShaderGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.cb_attachments_.colorWriteMask = 0xf; // all components
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotProduced");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9616
TEST_F(NegativeShaderInterface, DISABLED_FragmentOutputNotWrittenDynamicRendering) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
// Nothing is written
VkShaderObj fs(*m_device, kMinimalShaderGlsl, VK_SHADER_STAGE_FRAGMENT_BIT);
VkFormat color_formats = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_formats;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.cb_attachments_.colorWriteMask = 0xf; // all components
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotProduced-DynamicRendering");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9616
TEST_F(NegativeShaderInterface, DISABLED_FragmentOutputNotWrittenDynamicRenderingShaderObject) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::shaderObject);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const vkt::Shader vert_shader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl));
const vkt::Shader frag_shader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT,
GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kMinimalShaderGlsl));
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
SetDefaultDynamicStatesExclude();
m_command_buffer.BindShaders(vert_shader, frag_shader);
VkColorComponentFlags color_write_mask = 0xf; // all
vk::CmdSetColorWriteMaskEXT(m_command_buffer, 0, 1, &color_write_mask);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotProduced-DynamicRendering");
vk::CmdDraw(m_command_buffer, 4, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
// TODO - https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7923
TEST_F(NegativeShaderInterface, DISABLED_FragmentOutputNotWrittenArray) {
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fs_source = R"glsl(
#version 460
layout(location = 0) out vec4 uFragColor[2];
void main(){
uFragColor[0] = vec4(0);
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddColorAttachment(1);
rp.CreateRenderPass();
VkPipelineColorBlendAttachmentState color_blends[2];
color_blends[0] = DefaultColorBlendAttachmentState();
color_blends[0].colorWriteMask = 0xf;
color_blends[1] = DefaultColorBlendAttachmentState();
color_blends[1].colorWriteMask = 0xf;
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.cb_ci_.attachmentCount = 2;
pipe.cb_ci_.pAttachments = color_blends;
pipe.gp_ci_.renderPass = rp;
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotProduced");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
// TODO - https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7923
TEST_F(NegativeShaderInterface, DISABLED_FragmentOutputNotWrittenArrayDynamicRendering) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const char *fs_source = R"glsl(
#version 460
layout(location = 0) out vec4 uFragColor[2];
void main(){
uFragColor[0] = vec4(0);
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
VkFormat color_formats[2] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM};
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 2;
pipeline_rendering_info.pColorAttachmentFormats = color_formats;
VkPipelineColorBlendAttachmentState color_blends[2];
color_blends[0] = DefaultColorBlendAttachmentState();
color_blends[0].colorWriteMask = 0xf;
color_blends[1] = DefaultColorBlendAttachmentState();
color_blends[1].colorWriteMask = 0xf;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.cb_ci_.attachmentCount = 2;
pipe.cb_ci_.pAttachments = color_blends;
pipe.CreateGraphicsPipeline();
VkRenderingAttachmentInfo color_attachments[2];
color_attachments[0] = vku::InitStructHelper();
color_attachments[0].imageView = GetDynamicRenderTarget();
color_attachments[0].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachments[1] = color_attachments[0];
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.colorAttachmentCount = 2;
rendering_info.pColorAttachments = color_attachments;
rendering_info.layerCount = 1;
rendering_info.renderArea = GetRenderTargetArea();
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotProduced-DynamicRendering");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, CreatePipelineFragmentOutputTypeMismatch) {
TEST_DESCRIPTION(
"Test that an error is produced for a mismatch between the fundamental type of an fragment shader output variable, and the "
"format of the corresponding attachment");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"glsl(
#version 450
layout(location=0) out ivec4 x; /* not UNORM */
void main(){
x = ivec4(1);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
const auto set_info = [&](CreatePipelineHelper &helper) {
helper.shader_stages_ = {helper.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
};
CreatePipelineHelper::OneshotTest(*this, set_info, kWarningBit, "Undefined-Value-ShaderFragmentOutputMismatch");
}
TEST_F(NegativeShaderInterface, FragmentOutputTypeMismatchDynamicRendering) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const char *fs_source = R"glsl(
#version 450
layout(location=0) out ivec4 x; /* not UNORM */
void main(){
x = ivec4(1);
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
VkFormat color_formats = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_formats;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.cb_attachments_.colorWriteMask = 0xf; // all components
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderFragmentOutputMismatch-DynamicRendering");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, FragmentOutputTypeMismatchDynamicRenderingLocalRead) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::dynamicRenderingLocalRead);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget(VK_FORMAT_R8G8B8A8_SINT);
InitDynamicRenderTarget(VK_FORMAT_R8G8B8A8_UNORM);
const char *fs_source = R"glsl(
#version 450
layout(location=0) out ivec4 x; /* not UNORM */
void main(){
x = ivec4(1);
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
static constexpr uint32_t locations[] = {VK_ATTACHMENT_UNUSED, 0};
VkRenderingAttachmentLocationInfo locations_info = vku::InitStructHelper();
locations_info.colorAttachmentCount = std::size(locations);
locations_info.pColorAttachmentLocations = locations;
static constexpr VkFormat color_formats[] = {VK_FORMAT_R8G8B8A8_SINT, VK_FORMAT_R8G8B8A8_UNORM};
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper(&locations_info);
pipeline_rendering_info.colorAttachmentCount = std::size(color_formats);
pipeline_rendering_info.pColorAttachmentFormats = color_formats;
VkPipelineColorBlendAttachmentState color_blend_attachments[2] = {};
VkPipelineColorBlendStateCreateInfo cbi = vku::InitStructHelper();
cbi.attachmentCount = 2u;
cbi.pAttachments = color_blend_attachments;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.cb_attachments_.colorWriteMask = 0xf; // all components
pipe.gp_ci_.pColorBlendState = &cbi;
pipe.CreateGraphicsPipeline();
VkRenderingAttachmentInfo color_attachment[] = {vku::InitStructHelper(), vku::InitStructHelper()};
color_attachment[0].imageView = GetDynamicRenderTarget(0);
color_attachment[0].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment[1].imageView = GetDynamicRenderTarget(1);
color_attachment[1].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.colorAttachmentCount = std::size(color_attachment);
rendering_info.pColorAttachments = color_attachment;
rendering_info.layerCount = 1;
rendering_info.renderArea = GetRenderTargetArea();
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vk::CmdSetRenderingAttachmentLocationsKHR(m_command_buffer, &locations_info);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderFragmentOutputMismatch-DynamicRendering");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, FragmentOutputDynamicRenderingUnusedAttachments) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::dynamicRenderingUnusedAttachments);
RETURN_IF_SKIP(Init());
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
VkFormat color_formats[] = {VK_FORMAT_R8G8B8A8_UNORM};
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = color_formats;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.CreateGraphicsPipeline();
VkFormat ds_format = FindSupportedDepthStencilFormat(Gpu());
vkt::Image color_image(*m_device, 32, 32, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
vkt::ImageView color_image_view = color_image.CreateView();
vkt::Image ds_image(*m_device, 32, 32, ds_format, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
const vkt::ImageView depth_view(*m_device, ds_image.BasicViewCreatInfo(VK_IMAGE_ASPECT_DEPTH_BIT));
VkRenderingAttachmentInfo color_attachment = vku::InitStructHelper();
color_attachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment.imageView = VK_NULL_HANDLE; // null and causes warning
VkRenderingAttachmentInfo depth_stencil_attachment = vku::InitStructHelper();
depth_stencil_attachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_stencil_attachment.imageView = depth_view;
m_command_buffer.Begin();
VkRenderingInfo begin_rendering_info = vku::InitStructHelper();
begin_rendering_info.layerCount = 1;
begin_rendering_info.colorAttachmentCount = 1;
begin_rendering_info.pColorAttachments = &color_attachment;
begin_rendering_info.pDepthAttachment = &depth_stencil_attachment;
begin_rendering_info.renderArea = {{0, 0}, {1, 1}};
m_command_buffer.BeginRendering(begin_rendering_info);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotConsumed-DynamicRendering");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, CreatePipelineFragmentOutputNotConsumed) {
TEST_DESCRIPTION(
"Test that a warning is produced for a fragment shader which provides a spurious output with no matching attachment");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(location=1) out vec4 y; /* no matching attachment for this */
void main(){
x = vec4(1);
y = vec4(1);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotConsumed");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, FragmentOutputNotConsumedDynamicRendering) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const char *fs_source = R"glsl(
#version 450
layout(location=0) out vec4 x;
layout(location=1) out vec4 y; /* no matching attachment for this */
void main(){
x = vec4(1);
y = vec4(1);
}
)glsl";
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT);
VkFormat color_formats = VK_FORMAT_B8G8R8A8_UNORM;
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 1;
pipeline_rendering_info.pColorAttachmentFormats = &color_formats;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.cb_attachments_.colorWriteMask = 0xf; // all components
pipe.CreateGraphicsPipeline();
m_command_buffer.Begin();
m_command_buffer.BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea());
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotConsumed-DynamicRendering");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, InvalidStaticSpirv) {
TEST_DESCRIPTION(
"Test that a warning is produced for a fragment shader which provides a spurious output with no matching attachment");
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *spv_source = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %fragCoord %block_var
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpDecorate %fragCoord Location 0
OpDecorate %block Block
OpMemberDecorate %block 0 Location 1
%void = OpTypeVoid
%voidfn = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%ptr_v4float = OpTypePointer Output %v4float
%fragCoord = OpVariable %ptr_v4float Output
%block = OpTypeStruct %v4float %v4float
%block_ptr = OpTypePointer Output %block
%block_var = OpVariable %block_ptr Output
%main = OpFunction %void None %voidfn
%label = OpLabel
OpReturn
OpFunctionEnd
)";
m_errorMonitor->SetDesiredError("VUID-StandaloneSpirv-Location-04919");
auto fs = VkShaderObj::CreateFromASM(this, spv_source, VK_SHADER_STAGE_FRAGMENT_BIT);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, InvalidStaticSpirvMaintenance5) {
TEST_DESCRIPTION("Test SPIRV is still checked if using new pNext in VkPipelineShaderStageCreateInfo");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *spv_source = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main"
OpSource GLSL 460
OpMemberDecorate %gl_PerVertex 2 BuiltIn Position
OpDecorate %gl_PerVertex Location 1
%void = OpTypeVoid
%3 = OpTypeFunction %void
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::vector<uint32_t> shader;
ASMtoSPV(SPV_ENV_VULKAN_1_0, 0, spv_source, shader);
VkShaderModuleCreateInfo module_create_info = vku::InitStructHelper();
module_create_info.pCode = shader.data();
module_create_info.codeSize = shader.size() * sizeof(uint32_t);
VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&module_create_info);
stage_ci.stage = VK_SHADER_STAGE_VERTEX_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
CreatePipelineHelper pipe(*this);
pipe.gp_ci_.stageCount = 1;
pipe.gp_ci_.pStages = &stage_ci;
m_errorMonitor->SetDesiredError("VUID-VkShaderModuleCreateInfo-pCode-08737");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, InvalidStaticSpirvMaintenance5Compute) {
TEST_DESCRIPTION("Test SPIRV is still checked if using new pNext in VkPipelineShaderStageCreateInfo");
SetTargetApiVersion(VK_API_VERSION_1_1);
AddRequiredExtensions(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::maintenance5);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *spv_source = R"(
OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpSource GLSL 460
OpMemberDecorate %gl_PerVertex 2 BuiltIn Position
OpDecorate %gl_PerVertex Location 1
%void = OpTypeVoid
%3 = OpTypeFunction %void
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::vector<uint32_t> shader;
ASMtoSPV(SPV_ENV_VULKAN_1_0, 0, spv_source, shader);
VkShaderModuleCreateInfo module_create_info = vku::InitStructHelper();
module_create_info.pCode = shader.data();
module_create_info.codeSize = shader.size() * sizeof(uint32_t);
VkPipelineShaderStageCreateInfo stage_ci = vku::InitStructHelper(&module_create_info);
stage_ci.stage = VK_SHADER_STAGE_COMPUTE_BIT;
stage_ci.module = VK_NULL_HANDLE;
stage_ci.pName = "main";
vkt::PipelineLayout layout(*m_device, {});
CreateComputePipelineHelper pipe(*this);
pipe.cp_ci_.stage = stage_ci;
pipe.cp_ci_.layout = layout;
m_errorMonitor->SetDesiredError("VUID-VkShaderModuleCreateInfo-pCode-08737");
pipe.CreateComputePipeline(false);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, PhysicalStorageBuffer) {
TEST_DESCRIPTION("Details found in https://gitlab.khronos.org/spirv/SPIR-V/-/issues/779");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char *vs_source = R"(
OpCapability Shader
OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_KHR_physical_storage_buffer"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Vertex %main "main" %outgoingPtr
OpDecorate %dataBuffer Block
OpMemberDecorate %dataBuffer 0 Offset 0
OpMemberDecorate %dataBuffer 1 Offset 4
OpDecorate %outgoingPtr Location 0
OpDecorate %outgoingPtr AliasedPointer
%void = OpTypeVoid
%3 = OpTypeFunction %void
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_dataBuffer PhysicalStorageBuffer
%int = OpTypeInt 32 1
%dataBuffer = OpTypeStruct %int %int
%_ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer PhysicalStorageBuffer %dataBuffer
%_ptr_Output__ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer Output %_ptr_PhysicalStorageBuffer_dataBuffer
%outgoingPtr = OpVariable %_ptr_Output__ptr_PhysicalStorageBuffer_dataBuffer Output
%uint = OpTypeInt 32 0
%v2uint = OpTypeVector %uint 2
%uint_2 = OpConstant %uint 2
%14 = OpConstantComposite %v2uint %uint_2 %uint_2
%main = OpFunction %void None %3
%5 = OpLabel
%15 = OpBitcast %_ptr_PhysicalStorageBuffer_dataBuffer %14
OpStore %outgoingPtr %15
OpReturn
OpFunctionEnd
)";
m_errorMonitor->SetDesiredWarning("VUID-StandaloneSpirv-Input-09557");
VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
m_errorMonitor->VerifyFound();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9616
TEST_F(NegativeShaderInterface, DISABLED_MultipleFragmentAttachment) {
TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7923");
RETURN_IF_SKIP(Init());
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 color0;
layout(location=1) out vec4 color1;
void main() {
color0 = vec4(1.0);
color1 = vec4(1.0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddAttachmentReference({1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddAttachmentReference({2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL});
rp.AddColorAttachment(0);
rp.AddColorAttachment(1);
rp.AddColorAttachment(2);
rp.CreateRenderPass();
VkPipelineColorBlendAttachmentState color_blends[3];
color_blends[0] = DefaultColorBlendAttachmentState();
color_blends[0].colorWriteMask = 0xf;
color_blends[1] = DefaultColorBlendAttachmentState();
color_blends[1].colorWriteMask = 0xf;
color_blends[2] = DefaultColorBlendAttachmentState();
color_blends[2].colorWriteMask = 0xf;
CreatePipelineHelper pipe(*this);
pipe.shader_stages_[1] = fs.GetStageCreateInfo();
pipe.cb_ci_.attachmentCount = 3;
pipe.cb_ci_.pAttachments = color_blends;
pipe.gp_ci_.renderPass = rp;
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotProduced");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/9616
TEST_F(NegativeShaderInterface, DISABLED_MultipleFragmentAttachmentDynamicRendering) {
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
RETURN_IF_SKIP(Init());
InitDynamicRenderTarget();
const char *fsSource = R"glsl(
#version 450
layout(location=0) out vec4 color0;
layout(location=1) out vec4 color1;
void main() {
color0 = vec4(1.0);
color1 = vec4(1.0);
}
)glsl";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
VkFormat color_formats[3] = {VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM};
VkPipelineRenderingCreateInfo pipeline_rendering_info = vku::InitStructHelper();
pipeline_rendering_info.colorAttachmentCount = 3;
pipeline_rendering_info.pColorAttachmentFormats = color_formats;
VkPipelineColorBlendAttachmentState color_blends[3];
color_blends[0] = DefaultColorBlendAttachmentState();
color_blends[0].colorWriteMask = 0xf;
color_blends[1] = DefaultColorBlendAttachmentState();
color_blends[1].colorWriteMask = 0xf;
color_blends[2] = DefaultColorBlendAttachmentState();
color_blends[2].colorWriteMask = 0xf;
CreatePipelineHelper pipe(*this, &pipeline_rendering_info);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.cb_ci_.attachmentCount = 3;
pipe.cb_ci_.pAttachments = color_blends;
pipe.CreateGraphicsPipeline();
VkRenderingAttachmentInfo color_attachments[3];
color_attachments[0] = vku::InitStructHelper();
color_attachments[0].imageView = GetDynamicRenderTarget();
color_attachments[0].imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachments[1] = color_attachments[0];
color_attachments[2] = color_attachments[0];
VkRenderingInfo rendering_info = vku::InitStructHelper();
rendering_info.colorAttachmentCount = 3;
rendering_info.pColorAttachments = color_attachments;
rendering_info.layerCount = 1;
rendering_info.renderArea = GetRenderTargetArea();
m_command_buffer.Begin();
m_command_buffer.BeginRendering(rendering_info);
vk::CmdBindPipeline(m_command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
m_errorMonitor->SetDesiredWarning("Undefined-Value-ShaderOutputNotProduced-DynamicRendering");
vk::CmdDraw(m_command_buffer, 3, 1, 0, 0);
m_errorMonitor->VerifyFound();
m_command_buffer.EndRendering();
m_command_buffer.End();
}
TEST_F(NegativeShaderInterface, MissingInputAttachmentIndex) {
RETURN_IF_SKIP(Init());
InitRenderTarget();
// layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput xs;
// layout(location=0) out vec4 color;
// void main() {
// color = subpassLoad(xs);
// }
//
// missing OpDecorate %xs InputAttachmentIndex 0
const char *fsSource = R"(
OpCapability Shader
OpCapability InputAttachment
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %color
OpExecutionMode %main OriginUpperLeft
OpDecorate %color Location 0
OpDecorate %xs DescriptorSet 0
OpDecorate %xs Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%color = OpVariable %_ptr_Output_v4float Output
%10 = OpTypeImage %float SubpassData 0 0 0 2 Unknown
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
%xs = OpVariable %_ptr_UniformConstant_10 UniformConstant
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%v2int = OpTypeVector %int 2
%17 = OpConstantComposite %v2int %int_0 %int_0
%main = OpFunction %void None %3
%5 = OpLabel
%13 = OpLoad %10 %xs
%18 = OpImageRead %v4float %13 %17
OpStore %color %18
OpReturn
OpFunctionEnd
)";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
RenderPassSingleSubpass rp(*this);
rp.AddAttachmentDescription(VK_FORMAT_R8G8B8A8_UNORM);
rp.AddAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL});
rp.AddInputAttachment(0);
rp.AddColorAttachment(0);
rp.CreateRenderPass();
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
pipe.gp_ci_.renderPass = rp;
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-None-09558");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, MissingInputAttachmentIndexArray) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::dynamicRendering);
AddRequiredFeature(vkt::Feature::dynamicRenderingLocalRead);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput xs[1];
// layout(location=0) out vec4 color;
// void main() {
// color = subpassLoad(xs[0]);
// }
//
// missing OpDecorate %xs InputAttachmentIndex 0
const char *fsSource = R"(
OpCapability Shader
OpCapability InputAttachment
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %color
OpExecutionMode %main OriginUpperLeft
OpDecorate %color Location 0
OpDecorate %xs DescriptorSet 0
OpDecorate %xs Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%color = OpVariable %_ptr_Output_v4float Output
%10 = OpTypeImage %float SubpassData 0 0 0 2 Unknown
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_10_uint_1 = OpTypeArray %10 %uint_1
%_ptr_UniformConstant__arr_10_uint_1 = OpTypePointer UniformConstant %_arr_10_uint_1
%xs = OpVariable %_ptr_UniformConstant__arr_10_uint_1 UniformConstant
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
%v2int = OpTypeVector %int 2
%22 = OpConstantComposite %v2int %int_0 %int_0
%main = OpFunction %void None %3
%5 = OpLabel
%19 = OpAccessChain %_ptr_UniformConstant_10 %xs %int_0
%20 = OpLoad %10 %19
%23 = OpImageRead %v4float %20 %22
OpStore %color %23
OpReturn
OpFunctionEnd
)";
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {pipe.vs_->GetStageCreateInfo(), fs.GetStageCreateInfo()};
pipe.dsl_bindings_[0] = {0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr};
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-OpTypeImage-09644");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, MissingInputAttachmentIndexShaderObject) {
AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::shaderObject);
RETURN_IF_SKIP(Init());
// layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput xs;
// layout(location=0) out vec4 color;
// void main() {
// color = subpassLoad(xs);
// }
//
// missing OpDecorate %xs InputAttachmentIndex 0
const char *fsSource = R"(
OpCapability Shader
OpCapability InputAttachment
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %color
OpExecutionMode %main OriginUpperLeft
OpDecorate %color Location 0
OpDecorate %xs DescriptorSet 0
OpDecorate %xs Binding 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%color = OpVariable %_ptr_Output_v4float Output
%10 = OpTypeImage %float SubpassData 0 0 0 2 Unknown
%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
%xs = OpVariable %_ptr_UniformConstant_10 UniformConstant
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%v2int = OpTypeVector %int 2
%17 = OpConstantComposite %v2int %int_0 %int_0
%main = OpFunction %void None %3
%5 = OpLabel
%13 = OpLoad %10 %xs
%18 = OpImageRead %v4float %13 %17
OpStore %color %18
OpReturn
OpFunctionEnd
)";
std::vector<uint32_t> spv;
ASMtoSPV(SPV_ENV_VULKAN_1_0, 0, fsSource, spv);
OneOffDescriptorSet descriptor_set(m_device,
{
{0, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr},
});
m_errorMonitor->SetDesiredError("VUID-RuntimeSpirv-None-09558");
const vkt::Shader frag_shader(*m_device,
ShaderCreateInfo(spv, VK_SHADER_STAGE_FRAGMENT_BIT, 1, &descriptor_set.layout_.handle()));
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, PhysicalStorageBufferArray) {
TEST_DESCRIPTION("Details found in https://gitlab.khronos.org/spirv/SPIR-V/-/issues/779");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init())
InitRenderTarget();
const char *vs_source = R"(
OpCapability Shader
OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_KHR_physical_storage_buffer"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Vertex %main "main" %outgoingPtr
OpDecorate %dataBuffer Block
OpMemberDecorate %dataBuffer 0 Offset 0
OpMemberDecorate %dataBuffer 1 Offset 4
OpDecorate %outgoingPtr Location 0
OpDecorate %outgoingPtr AliasedPointer
%void = OpTypeVoid
%3 = OpTypeFunction %void
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_dataBuffer PhysicalStorageBuffer
%int = OpTypeInt 32 1
%dataBuffer = OpTypeStruct %int %int
%_ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer PhysicalStorageBuffer %dataBuffer
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%_arr__ptr_PhysicalStorageBuffer_dataBuffer_uint_3 = OpTypeArray %_ptr_PhysicalStorageBuffer_dataBuffer %uint_3
%_ptr_Output__arr__ptr_PhysicalStorageBuffer_dataBuffer_uint_3 = OpTypePointer Output %_arr__ptr_PhysicalStorageBuffer_dataBuffer_uint_3
%outgoingPtr = OpVariable %_ptr_Output__arr__ptr_PhysicalStorageBuffer_dataBuffer_uint_3 Output
%int_2 = OpConstant %int 2
%v2uint = OpTypeVector %uint 2
%uint_2 = OpConstant %uint 2
%17 = OpConstantComposite %v2uint %uint_2 %uint_2
%_ptr_Output__ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer Output %_ptr_PhysicalStorageBuffer_dataBuffer
%main = OpFunction %void None %3
%5 = OpLabel
%18 = OpBitcast %_ptr_PhysicalStorageBuffer_dataBuffer %17
%20 = OpAccessChain %_ptr_Output__ptr_PhysicalStorageBuffer_dataBuffer %outgoingPtr %int_2
OpStore %20 %18
OpReturn
OpFunctionEnd
)";
m_errorMonitor->SetDesiredWarning("VUID-StandaloneSpirv-Input-09557");
VkShaderObj vs(*m_device, vs_source, VK_SHADER_STAGE_VERTEX_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, PhysicalStorageBufferLinkedList) {
TEST_DESCRIPTION("Details found in https://gitlab.khronos.org/spirv/SPIR-V/-/issues/779");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init())
InitRenderTarget();
const char *fs_source = R"(
OpCapability Shader
OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_KHR_physical_storage_buffer"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main" %fragColor %incomingPtr
OpExecutionMode %main OriginUpperLeft
OpDecorate %fragColor Location 0
OpDecorate %dataBuffer Block
OpMemberDecorate %dataBuffer 0 Offset 0
OpMemberDecorate %dataBuffer 1 Offset 16
OpDecorate %incomingPtr Location 0
OpDecorate %incomingPtr AliasedPointer
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%fragColor = OpVariable %_ptr_Output_v4float Output
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_dataBuffer PhysicalStorageBuffer
%dataBuffer = OpTypeStruct %v4float %_ptr_PhysicalStorageBuffer_dataBuffer
%_ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer PhysicalStorageBuffer %dataBuffer
%_ptr_Input__ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer Input %_ptr_PhysicalStorageBuffer_dataBuffer
%incomingPtr = OpVariable %_ptr_Input__ptr_PhysicalStorageBuffer_dataBuffer Input
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_PhysicalStorageBuffer_v4float = OpTypePointer PhysicalStorageBuffer %v4float
%main = OpFunction %void None %3
%5 = OpLabel
%14 = OpLoad %_ptr_PhysicalStorageBuffer_dataBuffer %incomingPtr
%18 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %14 %int_0
%19 = OpLoad %v4float %18 Aligned 16
OpStore %fragColor %19
OpReturn
OpFunctionEnd
)";
m_errorMonitor->SetDesiredWarning("VUID-StandaloneSpirv-Input-09557");
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, PhysicalStorageBufferNested) {
TEST_DESCRIPTION("Details found in https://gitlab.khronos.org/spirv/SPIR-V/-/issues/779");
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::bufferDeviceAddress);
RETURN_IF_SKIP(Init())
InitRenderTarget();
const char *fs_source = R"(
OpCapability Shader
OpCapability PhysicalStorageBufferAddresses
OpExtension "SPV_KHR_physical_storage_buffer"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Fragment %main "main" %fragColor %incomingPtr
OpExecutionMode %main OriginUpperLeft
OpDecorate %fragColor Location 0
OpDecorate %dataBuffer Block
OpMemberDecorate %dataBuffer 0 Offset 0
OpDecorate %t1 Block
OpMemberDecorate %t1 0 NonWritable
OpMemberDecorate %t1 0 Offset 0
OpDecorate %_runtimearr_v4float ArrayStride 16
OpDecorate %t2 Block
OpMemberDecorate %t2 0 NonWritable
OpMemberDecorate %t2 0 Offset 0
OpDecorate %incomingPtr Location 0
OpDecorate %incomingPtr AliasedPointer
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%fragColor = OpVariable %_ptr_Output_v4float Output
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_dataBuffer PhysicalStorageBuffer
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_t1 PhysicalStorageBuffer
%dataBuffer = OpTypeStruct %_ptr_PhysicalStorageBuffer_t1
OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_t2 PhysicalStorageBuffer
%t1 = OpTypeStruct %_ptr_PhysicalStorageBuffer_t2
%_runtimearr_v4float = OpTypeRuntimeArray %v4float
%t2 = OpTypeStruct %_runtimearr_v4float
%_ptr_PhysicalStorageBuffer_t2 = OpTypePointer PhysicalStorageBuffer %t2
%_ptr_PhysicalStorageBuffer_t1 = OpTypePointer PhysicalStorageBuffer %t1
%_ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer PhysicalStorageBuffer %dataBuffer
%_ptr_Input__ptr_PhysicalStorageBuffer_dataBuffer = OpTypePointer Input %_ptr_PhysicalStorageBuffer_dataBuffer
%incomingPtr = OpVariable %_ptr_Input__ptr_PhysicalStorageBuffer_dataBuffer Input
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_t1 = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_t1
%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_t2 = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_t2
%int_2 = OpConstant %int 2
%_ptr_PhysicalStorageBuffer_v4float = OpTypePointer PhysicalStorageBuffer %v4float
%main = OpFunction %void None %3
%5 = OpLabel
%19 = OpLoad %_ptr_PhysicalStorageBuffer_dataBuffer %incomingPtr
%23 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_t1 %19 %int_0
%24 = OpLoad %_ptr_PhysicalStorageBuffer_t1 %23 Aligned 4
%26 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_t2 %24 %int_0
%27 = OpLoad %_ptr_PhysicalStorageBuffer_t2 %26 Aligned 4
%30 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %27 %int_0 %int_2
%31 = OpLoad %v4float %30 Aligned 4
OpStore %fragColor %31
OpReturn
OpFunctionEnd
)";
m_errorMonitor->SetDesiredWarning("VUID-StandaloneSpirv-PhysicalStorageBuffer64-06314");
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_0, SPV_SOURCE_ASM);
m_errorMonitor->VerifyFound();
}
// More interface checks that require deeping spirv matching
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/11267
TEST_F(NegativeShaderInterface, DISABLED_NestedStructInBlock) {
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
const char vsSource[] = R"glsl(
#version 450
struct Foo {
vec2 a;
};
layout(location = 0) out block {
Foo foo;
} testBlock;
void main(void) {
testBlock.foo.a = vec2(0);
}
)glsl";
const char fsSource[] = R"glsl(
#version 450
layout(location = 0) out vec4 color;
struct Foo {
int a[8];
vec4 b;
};
layout(location = 0) in block {
Foo foo;
} testBlock;
void main(void) {
color = testBlock.foo.b;
}
)glsl";
VkShaderObj vs(*m_device, vsSource, VK_SHADER_STAGE_VERTEX_BIT);
VkShaderObj fs(*m_device, fsSource, VK_SHADER_STAGE_FRAGMENT_BIT);
auto set_info = [&](CreatePipelineHelper &info) { info.shader_stages_ = {vs.GetStageCreateInfo(), fs.GetStageCreateInfo()}; };
CreatePipelineHelper::OneshotTest(*this, set_info, kErrorBit, "VUID-RuntimeSpirv-OpEntryPoint-07754");
}
TEST_F(NegativeShaderInterface, MeshFragmentPerPrimitive) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::meshShader);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char* ms_source = R"glsl(
#version 460
#extension GL_EXT_mesh_shader : require
layout(max_vertices = 12) out;
layout(max_primitives = 4) out;
layout(triangles) out;
layout(location = 0) out uint out_0[12];
layout(location = 1) perprimitiveEXT out uint out_1[4];
layout(location = 2) out float out_2[12];
layout(location = 3) perprimitiveEXT out float out_3[4];
void main() {
SetMeshOutputsEXT(12,4);
out_0[0] = 0;
out_1[0] = 0;
out_2[0] = 0.0;
out_3[0] = 0.0;
gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0,1,2);
}
)glsl";
const char* fs_source = R"glsl(
#version 460
#extension GL_EXT_mesh_shader : require
layout(location = 0) in flat uint in_0;
layout(location = 1) flat in uint in_1; // missing perprimitiveEXT
layout(location = 2) in float in_2;
layout(location = 3) perprimitiveEXT in float in_3;
layout(location = 0) out vec4 c;
void main(){
c = vec4(1);
if (in_0 == 0 && in_1 == 0 && in_2 == 1.0 && in_3 == 1.0) {
c = vec4(0);
}
}
)glsl";
VkShaderObj ms(*m_device, ms_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2);
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()};
m_errorMonitor->SetDesiredWarning("VUID-RuntimeSpirv-OpVariable-08746");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, MeshFragmentPerPrimitive2) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::meshShader);
RETURN_IF_SKIP(Init());
InitRenderTarget();
const char* ms_source = R"glsl(
#version 460
#extension GL_EXT_mesh_shader : require
layout(max_vertices = 12) out;
layout(max_primitives = 4) out;
layout(triangles) out;
layout(location = 0) out float out_0[12];
layout(location = 1) out float out_1[12]; // missing perprimitiveEXT
void main() {
SetMeshOutputsEXT(12,4);
out_0[0] = 0.0;
out_1[0] = 0.0;
gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0,1,2);
}
)glsl";
const char* fs_source = R"glsl(
#version 460
#extension GL_EXT_mesh_shader : require
layout(location = 0) in float in_0;
layout(location = 1) in perprimitiveEXT float in_1;
layout(location = 0) out vec4 c;
void main(){
c = vec4(1);
if (in_0 == 1.0 && in_1 == 1.0) {
c = vec4(0);
}
}
)glsl";
VkShaderObj ms(*m_device, ms_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2);
VkShaderObj fs(*m_device, fs_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()};
m_errorMonitor->SetDesiredWarning("VUID-RuntimeSpirv-OpVariable-08746");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}
TEST_F(NegativeShaderInterface, MeshFragmentPerPrimitiveSlang) {
SetTargetApiVersion(VK_API_VERSION_1_2);
AddRequiredExtensions(VK_EXT_MESH_SHADER_EXTENSION_NAME);
AddRequiredFeature(vkt::Feature::meshShader);
RETURN_IF_SKIP(Init());
InitRenderTarget();
// https://godbolt.org/z/ov4G4K19a
// Known issue in slang https://github.com/shader-slang/slang/issues/7019
const char* spirv_source = R"(
OpCapability MeshShadingEXT
OpCapability Shader
OpExtension "SPV_KHR_non_semantic_info"
OpExtension "SPV_EXT_mesh_shader"
%2 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
OpMemoryModel Logical GLSL450
OpEntryPoint MeshEXT %main "main" %38 %gl_Position %verts_normal %prims_color %75
OpEntryPoint Fragment %main_0 "main" %entryPointParam_main %gl_FragCoord %input_normal %prim_color
OpExecutionMode %main OutputPrimitivesEXT 3
OpExecutionMode %main OutputVertices 9
OpExecutionMode %main LocalSize 1 1 1
OpExecutionMode %main OutputTrianglesEXT
OpExecutionMode %main_0 OriginUpperLeft
OpSource Slang 1
OpDecorate %38 BuiltIn PrimitiveTriangleIndicesEXT
OpDecorate %gl_Position BuiltIn Position
OpDecorate %verts_normal Location 0
OpDecorate %prims_color Location 1
OpDecorate %prims_color PerPrimitiveEXT
OpDecorate %75 BuiltIn CullPrimitiveEXT
OpDecorate %75 PerPrimitiveEXT
OpDecorate %gl_FragCoord BuiltIn FragCoord
OpDecorate %input_normal Location 0
OpDecorate %prim_color Location 1
OpDecorate %prim_color Flat
OpDecorate %entryPointParam_main Location 0
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%uint_5 = OpConstant %uint 5
%12 = OpTypeFunction %void
%uint_0 = OpConstant %uint 0
%uint_6 = OpConstant %uint 6
%uint_2 = OpConstant %uint 2
%v3uint = OpTypeVector %uint 3
%int = OpTypeInt 32 1
%int_3 = OpConstant %int 3
%_arr_v3uint_int_3 = OpTypeArray %v3uint %int_3
%_ptr_Output__arr_v3uint_int_3 = OpTypePointer Output %_arr_v3uint_int_3
%_ptr_Output_v3uint = OpTypePointer Output %v3uint
%41 = OpConstantComposite %v3uint %uint_0 %uint_0 %uint_0
%uint_18 = OpConstant %uint 18
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%int_9 = OpConstant %int 9
%_arr_v4float_int_9 = OpTypeArray %v4float %int_9
%_ptr_Output__arr_v4float_int_9 = OpTypePointer Output %_arr_v4float_int_9
%_ptr_Output_v4float = OpTypePointer Output %v4float
%uint_19 = OpConstant %uint 19
%uint_20 = OpConstant %uint 20
%_arr_v4float_int_3 = OpTypeArray %v4float %int_3
%_ptr_Output__arr_v4float_int_3 = OpTypePointer Output %_arr_v4float_int_3
%uint_21 = OpConstant %uint 21
%bool = OpTypeBool
%_arr_bool_int_3 = OpTypeArray %bool %int_3
%_ptr_Output__arr_bool_int_3 = OpTypePointer Output %_arr_bool_int_3
%_ptr_Output_bool = OpTypePointer Output %bool
%true = OpConstantTrue %bool
%uint_25 = OpConstant %uint 25
%uint_8 = OpConstant %uint 8
%_ptr_Input_v4float = OpTypePointer Input %v4float
%uint_27 = OpConstant %uint 27
%38 = OpVariable %_ptr_Output__arr_v3uint_int_3 Output
%gl_Position = OpVariable %_ptr_Output__arr_v4float_int_9 Output
%verts_normal = OpVariable %_ptr_Output__arr_v4float_int_9 Output
%prims_color = OpVariable %_ptr_Output__arr_v4float_int_3 Output
%75 = OpVariable %_ptr_Output__arr_bool_int_3 Output
%gl_FragCoord = OpVariable %_ptr_Input_v4float Input
%input_normal = OpVariable %_ptr_Input_v4float Input
%prim_color = OpVariable %_ptr_Input_v4float Input
%entryPointParam_main = OpVariable %_ptr_Output_v4float Output
%float_0 = OpConstant %float 0
%123 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
%main = OpFunction %void None %12
%13 = OpLabel
OpSetMeshOutputsEXT %uint_6 %uint_2
%40 = OpAccessChain %_ptr_Output_v3uint %38 %uint_0
OpStore %40 %41
%52 = OpAccessChain %_ptr_Output_v4float %gl_Position %uint_0
OpStore %52 %123
%61 = OpAccessChain %_ptr_Output_v4float %verts_normal %uint_0
OpStore %61 %123
%68 = OpAccessChain %_ptr_Output_v4float %prims_color %uint_0
OpStore %68 %123
%77 = OpAccessChain %_ptr_Output_bool %75 %uint_0
OpStore %77 %true
OpReturn
OpFunctionEnd
%main_0 = OpFunction %void None %12
%82 = OpLabel
%90 = OpLoad %v4float %gl_FragCoord
%93 = OpLoad %v4float %input_normal
%95 = OpLoad %v4float %prim_color
%100 = OpFAdd %v4float %95 %90
%101 = OpFAdd %v4float %100 %93
OpStore %entryPointParam_main %101
OpReturn
OpFunctionEnd
)";
VkShaderObj ms(*m_device, spirv_source, VK_SHADER_STAGE_MESH_BIT_EXT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM);
VkShaderObj fs(*m_device, spirv_source, VK_SHADER_STAGE_FRAGMENT_BIT, SPV_ENV_VULKAN_1_2, SPV_SOURCE_ASM);
CreatePipelineHelper pipe(*this);
pipe.shader_stages_ = {ms.GetStageCreateInfo(), fs.GetStageCreateInfo()};
m_errorMonitor->SetDesiredWarning("VUID-RuntimeSpirv-OpVariable-08746");
pipe.CreateGraphicsPipeline();
m_errorMonitor->VerifyFound();
}