// Copyright 2015 The Shaderc Authors. 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
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef COMMON_SHADERS_FOR_TESTS_H_
#define COMMON_SHADERS_FOR_TESTS_H_

#ifdef __cplusplus
extern "C" {
#endif

// The minimal shader, without a version directive.
const char kMinimalShaderWithoutVersion[] = "void main(){}";
// The minimal shader, with a version directive.
const char kMinimalShader[] =
    "#version 140\n"
    "void main(){}";
const char kMinimalHlslShader[] =
    "float4 EntryPoint(uint index : SV_VERTEXID) : SV_POSITION\n"
    "{ return float4(1.0, 2.0, 3.0, 4.0); }";
const char kMinimalShaderWithMacro[] =
    "#version 140\n"
    "#define E main\n"
    "void E(){}\n";

// The minimal shader that needs valueless predefinition of 'E' to compile.
const char kValuelessPredefinitionShader[] =
    "#version 140\n"
    "#ifdef E\n"
    "void main(){}\n"
    "#else\n"
    "#error\n"
    "#endif";

// By default the compiler will emit a warning on line 2 complaining
// that 'float' is a deprecated attribute in version 130.  Use verison 140
// because some versions of glslang will error out for a too-low version
// when generating SPIR-V.
const char kDeprecatedAttributeShader[] =
    "#version 400\n"
    "layout(location = 0) attribute float x;\n"
    "void main() {}\n";

// By default the compiler will emit a warning as version 550 is an unknown
// version.
const char kMinimalUnknownVersionShader[] =
    "#version 550\n"
    "void main() {}\n";

// gl_ClipDistance doesn't exist in es profile (at least until 3.10).
const char kCoreVertShaderWithoutVersion[] =
    "void main() {\n"
    "gl_ClipDistance[0] = 5.;\n"
    "}\n";

// Generated debug information should contain the name of the vector:
// debug_info_sample.
const char kMinimalDebugInfoShader[] =
    "#version 140\n"
    "void main(){\n"
    "vec2 debug_info_sample = vec2(1.0,1.0);\n"
    "}\n";

// Compiler should generate two errors.
const char kTwoErrorsShader[] =
    "#version 150\n"
    "#error\n"
    "#error\n"
    "void main(){}\n";

// Compiler should generate two warnings.
const char kTwoWarningsShader[] =
    "#version 400\n"
    "layout(location = 0) attribute float x;\n"
    "layout(location = 1) attribute float y;\n"
    "void main(){}\n";

// A shader that compiles under OpenGL compatibility profile rules,
// but not OpenGL core profile rules.
const char kOpenGLCompatibilityFragmentShader[] =
    R"(#version 100
     uniform highp sampler2D tex;
     void main() {
       gl_FragColor = texture2D(tex, vec2(0.0,0.0));
     })";

// A shader that compiles under OpenGL core profile rules.
const char kOpenGLVertexShader[] =
    R"(#version 330
       void main() { int t = gl_VertexID; })";

// Empty 310 es shader. It is valid for vertex, fragment, compute shader kind.
const char kEmpty310ESShader[] =
    "#version 310 es\n"
    "void main() {}\n";

// Vertex only shader.
const char kVertexOnlyShader[] =
    "#version 310 es\n"
    "void main() {\n"
    "    gl_Position = vec4(1.);\n"
    "}";

// TessControl only shader.
const char kTessControlOnlyShader[] =
    "#version 440 core\n"
    "layout(vertices = 3) out;\n"
    "void main() { }";

// TessEvaluation only shader.
const char kTessEvaluationOnlyShader[] =
    "#version 440 core\n"
    "layout(triangles) in;\n"
    "void main() { }";

// Geometry only shader.
const char kGeometryOnlyShader[] =
    "#version 150 core\n"
    "layout (triangles) in;\n"
    "layout (line_strip, max_vertices = 4) out;\n"
    "void main() { }";

// Vertex only shader with #pragma annotation.
const char kVertexOnlyShaderWithPragma[] =
    "#version 310 es\n"
    "#pragma shader_stage(vertex)\n"
    "void main() {\n"
    "    gl_Position = vec4(1.);\n"
    "}";

// Fragment only shader with #pragma annotation.
const char kFragmentOnlyShaderWithPragma[] =
    "#version 310 es\n"
    "#pragma shader_stage(fragment)\n"
    "void main() {\n"
    "    gl_FragDepth = 10.;\n"
    "}";

// TessControl only shader with #pragma annotation.
const char kTessControlOnlyShaderWithPragma[] =
    "#version 440 core\n"
    "#pragma shader_stage(tesscontrol)\n"
    "layout(vertices = 3) out;\n"
    "void main() { }";

// TessEvaluation only shader with #pragma annotation.
const char kTessEvaluationOnlyShaderWithPragma[] =
    "#version 440 core\n"
    "#pragma shader_stage(tesseval)\n"
    "layout(triangles) in;\n"
    "void main() { }";

// Geometry only shader with #pragma annotation.
const char kGeometryOnlyShaderWithPragma[] =
    "#version 150 core\n"
    "#pragma shader_stage(geometry)\n"
    "layout (triangles) in;\n"
    "layout (line_strip, max_vertices = 4) out;\n"
    "void main() { }";

// Compute only shader with #pragma annotation.
const char kComputeOnlyShaderWithPragma[] =
    "#version 310 es\n"
    "#pragma shader_stage(compute)\n"
    "void main() {\n"
    "    uvec3 temp = gl_WorkGroupID;\n"
    "}";

// NV mesh shader without #pragma.
const char kNVMeshShader[] =
    "#version 450\n"
    "#extension GL_NV_mesh_shader : enable\n"
    "layout(local_size_x=8) in;\n"
    "layout(max_vertices=5) out;\n"
    "layout(max_primitives=10) out;\n"
    "layout(triangles) out;\n"
    "void main() {\n"
    "  gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(0.0);\n"
    "}\n";

// NV mesh shader with #pragma annotation.
const char kNVMeshShaderWithPragma[] =
    "#version 450\n"
    "#extension GL_NV_mesh_shader : enable\n"
    "#pragma shader_stage(mesh)\n"
    "layout(local_size_x=8) in;\n"
    "layout(max_vertices=5) out;\n"
    "layout(max_primitives=10) out;\n"
    "layout(triangles) out;\n"
    "void main() {\n"
    "  gl_MeshVerticesNV[gl_LocalInvocationID.x].gl_Position = vec4(0.0);\n"
    "}\n";

// NV task shader without #pragma annotation.
const char kNVTaskShader[] =
    "#version 450\n"
    "#extension GL_NV_mesh_shader : enable\n"
    "layout(local_size_x=8) in;\n"
    "void main() {\n"
    "  gl_TaskCountNV = 2;\n"
    "}\n";

// NV task shader with #pragma annotation.
const char kNVTaskShaderWithPragma[] =
    "#version 450\n"
    "#extension GL_NV_mesh_shader : enable\n"
    "#pragma shader_stage(task)\n"
    "layout(local_size_x=8) in;\n"
    "void main() {\n"
    "  gl_TaskCountNV = 2;\n"
    "}\n";

// Vertex only shader with invalid #pragma annotation.
const char kVertexOnlyShaderWithInvalidPragma[] =
    "#version 310 es\n"
    "#pragma shader_stage(fragment)\n"
    "void main() {\n"
    "    gl_Position = vec4(1.);\n"
    "}";

// Parts of a valid disassembly of a minimal shader.  We only check certain
// parts since Glslang code generation changes in incidental ways.
const char* kMinimalShaderDisassemblySubstrings[] = {
    "; SPIR-V\n"
    "; Version: 1.0\n"
    "; Generator: Google Shaderc over Glslang; 11\n"
    "; Bound:",

    "               OpCapability Shader\n",
    "          %1 = OpExtInstImport \"GLSL.std.450\"\n",
    "               OpMemoryModel Logical GLSL450\n",
    "               OpReturn\n",
    "               OpFunctionEnd\n"};

const char* kMinimalShaderDebugInfoDisassemblySubstrings[] = {
    "; SPIR-V\n"
    "; Version: 1.0\n"
    "; Generator: Google Shaderc over Glslang; 11\n"
    "; Bound:",

    "               OpCapability Shader\n",
    "          %2 = OpExtInstImport \"GLSL.std.450\"\n",
    "               OpMemoryModel Logical GLSL450\n",
    "               OpReturn\n",
    "               OpFunctionEnd\n"};

const char kMinimalShaderAssembly[] = R"(
    ; SPIR-V
    ; Version: 1.0
    ; Generator: Google Shaderc over Glslang; 11
    ; Bound: 6
    ; Schema: 0

         OpCapability Shader
    %1 = OpExtInstImport "GLSL.std.450"
         OpMemoryModel Logical GLSL450
         OpEntryPoint Vertex %4 "main"
         OpSource ESSL 310
         OpName %4 "main"
    %2 = OpTypeVoid
    %3 = OpTypeFunction %2
    %4 = OpFunction %2 None %3
    %5 = OpLabel
         OpReturn
         OpFunctionEnd)";

const char kShaderWithUniformsWithoutBindings[] =
    R"(#version 450
       #extension GL_ARB_sparse_texture2 : enable
       uniform texture2D my_tex;
       uniform sampler my_sam;
       layout(rgba32f) uniform image2D my_img;
       layout(rgba32f) uniform imageBuffer my_imbuf;
       uniform block { float x; float y; } my_ubo;
       void main() {
         texture(sampler2D(my_tex,my_sam),vec2(1.0));
         vec4 t;
         sparseImageLoadARB(my_img,ivec2(0),t);
         imageLoad(my_imbuf,42);
         float x = my_ubo.x;
       })";

// A GLSL vertex shader with a weirdly packed block.
const char kGlslShaderWeirdPacking[] =
    R"(#version 450
       layout(set=0, binding=0)
       buffer B { float x; vec3 foo; } my_ssbo;
       void main() { my_ssbo.x = 1.0; })";

// A HLSL fragment shader with a weirdly packed block.
const char kHlslFragShaderWithRegisters[] =
    R"(Buffer<float> t4 : register(t4);
       Buffer<float> t5 : register(t5);
       float4 main() : SV_Target0 {
         return float4(t4.Load(0) + t5.Load(1));
       })";

// A GLSL compute shader using a regular barrier.
const char kGlslShaderComputeBarrier[] =
    R"(#version 450
       void main() { barrier(); })";

// A GLSL compute shader using the Subgroups feature.
const char kGlslShaderComputeSubgroupBarrier[] =
    R"(#version 450
       #extension GL_KHR_shader_subgroup_basic : enable
       void main() { subgroupBarrier(); })";

// A GLSL task shader using a regular barrier.
const char kGlslShaderTaskBarrier[] =
    R"(#version 450
       #extension GL_NV_mesh_shader : enable
       layout(local_size_x = 32) in;
       void main() { barrier(); })";

// A GLSL task shader using the Subgroups feature.
const char kGlslShaderTaskSubgroupBarrier[] =
    R"(#version 450
       #extension GL_NV_mesh_shader : enable
       #extension GL_KHR_shader_subgroup_basic : enable
       layout(local_size_x = 32) in;
       void main() { subgroupBarrier(); })";

// A GLSL mesh shader using a regular barrier.
const char kGlslShaderMeshBarrier[] =
    R"(#version 450
       #extension GL_NV_mesh_shader : enable
       layout(local_size_x = 32) in;
       layout(max_vertices=81) out;
       layout(max_primitives=32) out;
       layout(triangles) out;
       void main() { barrier(); })";

// A GLSL mesh shader using the Subgroups feature.
const char kGlslShaderMeshSubgroupBarrier[] =
    R"(#version 450
       #extension GL_NV_mesh_shader : enable
       #extension GL_KHR_shader_subgroup_basic : enable
       layout(local_size_x = 32) in;
       layout(max_vertices=81) out;
       layout(max_primitives=32) out;
       layout(triangles) out;
       void main() { subgroupBarrier(); })";

const char kGlslMultipleFnShader[] =
    R"(#version 450
       layout(location=0) flat in  int inVal;
       layout(location=0)      out int outVal;
       int foo(int a) { return a; }
       void main() { outVal = foo(inVal); })";

const char kHlslShaderWithCounterBuffer[] =
    R"(RWStructuredBuffer<uint> Ainc;
       float4 main() : SV_Target0 {
         return float4(Ainc.IncrementCounter(), 0, 0, 0);
       })";

const char kHlslWaveActiveSumeComputeShader[] =
  R"(struct S { uint val; uint result; };

     [[vk::binding(0,0)]]
     RWStructuredBuffer<S> MyBuffer;

     [numthreads(32, 1, 1)]
     void main(uint3 id : SV_DispatchThreadID) {
       MyBuffer[id.x].result = WaveActiveSum(MyBuffer[id.x].val);
     })";

const char kHlslMemLayoutResourceSelect[] =
    R"(cbuffer Foo { float a; float3 b; }

       [[vk::binding(0,0)]]
       Texture2D Tex;
       [[vk::binding(1,0)]]
       SamplerState Sampler1;
       [[vk::binding(2,0)]]
       SamplerState Sampler2;

       static const int val = 42;

       float4 main() : SV_Target {
         SamplerState samp;

         if (val > 5)
           samp = Sampler1;
         else
           samp = Sampler2;

         return Tex.Sample(samp, float2(0.5, 0.5)) + float4(a, b);
       })";

const char kGlslShaderWithClamp[] =
    R"(#version 450
    layout(location=0) in vec4 i;
    layout(location=0) out vec4 o;
    void main() { o = clamp(i, vec4(0.5), vec4(1.0)); }
    )";

#ifdef __cplusplus
}
#endif  // __cplusplus

#endif  // COMMON_SHADERS_FOR_TESTS_H_
