/****************************************************************************** * The MIT License (MIT) * * Copyright (c) 2019-2025 Baldur Karlsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ #include #include "3rdparty/fmt/core.h" #include "vk_test.h" RD_TEST(VK_Shader_Debug_Zoo, VulkanGraphicsTest) { static constexpr const char *Description = "Tests shader debugging on SPIR-V opcodes."; struct ConstsA2V { Vec4f pos; float zero; float one; float negone; Vec2f uv; }; struct PushData { Vec4i push; Vec2u bda_uvec2; uint32_t bda_hi; uint32_t bda_lo; uint64_t bda_u64; }; struct BDA_Data { float f32[8]; }; std::string v2f = R"EOSHADER( struct flatv2f { uint test; uint intval; }; struct v2f { vec2 zeroVal; vec2 inpos; vec2 inposIncreased; float tinyVal; float oneVal; float negoneVal; }; layout(location = 1) inout_type flat flatv2f flatData; layout(location = 3) inout_type v2f linearData; )EOSHADER"; std::string vertex = R"EOSHADER( #version 430 core #define inout_type out )EOSHADER" + v2f + R"EOSHADER( layout(location = 0) in vec4 pos; layout(location = 1) in float zero; layout(location = 2) in float one; layout(location = 3) in float negone; void main() { int test = gl_InstanceIndex; gl_Position = vec4(pos.x + pos.z * float(test % 256), pos.y + pos.w * float(test / 256), 0.0, 1.0); const vec4 verts[4] = vec4[4](vec4(-1.0, -1.0, 0.5, 1.0), vec4(1.0, -1.0, 0.5, 1.0), vec4(-1.0, 1.0, 0.5, 1.0), vec4(1.0, 1.0, 0.5, 1.0)); const vec2 data[3] = vec2[3](vec2(10.0f, 10.0f), vec2(20.0f, 10.0f), vec2(10.0f, 20.0f)); linearData.zeroVal = zero.xx; linearData.oneVal = one; linearData.negoneVal = negone; linearData.tinyVal = one * 1.0e-30; linearData.inpos = data[gl_VertexIndex]; linearData.inposIncreased = data[gl_VertexIndex] * 2.75f; flatData.test = test; flatData.intval = test + 7; } )EOSHADER"; std::string pixel_glsl_header = R"EOSHADER( #version 460 core #extension GL_EXT_samplerless_texture_functions : require #extension GL_EXT_nonuniform_qualifier : require #define TEST_DESC_INDEXING layout(set = 0, binding = 10, std140) uniform constsbuf { vec4 first; uint uniformIndex; vec4 second; vec4 nan; vec4 third; vec4 pad3; vec4 fourth; vec4 unorm2PackSource; vec4 snorm2PackSource; vec4 unorm4PackSource; vec4 snorm4PackSource; vec4 halfPackSource; uint unormUnpackSource; uint snormUnpackSource; uint halfUnpackSource; uint pad; } cbuf; layout(set = 0, binding = 11) uniform sampler pointSampler; layout(set = 0, binding = 12) uniform sampler linearSampler; layout(set = 0, binding = 13) uniform texture2D sampledImage; layout(set = 0, binding = 14) uniform sampler2D linearSampledImage; struct dummy { uvec4 val; uvec4 val2; }; layout(set = 0, binding = 15, std430) buffer storebuftype { layout(row_major) mat4 a; layout(column_major) mat4 b; vec4 x; dummy y; vec4 arr[]; } storebuf; layout(set = 0, binding = 16, rgba32f) uniform coherent image2D storeImage; layout(set = 0, binding = 17) uniform samplerBuffer texBuffer; layout(set = 0, binding = 18, rgba32f) uniform coherent imageBuffer storeTexBuffer; layout(set = 0, binding = 19) uniform sampler shadowSampler; layout(set = 0, binding = 20) uniform samplerCube cubeSampler; layout(set = 0, binding = 21, std430) buffer atomicbuftype { uvec4 data[]; } atomicbuf; layout(set = 0, r32ui, binding = 22) uniform uimage2D atomicimg; layout(set = 0, binding = 30) uniform sampler2DArray queryTest; layout(set = 0, binding = 31) uniform sampler2DMSArray queryTestMS; layout(set = 0, binding = 32) uniform texture2D depthImage; layout(set = 0, binding = 33) uniform samplerBuffer texBuffer1010102unorm; layout(set = 0, binding = 34, rgb10_a2) uniform imageBuffer storeTexBuffer1010102unorm; layout(set = 0, binding = 35) uniform usamplerBuffer texBuffer1010102uint; layout(set = 0, binding = 36, rgb10_a2ui) uniform uimageBuffer storeTexBuffer1010102uint; #if TEST_DESC_INDEXING layout(set = 1, binding = 1) uniform sampler pointSamplers[14]; layout(set = 1, binding = 2) uniform sampler linearSamplers[14]; layout(set = 1, binding = 3) uniform texture2D sampledImages[14]; layout(set = 1, binding = 4) uniform sampler2D linearSampledImages[14]; layout(set = 1, binding = 5, std430) buffer storebufstype { vec4 x; dummy y; vec4 arr[]; } storebufs[14]; layout(set = 1, binding = 6, rgba32f) uniform coherent image2D storeImages[14]; layout(set = 1, binding = 7) uniform samplerBuffer texBuffers[14]; layout(set = 1, binding = 8, rgba32f) uniform coherent imageBuffer storeTexBuffers[14]; layout(set = 1, binding = 9) uniform sampler shadowSamplers[14]; layout(set = 1, binding = 20) uniform sampler2DArray queryTests[14]; layout(set = 1, binding = 21) uniform sampler2DMSArray queryTestsMS[14]; layout(set = 2, binding = 0) uniform sampler1D zoo_1D; layout(set = 2, binding = 1) uniform sampler2D zoo_2D; layout(set = 2, binding = 2) uniform sampler3D zoo_3D; layout(set = 2, binding = 3) uniform samplerCube zoo_Cube; layout(set = 2, binding = 4) uniform sampler1DArray zoo_1DArray; layout(set = 2, binding = 5) uniform sampler2DArray zoo_2DArray; layout(set = 2, binding = 6) uniform samplerCubeArray zoo_CubeArray; layout(set = 2, binding = 7) uniform sampler2DMS zoo_2DMS; layout(set = 2, binding = 8) uniform sampler2DMSArray zoo_2DMSArray; layout(set = 2, binding = 9) uniform samplerBuffer zoo_Buffer; layout(set = 2, binding = 10) uniform usampler1D zoo_u1D; layout(set = 2, binding = 11) uniform usampler2D zoo_u2D; layout(set = 2, binding = 12) uniform usampler3D zoo_u3D; layout(set = 2, binding = 13) uniform usamplerCube zoo_uCube; layout(set = 2, binding = 14) uniform usampler1DArray zoo_u1DArray; layout(set = 2, binding = 15) uniform usampler2DArray zoo_u2DArray; layout(set = 2, binding = 16) uniform usamplerCubeArray zoo_uCubeArray; layout(set = 2, binding = 17) uniform usampler2DMS zoo_u2DMS; layout(set = 2, binding = 18) uniform usampler2DMSArray zoo_u2DMSArray; layout(set = 2, binding = 19) uniform usamplerBuffer zoo_uBuffer; layout(set = 2, binding = 20) uniform isampler1D zoo_i1D; layout(set = 2, binding = 21) uniform isampler2D zoo_i2D; layout(set = 2, binding = 22) uniform isampler3D zoo_i3D; layout(set = 2, binding = 23) uniform isamplerCube zoo_iCube; layout(set = 2, binding = 24) uniform isampler1DArray zoo_i1DArray; layout(set = 2, binding = 25) uniform isampler2DArray zoo_i2DArray; layout(set = 2, binding = 26) uniform isamplerCubeArray zoo_iCubeArray; layout(set = 2, binding = 27) uniform isampler2DMS zoo_i2DMS; layout(set = 2, binding = 28) uniform isampler2DMSArray zoo_i2DMSArray; layout(set = 2, binding = 29) uniform isamplerBuffer zoo_iBuffer; layout(set = 2, rgba32f, binding = 30) uniform image1D storezoo_1D; layout(set = 2, rgba32f, binding = 31) uniform image2D storezoo_2D; layout(set = 2, rgba32f, binding = 32) uniform image3D storezoo_3D; layout(set = 2, rgba32f, binding = 33) uniform imageCube storezoo_Cube; layout(set = 2, rgba32f, binding = 34) uniform image1DArray storezoo_1DArray; layout(set = 2, rgba32f, binding = 35) uniform image2DArray storezoo_2DArray; layout(set = 2, rgba32f, binding = 36) uniform imageCubeArray storezoo_CubeArray; //layout(set = 2, rgba32f, binding = 37) uniform image2DMS storezoo_2DMS; //layout(set = 2, rgba32f, binding = 38) uniform image2DMSArray storezoo_2DMSArray; layout(set = 2, rgba32f, binding = 39) uniform imageBuffer storezoo_Buffer; layout(set = 2, rgba32ui, binding = 40) uniform uimage1D storezoo_u1D; layout(set = 2, rgba32ui, binding = 41) uniform uimage2D storezoo_u2D; layout(set = 2, rgba32ui, binding = 42) uniform uimage3D storezoo_u3D; layout(set = 2, rgba32ui, binding = 43) uniform uimageCube storezoo_uCube; layout(set = 2, rgba32ui, binding = 44) uniform uimage1DArray storezoo_u1DArray; layout(set = 2, rgba32ui, binding = 45) uniform uimage2DArray storezoo_u2DArray; layout(set = 2, rgba32ui, binding = 46) uniform uimageCubeArray storezoo_uCubeArray; //layout(set = 2, rgba32ui, binding = 47) uniform uimage2DMS storezoo_u2DMS; //layout(set = 2, rgba32ui, binding = 48) uniform uimage2DMSArray storezoo_u2DMSArray; layout(set = 2, rgba32ui, binding = 49) uniform uimageBuffer storezoo_uBuffer; layout(set = 2, rgba32i, binding = 50) uniform iimage1D storezoo_i1D; layout(set = 2, rgba32i, binding = 51) uniform iimage2D storezoo_i2D; layout(set = 2, rgba32i, binding = 52) uniform iimage3D storezoo_i3D; layout(set = 2, rgba32i, binding = 53) uniform iimageCube storezoo_iCube; layout(set = 2, rgba32i, binding = 54) uniform iimage1DArray storezoo_i1DArray; layout(set = 2, rgba32i, binding = 55) uniform iimage2DArray storezoo_i2DArray; layout(set = 2, rgba32i, binding = 56) uniform iimageCubeArray storezoo_iCubeArray; //layout(set = 2, rgba32i, binding = 57) uniform iimage2DMS storezoo_i2DMS; //layout(set = 2, rgba32i, binding = 58) uniform iimage2DMSArray storezoo_i2DMSArray; layout(set = 2, rgba32i, binding = 59) uniform iimageBuffer storezoo_iBuffer; #endif layout(push_constant) uniform PushData { layout(offset = 16) ivec4 data; } push; )EOSHADER"; std::string pixel_glsl1 = pixel_glsl_header + R"EOSHADER( layout(location = 0, index = 0) out vec4 Color; #define inout_type in )EOSHADER" + v2f + R"EOSHADER( vec4 varscope_test(int coord, vec2 inpos_param, vec2 inpos_incr_param) { float never_in_scope; if(coord < 0) { never_in_scope = inpos_param.x; never_in_scope *= 2.0f; } vec4 ret; // for the first pixel ret comes into scope early if(coord == 0) { ret = vec4(0.5, 0.5, 0.5, 0.0); } float long_scope; { float short_scope; short_scope = inpos_param.y; short_scope = sin(short_scope); long_scope = short_scope * inpos_incr_param.x; } if(coord != 0) { ret = vec4(1.0, 1.0, 1.0, 0.0); } ret.w += long_scope; ret *= 1.5f; return ret; } void main() { float posinf = linearData.oneVal/linearData.zeroVal.x; float neginf = linearData.negoneVal/linearData.zeroVal.x; float nan = linearData.zeroVal.x/linearData.zeroVal.y; nan *= cbuf.nan.x; float negone = linearData.negoneVal; float posone = linearData.oneVal; float zerof = linearData.zeroVal.x; float tiny = linearData.tinyVal; int intval = int(flatData.intval); uint zerou = flatData.intval - flatData.test - 7u; int zeroi = int(zerou); uint test = flatData.test; vec2 inpos = linearData.inpos; vec2 inposIncreased = linearData.inposIncreased; ivec2 localCoord = ivec2(gl_FragCoord) % ivec2(4, 4); int flatLocalCoord = localCoord.x + localCoord.y * 4; int flatGlobalCoord = int(gl_FragCoord.x) + int(gl_FragCoord.y) * 1024; Color = vec4(0,0,0,0); switch(test) { case 0: { Color = gl_FragCoord; break; } case 1: { Color = dFdx(gl_FragCoord); break; } case 2: { Color = dFdy(gl_FragCoord); break; } case 3: { Color = dFdxCoarse(gl_FragCoord); break; } case 4: { Color = dFdyCoarse(gl_FragCoord); break; } case 5: { Color = dFdxFine(gl_FragCoord); break; } case 6: { Color = dFdyFine(gl_FragCoord); break; } case 7: { Color = dFdx(vec4(inpos, inposIncreased)); break; } case 8: { Color = dFdy(vec4(inpos, inposIncreased)); break; } case 9: { Color = dFdxCoarse(vec4(inpos, inposIncreased)); break; } case 10: { Color = dFdyCoarse(vec4(inpos, inposIncreased)); break; } case 11: { Color = dFdxFine(vec4(inpos, inposIncreased)); break; } case 12: { Color = dFdyFine(vec4(inpos, inposIncreased)); break; } case 13: { Color = vec4(abs(posone*2.5f), abs(negone*2.5f), abs(zerof*2.5f), 1.0f); break; } case 14: { Color = vec4(pow(posone*2.5f, posone*1.3f), pow(posone*2.5f, posone*0.45f), pow(vec2(posone*2.5f, posone*1.3f), vec2(posone*0.9f, posone*8.5f))); break; } case 15: { Color = vec4(normalize(posone*2.5f), normalize(posone), normalize(negone), 1.0f); break; } case 16: { Color = vec4(normalize(vec2(posone*2.5f, negone*1.8f)), normalize(vec2(posone*8.5f, negone*7.1f))); break; } case 17: { Color = vec4(normalize(vec3(posone*2.5f, negone*1.8f, posone*8.5f)), 1.0f); break; } case 18: { Color = normalize(vec4(posone*2.5f, negone*1.8f, posone*8.5f, negone*5.2f)); break; } case 19: { Color = vec4(floor(posone*2.5f), floor(posone*2.4f), floor(posone*2.6f), floor(zerof)); break; } case 20: { Color = vec4(floor(negone*2.5f), floor(negone*2.4f), floor(negone*2.6f), 1.0f); break; } case 21: { Color = vec4(mix(posone*1.1f, posone*3.3f, 0.5f), mix(posone*1.1f, posone*3.3f, 0.2f), mix(posone*1.1f, posone*3.3f, 0.8f), 1.0f); break; } case 22: { Color = vec4(mix(posone*1.1f, posone*3.3f, 1.5f), mix(posone*1.1f, posone*3.3f, -0.3f), 0.0f, 1.0f); break; } case 23: { Color = vec4(mix(posone*3.3f, posone*1.1f, 0.5f), mix(posone*3.3f, posone*1.1f, 0.2f), mix(posone*3.3f, posone*1.1f, 0.8f), 1.0f); break; } case 24: { vec3 a = vec3(posone*2.5f, negone*1.8f, posone*8.5f); vec3 b = vec3(negone*6.3f, posone*3.2f, negone*0.4f); Color = vec4(cross(a, b), 1.0f); break; } case 25: { vec4 a = vec4(posone*2.5f, negone*1.8f, posone*8.5f, posone*3.9f); vec4 b = vec4(negone*6.3f, posone*3.2f, negone*0.4f, zerof); Color = vec4(dot(a.xyz, b.xyz), dot(a.w, b.w), dot(a, b), dot(a.wz, b.ww)); break; } case 26: { Color = cbuf.first; break; } case 27: { Color = cbuf.second; break; } case 28: { Color = cbuf.third; break; } case 29: { Color = cbuf.fourth; break; } case 30: { Color = cbuf.first + cbuf.second + cbuf.third + cbuf.fourth + cbuf.pad3; break; } case 31: { ivec2 coord = ivec2(zeroi + 20, zeroi + 20); Color = texelFetch(sampledImage, coord, 0); break; } case 32: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImage, pointSampler), coord, 0.0); break; } case 33: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImage, linearSampler), coord, 0.0); break; } case 34: { Color = texture(linearSampledImage, inpos); break; } case 35: { Color = vec4(max(posone*3.3f, posone*4.4f), max(posone*4.4f, posone*3.3f), max(posone, posinf), max(posone, neginf)); break; } case 36: { Color = vec4(max(negone*3.3f, negone*4.4f), max(negone*4.4f, negone*3.3f), max(negone, posinf), max(negone, neginf)); break; } case 37: { Color = vec4(min(posone*3.3f, posone*4.4f), min(posone*4.4f, posone*3.3f), min(posone, posinf), min(posone, neginf)); break; } case 38: { Color = vec4(min(negone*3.3f, negone*4.4f), min(negone*4.4f, negone*3.3f), min(negone, posinf), min(negone, neginf)); break; } case 39: { Color = vec4(float(max(zeroi+5, zeroi+8)), float(max(zeroi+8, zeroi+5)), float(max(zeroi-8, zeroi-5)), float(max(zeroi-5, zeroi-8))); break; } case 40: { Color = vec4(float(min(zeroi+5, zeroi+8)), float(min(zeroi+8, zeroi+5)), float(min(zeroi-8, zeroi-5)), float(min(zeroi-5, zeroi-8))); break; } case 41: { Color = vec4(float(max(zerou+5, zerou+8)), float(max(zerou+8, zerou+5)), float(min(zerou+8, zerou+5)), float(min(zerou+5, zerou+8))); break; } case 42: { Color = vec4(clamp(posone*3.3f, posone, posone*5.0f), clamp(posone*0.3f, posone, posone*5.0f), clamp(posone*8.3f, posone, posone*5.0f), 1.0f); break; } case 43: { uint x = uint(posone); Color = vec4(float(clamp(x*4, zerou+2, zerou+50)), float(clamp(x, zerou+2, zerou+50)), float(clamp(x*400, zerou+2, zerou+50)), 1.0f); break; } case 44: { int x = int(posone); Color = vec4(float(clamp(x*4, zeroi+2, zeroi+50)), float(clamp(x, zeroi+2, zeroi+50)), float(clamp(x*400, zeroi+2, zeroi+50)), 1.0f); break; } case 45: { Color = vec4(float(abs(zeroi+2)), float(abs(zeroi)), float(abs(zeroi-5)), 1.0f); break; } case 46: { Color = fwidth(gl_FragCoord); break; } case 47: { Color = fwidthCoarse(gl_FragCoord); break; } case 48: { Color = fwidthFine(gl_FragCoord); break; } case 49: { Color = fwidth(vec4(inpos, inposIncreased)); break; } case 50: { Color = fwidthCoarse(vec4(inpos, inposIncreased)); break; } )EOSHADER" R"EOSHADER( case 51: { Color = fwidthFine(vec4(inpos, inposIncreased)); break; } case 52: { Color = vec4(isinf(posone) ? 1.0f : 0.0f, isinf(zerof) ? 1.0f : 0.0f, isinf(negone) ? 1.0f : 0.0f, 1.0f); break; } case 53: { Color = vec4(isnan(posone) ? 1.0f : 0.0f, isnan(zerof) ? 1.0f : 0.0f, isnan(negone) ? 1.0f : 0.0f, 1.0f); break; } case 54: { Color = vec4(isinf(posinf) ? 1.0f : 0.0f, isinf(neginf) ? 1.0f : 0.0f, isinf(nan) ? 1.0f : 0.0f, 1.0f); break; } case 55: { Color = vec4(isnan(posinf) ? 1.0f : 0.0f, isnan(neginf) ? 1.0f : 0.0f, isnan(nan) ? 1.0f : 0.0f, 1.0f); break; } case 56: { Color = vec4(push.data); break; } case 57: { Color = vec4(roundEven(posone*2.5f), roundEven(posone*3.5f), roundEven(posone*4.5f), roundEven(posone*5.1f)); break; } case 58: { Color = vec4(roundEven(negone*2.5f), roundEven(negone*3.5f), roundEven(negone*4.5f), roundEven(negone*5.1f)); break; } case 59: { // avoid implementation-defined behaviour at half-way points Color = vec4(round(posone*2.4f), round(posone*3.6f), round(posone*4.6f), round(posone*5.1f)); break; } case 60: { Color = vec4(round(negone*2.6f), round(negone*3.6f), round(negone*4.6f), round(posone*5.1f)); break; } case 61: { Color = vec4(trunc(posone*2.4f), trunc(posone*2.5f), trunc(posone*2.6f), trunc(posone*5.1f)); break; } case 62: { Color = vec4(trunc(negone*2.4f), trunc(negone*2.5f), trunc(negone*2.6f), trunc(negone*3.1f)); break; } case 63: { Color = vec4(fract(posone*2.4f), fract(posone*2.5f), fract(posone*2.6f), fract(posone*3.1f)); break; } case 64: { Color = vec4(fract(negone*2.4f), fract(negone*2.5f), fract(negone*2.6f), fract(negone*3.1f)); break; } case 65: { Color = vec4(ceil(posone*2.4f), ceil(posone*2.5f), ceil(posone*2.6f), ceil(posone*3.1f)); break; } case 66: { Color = vec4(ceil(negone*2.4f), ceil(negone*2.5f), ceil(negone*2.6f), ceil(negone*3.1f)); break; } case 67: { Color = vec4(sign(negone*2.4f), sign(posone*2.4f), sign(posinf), sign(neginf)); break; } case 68: { int onei = zeroi+1; int negi = zeroi-1; Color = vec4(float(sign(onei*2)), float(sign(negi*2)), float(sign(0)), 1.0f); break; } case 69: { Color = vec4(degrees(negone*2.4f), degrees(posone*2.4f), degrees(zerof), degrees(posone*34.56f)); break; } case 70: { Color = vec4(radians(negone*164.2f), radians(posone*164.2f), radians(zerof), radians(posone*3456.78f)); break; } case 71: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); vec4 b = vec4(zerof+2.5f, zerof+2.5f, zerof+2.5f, zerof+2.5f); Color = vec4(float(a.x < b.x), float(a.x <= b.x), float(a.x > b.x), float(a.x >= b.x)); break; } case 72: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); vec4 b = vec4(zerof+2.5f, zerof+2.5f, zerof+2.5f, zerof+2.5f); bvec4 c = lessThanEqual(a, b); Color = vec4(float(a.x == b.x), float(a.x != b.x), 0.0f, 1.0f); break; } case 73: { ivec4 a = ivec4(zeroi+2, zeroi+3, zeroi+4, zeroi+5); ivec4 b = ivec4(zeroi+4, zeroi+4, zeroi+4, zeroi+4); Color = vec4(float(a.x < b.x), float(a.x <= b.x), float(a.x > b.x), float(a.x >= b.x)); break; } case 74: { ivec4 a = ivec4(zeroi+2, zeroi+3, zeroi+4, zeroi+5); ivec4 b = ivec4(zeroi+4, zeroi+4, zeroi+4, zeroi+4); Color = vec4(float(a.x == b.x), float(a.x != b.x), 0.0f, 1.0f); break; } case 75: { uvec4 a = uvec4(zerou+2, zerou+3, zerou+4, zerou+5); uvec4 b = uvec4(zerou+4, zerou+4, zerou+4, zerou+4); Color = vec4(float(a.x < b.x), float(a.x <= b.x), float(a.x > b.x), float(a.x >= b.x)); break; } case 76: { uvec4 a = uvec4(zerou+2, zerou+3, zerou+4, zerou+5); uvec4 b = uvec4(zerou+4, zerou+4, zerou+4, zerou+4); Color = vec4(float(a.x == b.x), float(a.x != b.x), 0.0f, 1.0f); break; } case 77: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); vec4 b = vec4(zerof+2.5f, zerof+2.5f, zerof+2.5f, zerof+2.5f); bvec4 c = lessThanEqual(a, b); Color = vec4(float(any(c)), float(all(c)), float(c.x == c.z), float(c.x != c.w)); break; } case 78: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); vec4 b = vec4(zerof+2.5f, zerof+2.5f, zerof+2.5f, zerof+2.5f); bvec4 c = lessThanEqual(a, b); Color = vec4(float(c.x || c.y), float(c.x && c.y), float(!c.x), 1.0f); break; } case 79: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); vec4 b = vec4(zerof+2.5f, zerof+2.5f, zerof+2.5f, zerof+2.5f); bvec4 c = lessThanEqual(a, b); Color = mix(vec4(posone*9.0f, posone*8.0f, posone*7.0f, posone*6.0f), vec4(posone*1.0f, posone*2.0f, posone*3.0f, posone*4.0f), c); break; } case 80: { discard; } case 81: { Color = vec4(sin(posone*2.4f), cos(posone*2.4f), asin(posone*2.4f), acos(posone*2.4f)); break; } case 82: { Color = vec4(sinh(posone*2.4f), cosh(posone*2.4f), asinh(posone*2.4f), acosh(posone*2.4f)); break; } case 83: { Color = vec4(tan(posone*2.4f), tanh(posone*2.4f), atan(posone*2.4f), atanh(posone*2.4f)); break; } case 84: { Color = vec4(atan(posone*2.4f, posone*5.7f), sqrt(posone*2.4f), inversesqrt(posone*2.4f), 1.0f); break; } case 85: { Color = vec4(log(posone*2.4f), log2(posone*2.4f), exp(posone*2.4f), exp2(posone*2.4f)); break; } case 86: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); vec4 b = vec4(zerof+2.5f, zerof+2.5f, zerof+2.5f, zerof+2.5f); Color = vec4(length(a), length(b), distance(a, b), 1.0f); break; } case 87: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); Color = normalize(a); break; } case 88: { vec4 a = vec4(posone*2.4f, posone*2.5f, posone*2.6f, posone*2.7f); vec4 b = vec4(zerof+2.5f, zerof+2.5f, zerof+2.5f, zerof+2.5f); Color = refract(a, b, zerof+3.1f); break; } case 89: { Color = vec4(fma(zerof+2.4f, posone*0.1f, posone*8.3f), fma(zerof+2.4f, posone*0.0f, posone*8.3f), fma(zerof+3.675f, posone*9.703f, posone*1.45f), ((zerof+3.675f) * (posone*9.703f)) + posone*1.45f); break; } case 90: { Color = vec4(step(posone*2.6f, zerof+2.4f), step(posone*2.6f, zerof+2.5f), step(posone*2.6f, zerof+2.6f), step(posone*2.6f, zerof+2.7f)); break; } case 91: { Color = vec4(smoothstep(posone*2.0f, posone*2.6f, zerof+1.9f), smoothstep(posone*2.0f, posone*2.6f, zerof+2.0f), smoothstep(posone*2.0f, posone*2.6f, zerof+2.1f), smoothstep(posone*2.0f, posone*2.6f, zerof+2.3f)); break; } case 92: { Color = vec4(smoothstep(posone*2.0f, posone*2.6f, zerof+2.4f), smoothstep(posone*2.0f, posone*2.6f, zerof+2.5f), smoothstep(posone*2.0f, posone*2.6f, zerof+2.6f), smoothstep(posone*2.0f, posone*2.6f, zerof+2.8f)); break; } case 93: { vec4 N = vec4(posone*1.4f, posone*2.8f, posone*5.6f, posone*4.4f); vec4 I = vec4(posone*3.7f, posone*2.2f, posone*6.1f, posone*9.5f); vec4 Nref = vec4(posone*6.4f, posone*7.5f, posone*8.3f, posone*0.9f); Color = faceforward(N, I, Nref); break; } case 94: { vec4 N = vec4(posone*1.4f, posone*2.8f, posone*5.6f, posone*4.4f); vec4 I = vec4(posone*3.7f, posone*2.2f, posone*6.1f, posone*9.5f); Color = reflect(N, I); break; } case 95: { Color = vec4(ldexp(posone*1.4f, zeroi-3), ldexp(posone*2.8f, zeroi+0), ldexp(posone*5.6f, zeroi+3), ldexp(posone*4.4f, zeroi+7)); break; } case 96: { uint a = zerou + 0xb0b0b0b0; uint b = zerou + 0x12345678; // add and sub with no carry/borrow uint y; uint x = uaddCarry(a, b, y); uint w; uint z = usubBorrow(a, b, w); Color = vec4(float(x), float(y), float(z), float(w)); break; } case 97: { uint a = zerou + 0xb0b0b0b0; uint b = zerou + 0xdeadbeef; // add and sub with carry/borrow uint y; uint x = uaddCarry(a, b, y); uint w; uint z = usubBorrow(a, b, w); Color = vec4(float(x), float(y), float(z), float(w)); break; } case 98: { uint a = zerou + 0xb0b0b0b0; uint b = zerou + 0xdeadbeef; // add and sub with carry/borrow uint y; uint x = uaddCarry(a, b, y); uint w; uint z = usubBorrow(a, b, w); Color = vec4(float(x), float(y), float(z), float(w)); break; } case 99: { uint a = zerou + 0x1234; uint b = zerou + 0x5678; int c = zeroi + 0x1234; int d = zeroi + 0x5678; // positive mul with no overflow uint x, y; umulExtended(a, b, y, x); int z, w; imulExtended(c, d, w, z); Color = vec4(float(x), float(y), float(z), float(w)); break; } case 100: { uint a = zerou + 0x123456; uint b = zerou + 0x78abcd; int c = zeroi + 0x123456; int d = zeroi + 0x78abcd; // positive mul with overflow uint x, y; umulExtended(a, b, y, x); int z, w; imulExtended(c, d, w, z); Color = vec4(float(x), float(y), float(z), float(w)); break; } case 101: { int a = zeroi - 0x1234; int b = zeroi - 0x5678; int c = zeroi - 0x123456; int d = zeroi - 0x78abcd; // negative mul with and without overflow int x, y; imulExtended(a, b, y, x); int z, w; imulExtended(c, d, w, z); Color = vec4(float(x), float(y), float(z), float(w)); break; } )EOSHADER" R"EOSHADER( case 102: { uint a = zerou + 0x0dadbeef; int b = zeroi + 0x0dadbeef; Color = vec4(float(findLSB(a)), float(findLSB(b)), float(findMSB(a)), float(findMSB(b))); break; } case 103: { int a = zeroi - 0x0dadbeef; Color = vec4(float(findLSB(a)), float(findLSB(zeroi)), float(findMSB(a)), float(findMSB(zeroi))); break; } case 104: { uint a = zerou + 0x44b82a24; int b = zeroi + 0x44b82a24; Color = vec4(float(bitCount(a)), float(bitCount(b)), uintBitsToFloat(bitfieldReverse(a)), intBitsToFloat(bitfieldReverse(b))); break; } case 105: { uint a = zerou + 0x44b82a24; int b = zeroi + 0x44b82a24; uint af = zerou+0xffffffff; int bf = zeroi-1; Color = vec4(float(bitfieldExtract(a, 4, 5)), float(bitfieldExtract(b, 4, 5)), uintBitsToFloat(bitfieldInsert(a, af, 4, 5)), intBitsToFloat(bitfieldInsert(b, bf, 4, 5))); break; } case 106: { Color = vec4(float(textureQueryLevels(queryTest)), float(textureSamples(queryTestMS)), 0.0f, 1.0f); break; } case 107: { Color = vec4(vec3(textureSize(queryTest, 0)), 1.0f); break; } case 108: { Color = vec4(vec3(textureSize(queryTest, 1)), 1.0f); break; } case 109: { Color = vec4(vec3(textureSize(queryTestMS)), 1.0f); break; } case 110: { Color = vec4(vec3(textureSize(queryTestMS)), 1.0f); break; } case 111: { Color = texelFetch(texBuffer, int(zeroi+2)); break; } case 112: { float x = texture(sampler2DShadow(depthImage, shadowSampler), vec3(inpos, 0.1f)); float y = texture(sampler2DShadow(depthImage, shadowSampler), vec3(inpos, 0.3f)); float z = texture(sampler2DShadow(depthImage, shadowSampler), vec3(inpos, 0.7f)); float w = texture(sampler2DShadow(depthImage, shadowSampler), vec3(inpos, 0.9f)); Color = vec4(x, y, z, w); break; } case 113: { vec2 coord = vec2(zerof + 0.6, zerof + 0.43); Color = textureGather(linearSampledImage, coord, 0); break; } case 114: { vec2 coord = vec2(zerof + 0.6, zerof + 0.43); Color = textureGather(linearSampledImage, coord, 1); break; } case 115: { vec2 coord = vec2(zerof + 0.6, zerof + 0.43); Color = textureGather(linearSampledImage, coord, 2); break; } case 116: { vec2 coord = vec2(zerof + 0.6, zerof + 0.43); Color = textureGather(sampler2DShadow(depthImage, shadowSampler), coord, 0.8f); break; } case 117: { uint packed = packHalf2x16(cbuf.halfPackSource.xy); Color = vec4(float((packed & 0xff000000) >> 24), float((packed & 0x00ff0000) >> 16), float((packed & 0x0000ff00) >> 8), float((packed & 0x000000ff) >> 0)); break; } case 118: { vec2 unpacked = unpackHalf2x16(cbuf.halfUnpackSource); Color = unpacked.xyxy; break; } case 119: { uint packed = packUnorm2x16(cbuf.unorm2PackSource.xy); Color = vec4(float((packed & 0xff000000) >> 24), float((packed & 0x00ff0000) >> 16), float((packed & 0x0000ff00) >> 8), float((packed & 0x000000ff) >> 0)); break; } case 120: { uint packed = packUnorm4x8(cbuf.unorm4PackSource); Color = vec4(float((packed & 0xff000000) >> 24), float((packed & 0x00ff0000) >> 16), float((packed & 0x0000ff00) >> 8), float((packed & 0x000000ff) >> 0)); break; } case 121: { uint packed = packSnorm2x16(cbuf.snorm2PackSource.xy); Color = vec4(float((packed & 0xff000000) >> 24), float((packed & 0x00ff0000) >> 16), float((packed & 0x0000ff00) >> 8), float((packed & 0x000000ff) >> 0)); break; } case 122: { uint packed = packSnorm4x8(cbuf.snorm4PackSource); Color = vec4(float((packed & 0xff000000) >> 24), float((packed & 0x00ff0000) >> 16), float((packed & 0x0000ff00) >> 8), float((packed & 0x000000ff) >> 0)); break; } case 123: { vec2 unpacked = unpackUnorm2x16(cbuf.unormUnpackSource); Color = unpacked.xyxy; break; } case 124: { vec4 unpacked = unpackUnorm4x8(cbuf.unormUnpackSource); Color = unpacked; break; } case 125: { vec2 unpacked = unpackSnorm2x16(cbuf.snormUnpackSource); Color = unpacked.xyxy; break; } case 126: { vec4 unpacked = unpackSnorm4x8(cbuf.snormUnpackSource); Color = unpacked; break; } case 127: { uint len = storebuf.arr.length(); Color = vec4(float(len), float(len), float(len), float(len)); break; } case 128: { // test storage buffer write here, we'll read from it in GLSL test 2 storebuf.x = vec4(3.1f, 4.1f, 5.9f, 2.6f); storebuf.y.val = uvec4(31, 41, 59, 26); storebuf.arr[flatData.intval - flatData.test] = vec4(inpos, inposIncreased); Color = storebuf.x; break; } case 129: { Color = textureProj(linearSampledImage, vec3(inpos, 0.5f)); break; } case 130: { Color.xy = textureQueryLod(linearSampledImage, inpos); Color.zw = textureQueryLod(linearSampledImage, vec2(1.0f, 1.0f)/inpos); break; } case 131: { Color = vec4(vec2(imageSize(storeImage)), 0.0f, 1.0f); break; } case 132: { Color = vec4(float(imageSize(storeTexBuffer)), 0.0f, 0.0f, 1.0f); break; } case 133: { imageStore(storeImage, ivec2(zeroi+1,zeroi+3), vec4(3.1f, 4.1f, 5.9f, 2.6f)); Color = imageLoad(storeImage, ivec2(zeroi+1,zeroi+3)); break; } #if TEST_DESC_INDEXING case 134: { ivec2 coord = ivec2(zeroi + 20, zeroi + 20); Color = texelFetch(sampledImages[1], coord, 0); break; } case 135: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImages[2], pointSamplers[3]), coord, 0.0); break; } case 136: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImages[2], linearSamplers[3]), coord, 0.0); break; } case 137: { Color = texture(linearSampledImages[4], inpos.xy); break; } case 138: { ivec2 coord = ivec2(zeroi + 20, zeroi + 20); Color = texelFetch(sampledImages[cbuf.uniformIndex+1], coord, 0); break; } case 139: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImages[cbuf.uniformIndex+2], pointSamplers[cbuf.uniformIndex+3]), coord, 0.0); break; } case 140: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImages[cbuf.uniformIndex+2], linearSamplers[cbuf.uniformIndex+3]), coord, 0.0); break; } case 141: { Color = texture(linearSampledImages[cbuf.uniformIndex+4], inpos.xy); break; } case 142: { ivec2 coord = ivec2(zeroi + 20, zeroi + 20); Color = texelFetch(sampledImages[nonuniformEXT(zeroi)+9], coord, 0); break; } case 143: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImages[nonuniformEXT(zeroi)+10], pointSamplers[nonuniformEXT(zeroi)+11]), coord, 0.0); break; } case 144: { vec2 coord = vec2(zerof + 0.5, zerof + 0.145); Color = textureLod(sampler2D(sampledImages[nonuniformEXT(zeroi)+10], linearSamplers[nonuniformEXT(zeroi)+11]), coord, 0.0); break; } case 145: { Color = texture(linearSampledImages[nonuniformEXT(zeroi)+12], inpos.xy); break; } case 146: { Color = vec4(float(textureQueryLevels(queryTests[0])), float(textureSamples(queryTestsMS[0])), 0.0f, 1.0f); break; } case 147: { Color = vec4(float(textureQueryLevels(queryTests[zeroi+3])), float(textureSamples(queryTestsMS[zeroi+3])), 0.0f, 1.0f); break; } case 148: { Color = vec4(float(textureQueryLevels(queryTests[nonuniformEXT(zeroi)+5])), float(textureSamples(queryTestsMS[nonuniformEXT(zeroi)+5])), 0.0f, 1.0f); break; } case 149: { uint len = storebufs[zeroi+7].arr.length(); Color = vec4(float(len), float(len), float(len), float(len)); break; } case 150: { // test storage buffer write here, we'll read from it in GLSL test 2 storebufs[zeroi+7].x = vec4(3.1f, 4.1f, 5.9f, 2.6f); storebufs[zeroi+7].y.val = uvec4(31, 41, 59, 26); storebufs[zeroi+7].arr[flatData.intval - flatData.test] = vec4(inpos, inposIncreased); Color = storebufs[zeroi+7].x; break; } case 151: { imageStore(storeImages[zeroi+7], ivec2(zeroi+1,zeroi+3), vec4(3.1f, 4.1f, 5.9f, 2.6f)); Color = imageLoad(storeImages[zeroi+7], ivec2(zeroi+1,zeroi+3)); break; } case 152: { float x = texture(sampler2DShadow(sampledImages[zeroi+5], shadowSamplers[zeroi+8]), vec3(inpos, 0.1f)); float y = texture(sampler2DShadow(sampledImages[zeroi+5], shadowSamplers[zeroi+8]), vec3(inpos, 0.3f)); float z = texture(sampler2DShadow(sampledImages[zeroi+5], shadowSamplers[zeroi+8]), vec3(inpos, 0.7f)); float w = texture(sampler2DShadow(sampledImages[zeroi+5], shadowSamplers[zeroi+8]), vec3(inpos, 0.9f)); Color = vec4(x, y, z, w); break; } #endif )EOSHADER" R"EOSHADER( case 153: { vec3 cubeCoord = vec3(1.0f, -0.3f, 0.9f); Color = textureLod(cubeSampler, cubeCoord, 0.0f); break; } case 154: { vec3 cubeCoord = vec3(-1.0f, -0.3f, 0.9f); Color = textureLod(cubeSampler, cubeCoord, 0.0f); break; } case 155: { vec3 cubeCoord = vec3(-1.0f, 0.3f, 0.9f); Color = textureLod(cubeSampler, cubeCoord, 0.0f); break; } case 156: { vec3 cubeCoord = vec3(-1.0f, 0.3f, -0.9f); Color = textureLod(cubeSampler, cubeCoord, 0.0f); break; } case 157: { uint old = atomicAdd(atomicbuf.data[flatGlobalCoord].x, flatGlobalCoord); Color = vec4(float(old & 0xfffff), float(atomicbuf.data[flatGlobalCoord].x & 0xfffff), 0.0f, 0.0f); break; } case 158: { uint old = atomicOr(atomicbuf.data[flatGlobalCoord].x, 0x55555555U); Color = vec4(float(old & 0xfffff), float(atomicbuf.data[flatGlobalCoord].x & 0xfffff), 0.0f, 0.0f); break; } case 159: { uint old = atomicXor(atomicbuf.data[flatGlobalCoord].x, 0x55555555U); Color = vec4(float(old & 0xfffff), float(atomicbuf.data[flatGlobalCoord].x & 0xfffff), 0.0f, 0.0f); break; } case 160: { uint old = atomicMax(atomicbuf.data[flatGlobalCoord].x, 0x55555555U); uint old2 = atomicMax(atomicbuf.data[flatGlobalCoord].y, 0x38383838U); Color = vec4(float(old & 0xfffff), float(atomicbuf.data[flatGlobalCoord].x & 0xfffff), float(old2 & 0xfffff), float(atomicbuf.data[flatGlobalCoord].y & 0xfffff)); break; } case 161: { uint old = atomicMin(atomicbuf.data[flatGlobalCoord].x, 0x55555555U); uint old2 = atomicMin(atomicbuf.data[flatGlobalCoord].y, 0x38383838U); Color = vec4(float(old & 0xfffff), float(atomicbuf.data[flatGlobalCoord].x & 0xfffff), float(old2 & 0xfffff), float(atomicbuf.data[flatGlobalCoord].y & 0xfffff)); break; } case 162: { uint old = atomicExchange(atomicbuf.data[flatGlobalCoord].x, 0x12345678U); Color = vec4(float(old & 0xfffff), float(atomicbuf.data[flatGlobalCoord].x & 0xfffff), 0.0f, 0.0f); break; } case 163: { uint old = atomicCompSwap(atomicbuf.data[flatGlobalCoord].x, 0x55555555U, 0x12345678U); uint old2 = atomicCompSwap(atomicbuf.data[flatGlobalCoord].y, 0x42424242U, 0x12345678U); Color = vec4(float(old & 0xfffff), float(atomicbuf.data[flatGlobalCoord].x & 0xfffff), float(old2 & 0xfffff), float(atomicbuf.data[flatGlobalCoord].y & 0xfffff)); break; } case 164: { uint old = imageAtomicAdd(atomicimg, ivec2(gl_FragCoord), flatGlobalCoord); Color = vec4(float(old & 0xfffff), float(imageLoad(atomicimg, ivec2(gl_FragCoord)).x & 0xfffff), 0.0f, 0.0f); break; } case 165: { uint old = imageAtomicOr(atomicimg, ivec2(gl_FragCoord), 0x55555555U); Color = vec4(float(old & 0xfffff), float(imageLoad(atomicimg, ivec2(gl_FragCoord)).x & 0xfffff), 0.0f, 0.0f); break; } case 166: { uint old = imageAtomicXor(atomicimg, ivec2(gl_FragCoord), 0x55555555U); Color = vec4(float(old & 0xfffff), float(imageLoad(atomicimg, ivec2(gl_FragCoord)).x & 0xfffff), 0.0f, 0.0f); break; } case 167: { uint old = imageAtomicMax(atomicimg, ivec2(gl_FragCoord), 0x55555555U); Color = vec4(float(old & 0xfffff), float(imageLoad(atomicimg, ivec2(gl_FragCoord)).x & 0xfffff), 0.0f, 0.0f); break; } case 168: { uint old = imageAtomicMin(atomicimg, ivec2(gl_FragCoord), 0x55555555U); Color = vec4(float(old & 0xfffff), float(imageLoad(atomicimg, ivec2(gl_FragCoord)).x & 0xfffff), 0.0f, 0.0f); break; } case 169: { uint old = imageAtomicExchange(atomicimg, ivec2(gl_FragCoord), 0x12345678U); Color = vec4(float(old & 0xfffff), float(imageLoad(atomicimg, ivec2(gl_FragCoord)).x & 0xfffff), 0.0f, 0.0f); break; } case 170: { uint old = imageAtomicCompSwap(atomicimg, ivec2(gl_FragCoord), 0x55555555U, 0x12345678U); Color = vec4(float(old & 0xfffff), float(imageLoad(atomicimg, ivec2(gl_FragCoord)).x & 0xfffff), 0.0f, 0.0f); break; } case 171: { vec4 ret = vec4(0,0,0,0); // test loop continues for(int i=0; i < flatLocalCoord + 5; i++) { ret.x += 0.1f; if(i == 2) { ret.y += 0.2f; continue; } ret.z += 0.1f; if(i == 4) { continue; } ret.w += 0.1f; } Color = ret; break; } case 172: { vec4 ret = vec4(0,0,0,0); // test loop breaks for(int i=0; i < flatLocalCoord + 5; i++) { ret.x += 0.1f; if(i == 2) { break; } ret.y += 0.2f; } Color = ret; break; } // test fall through case 173: Color += vec4(0.5, 0.5, 0.5, 0.5); case 174: { Color += vec4(1.0, 1.0, 1.0, 1.0); break; } case 175: { // this isn't really intended as a true test but more a convenience for manual testing. Color = varscope_test(flatLocalCoord, inpos, inposIncreased); break; } case 176: { ivec2 coord = ivec2(zeroi + 20, zeroi + 20); Color = texelFetch(sampledImages[cbuf.uniformIndex+1], coord, 0); mat4 mat; // force out of bounds matrix lookup to make sure it doesn't crash float temp = mat[int(Color.r)+70][int(Color.g)+80]; if (int(temp/(temp+10000.0)) == 1) { Color.r = Color.r; } Color += vec4(1.0, 1.0, 1.0, 1.0); break; } case 177: { Color = imageLoad(storeTexBuffer, 1) + imageLoad(storeTexBuffer, 4); break; } case 178: { imageStore(storeTexBuffer, 5, vec4(3.1f, 4.1f, 5.9f, 2.6f)); Color = imageLoad(storeTexBuffer, 5); break; } case 179: { Color = texelFetch(texBuffer1010102unorm, int(1)); break; } case 180: { Color = vec4(texelFetch(texBuffer1010102uint, int(1))); break; } case 181: { Color = imageLoad(storeTexBuffer1010102unorm, int(1)) + imageLoad(storeTexBuffer1010102unorm, int(4)); break; } case 182: { Color = vec4(imageLoad(storeTexBuffer1010102uint, int(1))) + vec4(imageLoad(storeTexBuffer1010102uint, int(4))); break; } case 183: { imageStore(storeTexBuffer1010102unorm, 5, vec4(200.1f/1023.0f, 400.1f/1023.0f, 800.1f/1023.0f, 1.0f)); Color = imageLoad(storeTexBuffer1010102unorm, int(1)) + imageLoad(storeTexBuffer1010102unorm, int(5)); break; } case 184: { imageStore(storeTexBuffer1010102uint, 5, uvec4(20, 40, 80, 1)); Color = vec4(imageLoad(storeTexBuffer1010102uint, int(1))) + vec4(imageLoad(storeTexBuffer1010102uint, int(5))); break; } case 185: { // this is intended to test triggering a mixture of GPU math and GPU sample ops vec2 coord = vec2(zerof + 0.5, zerof + 0.15); if (localCoord.x % 2 == 0) { Color = textureLod(sampler2D(sampledImage, pointSampler), coord, 0.0); for (int i = 0; i < 100; i++) { Color += textureLod(sampler2D(sampledImage, pointSampler), coord, float(i)); } } else { Color = vec4(pow(posone*2.5f, posone*1.3f), pow(posone*2.5f, posone*0.45f), pow(vec2(posone*2.5f, posone*1.3f), vec2(posone*0.9f, posone*8.5f))); for (int i = 0; i < 100; i++) { vec4 value = vec4(pow(posone*2.5f+float(i), posone*1.3f), pow(posone*2.5f, posone*0.45f), pow(vec2(posone*2.5f, posone*1.3f), vec2(posone*0.9f, posone*8.5f))); Color += value / 100.0; } } break; } default: break; } } )EOSHADER"; std::string vertex2 = R"EOSHADER( #version 460 core layout(location = 0) in vec4 pos; layout(location = 1) in float zero; layout(location = 2) in float one; layout(location = 3) in float negone; layout(location = 4) in vec2 texcoord; layout(location = 0, component = 0) flat out uint test; layout(location = 0, component = 1) flat out int zeroi; layout(location = 0, component = 2) flat out uint intval; layout(location = 1, component = 1) out vec3 uv; struct nested { float c; // location 4 vec2 d; // location 5 }; struct iostruct { float a; // location 2 float b; // location 3 nested n; }; layout(location = 2) out iostruct str; layout(location = 6) out mat3 matrix; layout(location = 9) out vec3 arr[3]; void main() { test = gl_InstanceIndex; gl_Position = vec4(pos.x + pos.z * float(test % 256), pos.y + pos.w * float(test / 256), 0.0, 1.0); zeroi = 0; intval = test + 7u; uv = vec3(texcoord.xy, pos.x); vec4 test = vec4(uv.x + 1.0f, uv.y + 2.0f, uv.x + 3.0f, uv.y + 4.0f); str.a = test.x; str.b = test.y; str.n.c = test.z; str.n.d = vec2(test.w, 3.141592f); test *= 1.5f; matrix = mat3((test * 2.0f).xyz, (test * 3.0f).xyz, (test * 4.0f).xyz); arr[0] = (test * 5.0f).yzw; arr[1] = (test * 6.0f).yzw; arr[2] = (test * 7.0f).yzw; } )EOSHADER"; std::string pixel_glsl2 = pixel_glsl_header + R"EOSHADER( layout(location = 0, component = 0) flat in uint test; layout(location = 0, component = 1) flat in int zeroi; layout(location = 0, component = 2) flat in uint intval; layout(location = 1, component = 1) in vec3 uv; struct nested { float c; // location 4 vec2 d; // location 5 }; struct iostruct { float a; // location 2 float b; // location 3 nested n; }; layout(location = 2) in iostruct str; layout(location = 6) in mat3 matrix; layout(location = 9) in vec3 arr[3]; layout(location = 0) out vec4 Color; void main() { float zerof = float(zeroi); Color = vec4(0,0,0,0); switch(test) { case 0: { // test loading from the storage buffer (after a nice big barrier) Color = storebuf.x; break; } case 1: { // test loading from the storage buffer (after a nice big barrier) Color = vec4(storebuf.y.val); break; } case 2: { // test loading from the storage buffer (after a nice big barrier) Color = storebuf.arr[intval - test]; break; } case 3: { Color = imageLoad(storeImage, ivec2(zeroi+1,zeroi+3)); break; } case 4: { Color = vec4(test, zeroi, intval, 1.0f); break; } case 5: { Color = vec4(uv.xyz, 1.0f); break; } case 6: { Color = vec4(str.a, str.b, str.n.c, length(str.n.d)); break; } case 7: { Color = matrix[0].xyzx; break; } case 8: { Color = matrix[1].xyzx; break; } case 9: { Color = matrix[2].xyzx; break; } case 10: { Color = arr[0].xyzx; break; } case 11: { Color = arr[1].xyzx; break; } case 12: { Color = arr[2].xyzx; break; } case 13: { Color = vec4(0,0,0,0); uint loopCount = uint(intval - test); loopCount -= (uint(gl_FragCoord.x) % 2u); loopCount -= (uint(gl_FragCoord.y) % 2u) * 2u; vec2 val = uv.xy; for(uint i=0; i < loopCount; i++) { val += vec2(0.01f, 0.01f); } Color = dFdxFine(val).xyxy; break; } case 14: { Color = vec4(0,0,0,0); uint loopCount = uint(intval - test); loopCount += (uint(gl_FragCoord.x) % 2u); loopCount += (uint(gl_FragCoord.y) % 2u) * 2u; vec2 val = uv.xy; for(uint i=0; i < loopCount; i++) { val += vec2(0.01f, 0.01f); } Color = dFdxFine(val).xyxy; break; } #if TEST_DESC_INDEXING case 15: { // test loading from the storage buffer (after a nice big barrier) Color = storebufs[zeroi+7].x; break; } case 16: { // test loading from the storage buffer (after a nice big barrier) Color = vec4(storebufs[zeroi+7].y.val); break; } case 17: { // test loading from the storage buffer (after a nice big barrier) Color = storebufs[zeroi+7].arr[intval - test]; break; } case 18: { Color = imageLoad(storeImages[zeroi+7], ivec2(zeroi+1,zeroi+3)); break; } #endif case 19: { Color = gl_FrontFacing ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); break; } case 20: { Color = imageLoad(storeTexBuffer, 1)+imageLoad(storeTexBuffer, 5); break; } case 21: { Color = imageLoad(storeTexBuffer1010102unorm, int(1)) + imageLoad(storeTexBuffer1010102unorm, int(5)); } case 22: { Color = vec4(imageLoad(storeTexBuffer1010102uint, int(1))) + vec4(imageLoad(storeTexBuffer1010102uint, int(5))); } default: break; } } )EOSHADER"; std::string capabilities = "OpCapability Shader\n"; std::string spv_extensions; std::string extinstimport = R"EOSHADER( %glsl450 = OpExtInstImport "GLSL.std.450" )EOSHADER"; std::string executionmodes = R"EOSHADER( OpExecutionMode %main OriginUpperLeft )EOSHADER"; std::string spv_debug = R"EOSHADER( %filename = OpString "file.foo" )EOSHADER"; std::string decorations = R"EOSHADER( OpDecorate %flatData Flat OpDecorate %flatData Location 1 OpDecorate %linearData Location 3 OpDecorate %Color Index 0 OpDecorate %Color Location 0 OpDecorate %gl_FragCoord BuiltIn FragCoord OpDecorate %rtarray_float4 ArrayStride 16 OpMemberDecorate %dummy 0 Offset 0 OpMemberDecorate %dummy 1 Offset 16 OpMemberDecorate %buftype 0 Offset 0 OpMemberDecorate %buftype 1 Offset 64 OpMemberDecorate %buftype 2 Offset 128 OpMemberDecorate %buftype 3 Offset 144 OpMemberDecorate %buftype 4 Offset 176 OpMemberDecorate %buftype 0 MatrixStride 16 OpMemberDecorate %buftype 0 RowMajor OpMemberDecorate %buftype 1 MatrixStride 16 OpMemberDecorate %buftype 1 ColMajor OpDecorate %buftype BufferBlock OpDecorate %buffer DescriptorSet 0 OpDecorate %buffer Binding 15 )EOSHADER"; std::string typesConstants = R"EOSHADER( %void = OpTypeVoid %bool = OpTypeBool %float = OpTypeFloat 32 %uint = OpTypeInt 32 0 %int = OpTypeInt 32 1 %float2 = OpTypeVector %float 2 %float3 = OpTypeVector %float 3 %float4 = OpTypeVector %float 4 %int2 = OpTypeVector %int 2 %int3 = OpTypeVector %int 3 %int4 = OpTypeVector %int 4 %uint2 = OpTypeVector %uint 2 %uint3 = OpTypeVector %uint 3 %uint4 = OpTypeVector %uint 4 %float2x2 = OpTypeMatrix %float2 2 %float3x3 = OpTypeMatrix %float3 3 %float2x4 = OpTypeMatrix %float2 4 %float4x2 = OpTypeMatrix %float4 2 %float4x4 = OpTypeMatrix %float4 4 %mainfunc = OpTypeFunction %void %doublerfunc = OpTypeFunction %float %float %rtarray_float4 = OpTypeRuntimeArray %float4 %v2f = OpTypeStruct %float2 %float2 %float2 %float %float %float %flatv2f = OpTypeStruct %uint %uint %child = OpTypeStruct %float4 %float3 %float %parent = OpTypeStruct %float4 %child %float4x4 %f32f32 = OpTypeStruct %float %float %f32i32 = OpTypeStruct %float %int %dummy = OpTypeStruct %uint4 %uint4 %buftype = OpTypeStruct %float4x4 %float4x4 %float4 %dummy %rtarray_float4 %ptr_Input_v2f = OpTypePointer Input %v2f %ptr_Input_flatv2f = OpTypePointer Input %flatv2f %ptr_Input_uint = OpTypePointer Input %uint %ptr_Input_int = OpTypePointer Input %int %ptr_Input_float = OpTypePointer Input %float %ptr_Input_float2 = OpTypePointer Input %float2 %ptr_Input_float4 = OpTypePointer Input %float4 %ptr_Output_float4 = OpTypePointer Output %float4 %ptr_Private_int = OpTypePointer Private %int %ptr_Private_float = OpTypePointer Private %float %ptr_Private_float4 = OpTypePointer Private %float4 %ptr_Private_float4x4 = OpTypePointer Private %float4x4 %ptr_Function_float = OpTypePointer Function %float %ptr_Uniform_float = OpTypePointer Uniform %float %ptr_Uniform_float2 = OpTypePointer Uniform %float2 %ptr_Uniform_float3 = OpTypePointer Uniform %float3 %ptr_Uniform_float4 = OpTypePointer Uniform %float4 %ptr_Uniform_uint = OpTypePointer Uniform %uint %ptr_Uniform_uint2 = OpTypePointer Uniform %uint2 %ptr_Uniform_uint3 = OpTypePointer Uniform %uint3 %ptr_Uniform_uint4 = OpTypePointer Uniform %uint4 %ptr_Uniform_int = OpTypePointer Uniform %int %ptr_Uniform_int2 = OpTypePointer Uniform %int2 %ptr_Uniform_int3 = OpTypePointer Uniform %int3 %ptr_Uniform_int4 = OpTypePointer Uniform %int4 %ptr_Uniform_float4x4 = OpTypePointer Uniform %float4x4 %ptr_Uniform_dummy = OpTypePointer Uniform %dummy %ptr_Uniform_buftype = OpTypePointer Uniform %buftype %linearData = OpVariable %ptr_Input_v2f Input %flatData = OpVariable %ptr_Input_flatv2f Input %gl_FragCoord = OpVariable %ptr_Input_float4 Input %Color = OpVariable %ptr_Output_float4 Output %priv_int = OpVariable %ptr_Private_int Private %priv_float = OpVariable %ptr_Private_float Private %priv_float4 = OpVariable %ptr_Private_float4 Private %priv_float4x4 = OpVariable %ptr_Private_float4x4 Private %buffer = OpVariable %ptr_Uniform_buftype Uniform %flatv2f_test_idx = OpConstant %int 0 %flatv2f_intval_idx = OpConstant %int 1 %v2f_zeroVal_idx = OpConstant %int 0 %v2f_inpos_idx = OpConstant %int 1 %v2f_inposIncreased_idx = OpConstant %int 2 %v2f_tinyVal_idx = OpConstant %int 3 %v2f_oneVal_idx = OpConstant %int 4 %v2f_negoneVal_idx = OpConstant %int 5 )EOSHADER"; std::string functions = R"EOSHADER( %doubler = OpFunction %float None %doublerfunc OpLine %filename 123 456 OpNoLine OpLine %filename 111 222 %doubler_in = OpFunctionParameter %float OpNoLine OpLine %filename 99 55 OpLine %filename 199 155 %doubler_begin = OpLabel OpLine %filename 299 255 %doubler_tmp = OpVariable %ptr_Function_float Function OpLine %filename 399 355 %doubler_ret = OpFMul %float %float_2_0 %doubler_in OpLine %filename 499 455 OpStore %doubler_tmp %doubler_ret OpLine %filename 599 555 %doubler_ret2 = OpLoad %float %doubler_tmp OpLine %filename 699 655 OpReturnValue %doubler_ret2 OpLine %filename 799 755 OpFunctionEnd )EOSHADER"; std::vector asm_tests; void append_tests(const std::initializer_list &tests) { asm_tests.insert(asm_tests.end(), tests.begin(), tests.end()); } void make_asm_tests() { std::vector ret; // test binary float maths operations for(const std::string &op : {"OpFAdd", "OpFSub", "OpFMul", "OpFDiv", "OpFMod", "OpFRem"}) { bool div = (op == "OpFDiv" || op == "OpFMod" || op == "OpFRem"); bool mod = (op == "OpFMod" || op == "OpFRem"); for(const std::string &a : {"15_75", "4_5"}) { for(const std::string &b : {"15_75", "4_5"}) { // don't test A mod A if(mod && a == b) continue; // test A op B and B op A, with neg/pos and dyn/const append_tests({ fmt::format("%_x = {0} %float %float_{1} %float_{2}\n" "%_y = {0} %float %float_neg{1} %float_{2}\n" "%_z = {0} %float %float_{2} %float_{1}\n" "%_w = {0} %float %float_neg{2} %float_{1}\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", op, a, b), fmt::format("%_x = {0} %float %float_dyn_{1} %float_dyn_{2}\n" "%_y = {0} %float %float_dyn_neg{1} %float_dyn_{2}\n" "%_z = {0} %float %float_dyn_{2} %float_dyn_{1}\n" "%_w = {0} %float %float_dyn_neg{2} %float_dyn_{1}\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", op, a, b), }); if(features.shaderFloat64) { append_tests({ fmt::format("%_x = {0} %double %double_{1} %double_{2}\n" "%_y = {0} %double %double_neg{1} %double_{2}\n" "%_z = {0} %double %double_{2} %double_{1}\n" "%_w = {0} %double %double_neg{2} %double_{1}\n" "%_out_double4 = OpCompositeConstruct %double4 %_x %_y %_z %_w\n", op, a, b), fmt::format("%_x = {0} %double %double_dyn_{1} %double_dyn_{2}\n" "%_y = {0} %double %double_dyn_neg{1} %double_dyn_{2}\n" "%_z = {0} %double %double_dyn_{2} %double_dyn_{1}\n" "%_w = {0} %double %double_dyn_neg{2} %double_dyn_{1}\n" "%_out_double4 = OpCompositeConstruct %double4 %_x %_y %_z %_w\n", op, a, b), }); } // also test 0 op A/B append_tests({ fmt::format("%_x = {0} %float %float_0_0 %float_{1}\n" "%_y = {0} %float %float_0_0 %float_{2}\n" "%_z = {0} %float %float_0_0 %float_{3}{1}\n" "%_w = {0} %float %float_0_0 %float_{3}{2}\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", op, a, b, mod ? "" : "neg"), fmt::format("%_x = {0} %float %float_dyn_0_0 %float_dyn_{1}\n" "%_y = {0} %float %float_dyn_0_0 %float_dyn_{2}\n" "%_z = {0} %float %float_dyn_0_0 %float_dyn_{3}{1}\n" "%_w = {0} %float %float_dyn_0_0 %float_dyn_{3}{2}\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", op, a, b, mod ? "" : "neg"), }); // if this isn't a divide, test A/B op 0 if(!div) { append_tests({ fmt::format("%_x = {0} %float %float_{1} %float_0_0\n" "%_y = {0} %float %float_neg{1} %float_0_0\n" "%_z = {0} %float %float_{2} %float_0_0\n" "%_w = {0} %float %float_neg{2} %float_0_0\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", op, a, b), fmt::format("%_x = {0} %float %float_dyn_{1} %float_dyn_0_0\n" "%_y = {0} %float %float_dyn_neg{1} %float_dyn_0_0\n" "%_z = {0} %float %float_dyn_{2} %float_dyn_0_0\n" "%_w = {0} %float %float_dyn_neg{2} %float_dyn_0_0\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", op, a, b), }); } } } } // test binary int maths operations for(const std::string &op : {"OpIAdd", "OpISub", "OpIMul", "OpSDiv", "OpSMod", "OpSRem", "OpUDiv", "OpUMod"}) { bool div = (op == "OpSDiv" || op == "OpSMod" || op == "OpSRem" || op == "OpUDiv" || op == "OpUMod"); bool mod = (op == "OpSMod" || op == "OpSRem" || op == "OpUMod"); bool sign = op.find('U') == std::string::npos; for(uint32_t a : {15, 4}) { for(uint32_t b : {15, 4}) { // don't test A mod A if(mod && a == b) continue; // test A op B for uint and int (positive) append_tests({ fmt::format("%_x = {0} %uint %uint_{1} %uint_{2}\n" "%_y = {0} %uint %uint_dyn_{1} %uint_{2}\n" "%_z = {0} %uint %uint_{2} %uint_{1}\n" "%_w = {0} %uint %uint_dyn_{2} %uint_{1}\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", op, a, b), fmt::format("%_x = {0} %uint %uint_0 %uint_{1}\n" "%_y = {0} %uint %uint_0 %uint_dyn_{1}\n" "%_z = {0} %uint %uint_0 %uint_{2}\n" "%_w = {0} %uint %uint_0 %uint_dyn_{2}\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", op, a, b), }); // if this is a signed op, test negative values too if(sign && !mod) { append_tests({ fmt::format("%_x = {0} %int %int_{1} %int_{2}\n" "%_y = {0} %int %int_dyn_{1} %int_{2}\n" "%_z = {0} %int %int_{2} %int_{1}\n" "%_w = {0} %int %int_dyn_{2} %int_{1}\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", op, a, b), fmt::format("%_x = {0} %int %int_0 %int_{1}\n" "%_y = {0} %int %int_0 %int_dyn_{1}\n" "%_z = {0} %int %int_0 %int_{2}\n" "%_w = {0} %int %int_0 %int_dyn_{2}\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", op, a, b), fmt::format("%_x = {0} %int %int_neg{1} %int_{2}\n" "%_y = {0} %int %int_dyn_neg{1} %int_{2}\n" "%_z = {0} %int %int_neg{2} %int_{1}\n" "%_w = {0} %int %int_dyn_neg{2} %int_{1}\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", op, a, b), fmt::format("%_x = {0} %int %int_0 %int_neg{1}\n" "%_y = {0} %int %int_0 %int_dyn_neg{1}\n" "%_z = {0} %int %int_0 %int_neg{2}\n" "%_w = {0} %int %int_0 %int_dyn_neg{2}\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", op, a, b), }); } // if it's not a divide op, test A/B op 0 if(!div) { append_tests({ fmt::format("%_x = {0} %uint %uint_{1} %uint_0\n" "%_y = {0} %uint %uint_{2} %uint_0\n" "%_z = {0} %uint %uint_dyn_{1} %uint_dyn_0\n" "%_w = {0} %uint %uint_dyn_{2} %uint_dyn_0\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", op, a, b), }); // and if it's a signed non-divide op, test -A / -B op 0 if(sign) { append_tests({ fmt::format("%_x = {0} %int %int_neg{1} %int_0\n" "%_y = {0} %int %int_neg{2} %int_0\n" "%_z = {0} %int %int_dyn_neg{1} %int_dyn_0\n" "%_w = {0} %int %int_dyn_neg{2} %int_dyn_0\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", op, a, b), }); } } } } } // test unary operations append_tests({ "%_x = OpFNegate %float %float_10_0\n" "%_y = OpFNegate %float %float_neg10_0\n" "%_z = OpFNegate %float %float_dyn_10_0\n" "%_w = OpFNegate %float %float_dyn_neg10_0\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", "%_x = OpFNegate %float %float_0_0\n" "%_y = OpFNegate %float %float_neg0_0\n" "%_z = OpFNegate %float %float_dyn_0_0\n" "%_w = OpFNegate %float %float_dyn_neg0_0\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", "%_x = OpSNegate %int %int_10\n" "%_y = OpSNegate %int %int_neg10\n" "%_z = OpSNegate %int %int_dyn_10\n" "%_w = OpSNegate %int %int_dyn_neg10\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", "%_x = OpSNegate %int %int_0\n" "%_y = OpSNegate %int %int_neg0\n" "%_z = OpSNegate %int %int_dyn_0\n" "%_w = OpSNegate %int %int_dyn_neg0\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", }); // test bitwise operations append_tests({ "%_x = OpBitwiseOr %uint %uint_0x1234 %uint_0xb9c5\n" "%_y = OpBitwiseXor %uint %uint_0x1234 %uint_0xb9c5\n" "%_z = OpBitwiseAnd %uint %uint_0x1234 %uint_0xb9c5\n" "%_w = OpNot %uint %uint_0x1234 \n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", "%_x = OpBitwiseOr %uint %uint_dyn_0x1234 %uint_dyn_0xb9c5\n" "%_y = OpBitwiseXor %uint %uint_dyn_0x1234 %uint_dyn_0xb9c5\n" "%_z = OpBitwiseAnd %uint %uint_dyn_0x1234 %uint_dyn_0xb9c5\n" "%_w = OpNot %uint %uint_dyn_0xb9c5\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", "%_x = OpBitwiseOr %uint %uint_dyn_0x1234 %uint_0\n" "%_y = OpBitwiseXor %uint %uint_dyn_0x1234 %uint_0\n" "%_z = OpBitwiseAnd %uint %uint_dyn_0x1234 %uint_0\n" "%_w = OpNot %uint %uint_0\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", "%_x = OpBitwiseOr %uint %uint_0 %uint_dyn_0xb9c5\n" "%_y = OpBitwiseXor %uint %uint_0 %uint_dyn_0xb9c5\n" "%_z = OpBitwiseAnd %uint %uint_0 %uint_dyn_0xb9c5\n" "%_w = OpNot %uint %uint_dyn_0xb9c5\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", }); // test shifts for(const std::string &op : {"OpShiftLeftLogical", "OpShiftRightLogical", "OpShiftRightArithmetic"}) { for(const std::string &dyn : {"", "_dyn"}) { for(const std::string &intType : {"int", "uint"}) { append_tests({ fmt::format("%_x = {0} %{1} %{1}{2}_0x1234 %uint_0\n" "%_y = {0} %{1} %{1}{2}_0x1234 %uint_1\n" "%_z = {0} %{1} %{1}{2}_0x1234 %uint_2\n" "%_out_{1}3 = OpCompositeConstruct %{1}3 %_x %_y %_z\n", op, intType, dyn), fmt::format("%_x = {0} %{1} %{1}_0x1234 %uint{2}_0\n" "%_y = {0} %{1} %{1}_0x1234 %uint{2}_1\n" "%_z = {0} %{1} %{1}_0x1234 %uint{2}_2\n" "%_out_{1}3 = OpCompositeConstruct %{1}3 %_x %_y %_z\n", op, intType, dyn), fmt::format("%_x = {0} %{1} %{1}{2}_0x1234 %uint{2}_0\n" "%_y = {0} %{1} %{1}{2}_0x1234 %uint{2}_1\n" "%_z = {0} %{1} %{1}{2}_0x1234 %uint{2}_2\n" "%_out_{1}3 = OpCompositeConstruct %{1}3 %_x %_y %_z\n", op, intType, dyn), }); } } } // test square 2x2 matrix multiplies append_tests({ R"EOTEST( %_cola = OpCompositeConstruct %float2 %randf_0 %randf_1 %_colb = OpCompositeConstruct %float2 %randf_2 %randf_3 %_mat = OpCompositeConstruct %float2x2 %_cola %_colb %_vec = OpCompositeConstruct %float2 %randf_4 %randf_5 %_out_float2 = OpMatrixTimesVector %float2 %_mat %_vec )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float2 %randf_0 %randf_1 %_colb = OpCompositeConstruct %float2 %randf_2 %randf_3 %_mat = OpCompositeConstruct %float2x2 %_cola %_colb %_vec = OpCompositeConstruct %float2 %randf_4 %randf_5 %_out_float2 = OpVectorTimesMatrix %float2 %_vec %_mat )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float2 %randf_0 %randf_1 %_colb = OpCompositeConstruct %float2 %randf_2 %randf_3 %_mat1 = OpCompositeConstruct %float2x2 %_cola %_colb %_vec = OpCompositeConstruct %float2 %randf_4 %randf_5 %_mat2 = OpMatrixTimesScalar %float2x2 %_mat1 %randf_6 %_out_float2 = OpVectorTimesMatrix %float2 %_vec %_mat2 )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float2 %randf_0 %randf_1 %_colb = OpCompositeConstruct %float2 %randf_2 %randf_3 %_mat1 = OpCompositeConstruct %float2x2 %_cola %_colb %_vec = OpCompositeConstruct %float2 %randf_4 %randf_5 %_colc = OpCompositeConstruct %float2 %randf_6 %randf_7 %_cold = OpCompositeConstruct %float2 %randf_8 %randf_9 %_mat2 = OpCompositeConstruct %float2x2 %_colc %_cold %_mat3 = OpMatrixTimesMatrix %float2x2 %_mat1 %_mat2 %_out_float2 = OpVectorTimesMatrix %float2 %_vec %_mat3 )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float2 %randf_0 %randf_1 %_colb = OpCompositeConstruct %float2 %randf_2 %randf_3 %_mat1 = OpCompositeConstruct %float2x2 %_cola %_colb %_vec = OpCompositeConstruct %float2 %randf_4 %randf_5 %_colc = OpCompositeConstruct %float2 %randf_6 %randf_7 %_cold = OpCompositeConstruct %float2 %randf_8 %randf_9 %_mat2 = OpCompositeConstruct %float2x2 %_colc %_cold %_mat3 = OpMatrixTimesMatrix %float2x2 %_mat2 %_mat1 %_out_float2 = OpVectorTimesMatrix %float2 %_vec %_mat3 )EOTEST", }); // test rectangular 2x4 / 4x2 matrix multiplies append_tests({ R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_mat = OpCompositeConstruct %float4x2 %_cola %_colb %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_out_float2 = OpVectorTimesMatrix %float2 %_vec %_mat )EOTEST", R"EOTEST( %_colc = OpCompositeConstruct %float2 %randf_8 %randf_9 %_cold = OpCompositeConstruct %float2 %randf_10 %randf_11 %_cole = OpCompositeConstruct %float2 %randf_12 %randf_13 %_colf = OpCompositeConstruct %float2 %randf_14 %randf_15 %_mat = OpCompositeConstruct %float2x4 %_colc %_cold %_cole %_colf %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_out_float2 = OpMatrixTimesVector %float2 %_mat %_vec )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_mat = OpCompositeConstruct %float4x2 %_cola %_colb %_vec = OpCompositeConstruct %float2 %randf_16 %randf_17 %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec )EOTEST", R"EOTEST( %_colc = OpCompositeConstruct %float2 %randf_8 %randf_9 %_cold = OpCompositeConstruct %float2 %randf_10 %randf_11 %_cole = OpCompositeConstruct %float2 %randf_12 %randf_13 %_colf = OpCompositeConstruct %float2 %randf_14 %randf_15 %_mat = OpCompositeConstruct %float2x4 %_colc %_cold %_cole %_colf %_vec = OpCompositeConstruct %float2 %randf_16 %randf_17 %_out_float4 = OpVectorTimesMatrix %float4 %_vec %_mat )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_mat1 = OpCompositeConstruct %float4x2 %_cola %_colb %_colc = OpCompositeConstruct %float2 %randf_8 %randf_9 %_cold = OpCompositeConstruct %float2 %randf_10 %randf_11 %_cole = OpCompositeConstruct %float2 %randf_12 %randf_13 %_colf = OpCompositeConstruct %float2 %randf_14 %randf_15 %_mat2 = OpCompositeConstruct %float2x4 %_colc %_cold %_cole %_colf %_mat = OpMatrixTimesMatrix %float4x4 %_mat1 %_mat2 %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_mat1 = OpCompositeConstruct %float4x2 %_cola %_colb %_colc = OpCompositeConstruct %float4 %randf_8 %randf_9 %randf_10 %randf_11 %_cold = OpCompositeConstruct %float4 %randf_12 %randf_13 %randf_14 %randf_15 %_mat2 = OpCompositeConstruct %float4x2 %_colc %_cold %_mat2t = OpTranspose %float2x4 %_mat2 %_mat = OpMatrixTimesMatrix %float4x4 %_mat1 %_mat2t %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_mat = OpOuterProduct %float4x4 %_cola %_colb %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec )EOTEST", R"EOTEST( %_vec = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_out_float4 = OpVectorTimesScalar %float4 %_vec %randf_4 )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float2 %randf_0 %randf_1 %_colb = OpCompositeConstruct %float2 %randf_4 %randf_5 %_colc = OpCompositeConstruct %float2 %randf_8 %randf_9 %_cold = OpCompositeConstruct %float2 %randf_12 %randf_13 %_mat1 = OpCompositeConstruct %float2x2 %_cola %_colb %_out_float = OpExtInst %float %glsl450 Determinant %_mat1 )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float3 %randf_0 %randf_1 %randf_2 %_colb = OpCompositeConstruct %float3 %randf_4 %randf_5 %randf_6 %_colc = OpCompositeConstruct %float3 %randf_8 %randf_9 %randf_10 %_mat1 = OpCompositeConstruct %float3x3 %_cola %_colb %_colc %_out_float = OpExtInst %float %glsl450 Determinant %_mat1 )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_colc = OpCompositeConstruct %float4 %randf_8 %randf_9 %randf_10 %randf_11 %_cold = OpCompositeConstruct %float4 %randf_12 %randf_13 %randf_14 %randf_15 %_mat1 = OpCompositeConstruct %float4x4 %_cola %_colb %_colc %_cold %_out_float = OpExtInst %float %glsl450 Determinant %_mat1 )EOTEST", }); // test matrix inverse, but round the result to avoid needing to lower our global precision // epsilon for(int dim = 2; dim <= 4; dim++) { std::string test = fmt::format(R"EOTEST( %_cola = OpCompositeConstruct %float{0} %randf_0 %randf_1 {1} %randf_2 {2} %randf_3 %_colb = OpCompositeConstruct %float{0} %randf_4 %randf_5 {1} %randf_6 {2} %randf_7 %_colc = OpCompositeConstruct %float{0} %randf_8 %randf_9 {1} %randf_10 {2} %randf_11 %_cold = OpCompositeConstruct %float{0} %randf_12 %randf_13 {1} %randf_14 {2} %randf_15 %_mat = OpCompositeConstruct %float{0}x{0} %_cola %_colb {1} %_colc {2} %_cold %_vec = OpCompositeConstruct %float{0} %randf_16 %randf_17 {1} %randf_18 {2} %randf_19 %_mat0 = OpExtInst %float{0}x{0} %glsl450 MatrixInverse %_mat )EOTEST", dim, dim < 3 ? ";" : "", dim < 4 ? ";" : ""); int i = 0; for(int col = 0; col < dim; col++) { for(int row = 0; row < dim; row++) { test += fmt::format(R"EOTEST( %_mat{0}{1}a = OpCompositeExtract %float %_mat{2} {0} {1} %_mat{0}{1}b = OpFMul %float %_mat{0}{1}a %float_500_0 %_mat{0}{1}c = OpExtInst %float %glsl450 RoundEven %_mat{0}{1}b %_mat{0}{1}d = OpFDiv %float %_mat{0}{1}c %float_500_0 %_mat{3} = OpCompositeInsert %float{4}x{4} %_mat{0}{1}d %_mat{2} {0} {1} )EOTEST", col, row, i, i + 1, dim); i++; } } test += fmt::format("%_out_float{0} = OpMatrixTimesVector %float{0} %_mat{1} %_vec\n", dim, i); asm_tests.push_back(test); } // test OpVectorShuffle append_tests({ "%_out_float4 = OpVectorShuffle %float4 %float4_0000 %float4_1234 7 6 0 1", "%_out_float4 = OpVectorShuffle %float4 %float4_0000 %float4_dyn_1234 7 6 0 1", "%_out_float4 = OpVectorShuffle %float4 %float4_dyn_0000 %float4_1234 7 6 0 1", "%_out_float4 = OpVectorShuffle %float4 %float4_dyn_0000 %float4_dyn_1234 7 6 0 1", "%_out_float3 = OpVectorShuffle %float3 %float3_000 %float3_123 3 4 5", "%_out_float2 = OpVectorShuffle %float2 %float2_00 %float2_12 2 3", // test 0xffffffff component inputs "%_tmp = OpVectorShuffle %float4 %float4_0000 %float4_1234 5 4 4294967295 4294967295\n" "%_out_float4 = OpVectorShuffle %float4 %_tmp %float4_dyn_1234 0 1 4 5", }); // test OpVectorExtractDynamic append_tests({ "%_x = OpVectorExtractDynamic %float %float4_dyn_1234 %uint_dyn_1\n" "%_y = OpVectorExtractDynamic %float %float4_dyn_1234 %uint_dyn_3\n" "%_z = OpVectorExtractDynamic %float %float4_dyn_1234 %uint_dyn_2\n" "%_w = OpVectorExtractDynamic %float %float4_dyn_0000 %uint_dyn_2\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", }); // test OpVectorInsertDynamic append_tests({ "%_out_float4 = OpVectorInsertDynamic %float4 %float4_dyn_1234 %float_dyn_8_8 %uint_dyn_1", "%_out_float4 = OpVectorInsertDynamic %float4 %float4_dyn_1234 %float_dyn_8_8 %uint_dyn_2", "%_out_float4 = OpVectorInsertDynamic %float4 %float4_dyn_1234 %float_dyn_8_8 %uint_dyn_0", }); // test OpCompositeInsert on vectors append_tests({ " %_b = OpCompositeInsert %float4 %float_15_0 %float4_0000 2\n" " %_c = OpCompositeInsert %float4 %float_8_8 %_b 1\n" " %_d = OpCompositeInsert %float4 %float_6_1 %_c 3\n" "%_out_float4 = OpCompositeInsert %float4 %float_2_222 %_d 0\n", " %_b = OpCompositeInsert %float4 %float_dyn_15_0 %float4_dyn_0000 2\n" " %_c = OpCompositeInsert %float4 %float_dyn_8_8 %_b 1\n" " %_d = OpCompositeInsert %float4 %float_dyn_6_1 %_c 3\n" "%_out_float4 = OpCompositeInsert %float4 %float_dyn_2_222 %_d 0\n", }); // test OpCompositeExtract on vectors append_tests({ "%_out_float = OpCompositeExtract %float %float4_dyn_1234 0", "%_out_float = OpCompositeExtract %float %float4_dyn_1234 1", "%_out_float = OpCompositeExtract %float %float4_dyn_1234 3", }); // test OpCompositeInsert on structs asm_tests.push_back(R"EOTEST( %_a = OpCompositeConstruct %float4 %float_dyn_4_2 %float_dyn_1_0 %float_dyn_9_5 %float_dyn_0_01 %_b = OpCompositeConstruct %float3 %float_dyn_3_5 %float_dyn_5_3 %float_dyn_6_2 %_c = OpVectorShuffle %float4 %_a %_a 3 2 0 1 %_d = OpVectorShuffle %float4 %_a %_a 0 1 3 2 %_e = OpVectorShuffle %float4 %_a %_a 2 0 1 3 %_f = OpVectorShuffle %float4 %_a %_a 3 1 2 0 %_g = OpVectorShuffle %float4 %_a %_a 1 3 0 2 %_parent1 = OpCompositeInsert %parent %_a %null_parent 0 %_parent2 = OpCompositeInsert %parent %_a %_parent1 1 0 %_parent3 = OpCompositeInsert %parent %_b %_parent2 1 1 %_parent4 = OpCompositeInsert %parent %float_dyn_9_9 %_parent3 1 2 %_parent5 = OpCompositeInsert %parent %_c %_parent4 2 0 %_parent6 = OpCompositeInsert %parent %_d %_parent5 2 1 %_parent7 = OpCompositeInsert %parent %_e %_parent6 2 2 %_parent8 = OpCompositeInsert %parent %_g %_parent7 2 3 %_x = OpCompositeExtract %float %_parent8 0 2 %_y = OpCompositeExtract %float %_parent8 2 1 3 %_z = OpCompositeExtract %float %_parent8 1 1 1 %_w = OpCompositeExtract %float %_parent8 1 0 2 %_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w )EOTEST"); // test OpBitCast append_tests({ "%_a = OpBitcast %uint %float_dyn_15_0\n" "%_neg = OpBitwiseOr %uint %_a %uint_dyn_0x80000000\n" "%_out_float = OpBitcast %float %_neg\n", "%_result = OpBitwiseOr %uint %uint_dyn_0x4200004d %uint_dyn_0xa28b00\n" "%_out_float = OpBitcast %float %_result\n", }); // Bitcast vector <-> scalar if(float16Int8Features.shaderInt8 && features.shaderInt16) { append_tests({ // u8[2] -> u16 "%_result = OpCompositeConstruct %u8v2 %u8_8 %u8_9\n" "%_out_u16 = OpBitcast %u16 %_result\n", // u8[4] -> u32 "%_result = OpCompositeConstruct %u8v4 %u8_4 %u8_5 %u8_6 %u8_7\n" "%_out_uint = OpBitcast %uint %_result\n", // u16[2] -> u32 "%_result = OpCompositeConstruct %u16v2 %u16_4 %u16_5\n" "%_out_uint = OpBitcast %uint %_result\n", // u16 -> u8[2] "%_out_u8v2 = OpBitcast %u8v2 %u16_1234\n ", // u32 -> u8[4] "%_out_u8v4 = OpBitcast %u8v4 %uint_1234\n ", // u32 -> u16[2] "%_out_u16v2 = OpBitcast %u16v2 %uint_12345\n", }); } if(features.shaderInt16 && features.shaderInt64) { append_tests({ // u16[4] -> u64 "%_result = OpCompositeConstruct %u16v4 %u16_0 %u16_1 %u16_2 %u16_3\n" "%_out_u64 = OpBitcast %u64 %_result\n", // u64 -> u16[4] "%_out_u16v4 = OpBitcast %u16v4 %u64_1234\n", }); } if(features.shaderInt64) { append_tests({ // u32[2] -> u64 "%_result = OpCompositeConstruct %uint2 %uint_0 %uint_1\n" "%_out_u64 = OpBitcast %u64 %_result\n", // u64 -> u32[2] "%_out_uint2 = OpBitcast %uint2 %u64_1234\n", }); } if(float16Int8Features.shaderFloat16) { append_tests({ // f16[2] -> f32 "%_result = OpCompositeConstruct %half2 %half_0_25 %half_0_5\n" "%_out_float = OpBitcast %float %_result\n", // f32 -> f16[2] "%_out_half2 = OpBitcast %half2 %float_1_1125\n", }); } if(features.shaderFloat64) { append_tests({ // f32[2] -> f64 "%_result = OpCompositeConstruct %float2 %float_0_5 %float_0_25\n" "%_out_double = OpBitcast %double %_result\n", // f64 -> f32[2] "%_out_float2 = OpBitcast %float2 %double_1024_25\n", }); } // test ExtInst NMin/NMax/NClamp append_tests({ "%_x = OpExtInst %float %glsl450 NMin %nan %oneVal\n" "%_y = OpExtInst %float %glsl450 NMin %oneVal %nan\n" "%_z = OpExtInst %float %glsl450 NMin %nan %nan\n" "%_w = OpExtInst %float %glsl450 NMin %nan %neginf\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", "%_x = OpExtInst %float %glsl450 NMax %nan %oneVal\n" "%_y = OpExtInst %float %glsl450 NMax %oneVal %nan\n" "%_z = OpExtInst %float %glsl450 NMax %nan %nan\n" "%_w = OpExtInst %float %glsl450 NMax %nan %neginf\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", "%_out_float = OpExtInst %float %glsl450 NClamp %nan %zerof %oneVal", }); // test ExtInst Modf/ModfStruct and Frexp/FrexpStruct append_tests({ "%_x = OpExtInst %float %glsl450 Modf %float_dyn_123_456 %priv_float\n" "%_y = OpLoad %float %priv_float\n" "%_tmp = OpExtInst %f32f32 %glsl450 ModfStruct %float_dyn_789_012\n" "%_z = OpCompositeExtract %float %_tmp 0\n" "%_w = OpCompositeExtract %float %_tmp 1\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", "%_x = OpExtInst %float %glsl450 Frexp %float_dyn_123_456 %priv_int\n" "%_yi = OpLoad %int %priv_int\n" "%_y = OpConvertSToF %float %_yi\n" "%_tmp = OpExtInst %f32i32 %glsl450 FrexpStruct %float_dyn_789_012\n" "%_z = OpCompositeExtract %float %_tmp 0\n" "%_wi = OpCompositeExtract %int %_tmp 1\n" "%_w = OpConvertSToF %float %_wi\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", }); // test float <-> int conversions append_tests({ "%_x = OpConvertUToF %float %uint_dyn_1234\n" "%_y = OpConvertSToF %float %int_dyn_1234\n" "%_z = OpConvertSToF %float %int_dyn_neg1234\n" "%_w = OpConvertUToF %float %uint_dyn_0\n" "%_out_float4 = OpCompositeConstruct %float4 %_x %_y %_z %_w\n", "%_x = OpConvertFToU %uint %float_dyn_1_0\n" "%_y = OpConvertFToU %uint %float_dyn_0_0\n" "%_z = OpConvertFToU %uint %float_dyn_1_1\n" "%_w = OpConvertFToU %uint %float_dyn_1_3\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", "%_x = OpConvertFToU %uint %float_dyn_1_0\n" "%_y = OpConvertFToU %uint %float_dyn_1_5\n" "%_z = OpConvertFToU %uint %float_dyn_0_5\n" "%_w = OpConvertFToU %uint %float_dyn_1_7\n" "%_out_uint4 = OpCompositeConstruct %uint4 %_x %_y %_z %_w\n", "%_x = OpConvertFToS %int %float_dyn_1_0\n" "%_y = OpConvertFToS %int %float_dyn_0_0\n" "%_z = OpConvertFToS %int %float_dyn_neg1_0\n" "%_w = OpConvertFToS %int %float_dyn_1_3\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", "%_x = OpConvertFToS %int %float_dyn_1_0\n" "%_y = OpConvertFToS %int %float_dyn_1_5\n" "%_z = OpConvertFToS %int %float_dyn_0_5\n" "%_w = OpConvertFToS %int %float_dyn_neg1_5\n" "%_out_int4 = OpCompositeConstruct %int4 %_x %_y %_z %_w\n", }); // test copies append_tests({ "OpCopyMemory %Color %gl_FragCoord\n" "; no_out\n", "%_src = OpAccessChain %ptr_Uniform_float4 %buffer %uint_2\n" "%_dst = OpAccessChain %ptr_Uniform_float4 %buffer %uint_4 %uint_3\n" "OpCopyMemory %_dst %_src\n" "OpCopyMemory %Color %_src\n" "; no_out\n", "%frag = OpLoad %float4 %gl_FragCoord\n" "%_out_float4 = OpCopyObject %float4 %frag\n", }); // test SSBO pointers append_tests({ "%_y = OpAccessChain %ptr_Uniform_dummy %buffer %uint_3\n" "%_src = OpAccessChain %ptr_Uniform_uint4 %_y %uint_0\n" "%_dst = OpAccessChain %ptr_Uniform_uint4 %_y %uint_1\n" "%_tmp = OpLoad %uint4 %_src\n" "OpStore %_dst %_tmp\n" "%_out_uint4 = OpLoad %uint4 %_dst\n", }); // disabled while shaderc has a bug that doesn't respect the target environment /* if(vk_version >= 0x12) { append_tests({ "%frag = OpLoad %float4 %gl_FragCoord\n" "%_out_float4 = OpCopyLogical %float4 %frag\n", }); } */ if(features.shaderFloat64) { // test pack/unpack from double append_tests({ "%_ptr = OpAccessChain %ptr_Uniform_uint2 %cbuffer %uint_16\n" "%_double_pack_source = OpLoad %uint2 %_ptr\n" "%_out_double = OpExtInst %double %glsl450 PackDouble2x32 %_double_pack_source\n", "%_ptr = OpAccessChain %ptr_Uniform_double %cbuffer %uint_17\n" "%_double_unpack_source = OpLoad %double %_ptr\n" "%_out_uint2 = OpExtInst %uint2 %glsl450 UnpackDouble2x32 %_double_unpack_source\n", "%_ptr = OpAccessChain %ptr_Uniform_double %cbuffer %uint_17\n" "%_pi = OpLoad %double %_ptr\n" "%_two = OpFConvert %double %float_2_0\n" "%_out_double = OpFMul %double %_pi %_two\n", }); } // test pointers into columns of matrices append_tests({ R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_colc = OpCompositeConstruct %float4 %randf_8 %randf_9 %randf_10 %randf_11 %_cold = OpCompositeConstruct %float4 %randf_12 %randf_13 %randf_14 %randf_15 %_ptra = OpAccessChain %ptr_Private_float4 %priv_float4x4 %uint_0 %_ptrb = OpAccessChain %ptr_Private_float4 %priv_float4x4 %uint_1 %_ptrc = OpAccessChain %ptr_Private_float4 %priv_float4x4 %uint_2 %_ptrd = OpAccessChain %ptr_Private_float4 %priv_float4x4 %uint_3 OpStore %_ptra %_cola OpStore %_ptrb %_colb OpStore %_ptrc %_colc OpStore %_ptrd %_cold %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_mat = OpLoad %float4x4 %priv_float4x4 %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_colc = OpCompositeConstruct %float4 %randf_8 %randf_9 %randf_10 %randf_11 %_cold = OpCompositeConstruct %float4 %randf_12 %randf_13 %randf_14 %randf_15 %_ptra = OpAccessChain %ptr_Uniform_float4 %buffer %uint_0 %uint_0 %_ptrb = OpAccessChain %ptr_Uniform_float4 %buffer %uint_0 %uint_1 %_ptrc = OpAccessChain %ptr_Uniform_float4 %buffer %uint_0 %uint_2 %_ptrd = OpAccessChain %ptr_Uniform_float4 %buffer %uint_0 %uint_3 OpStore %_ptra %_cola OpStore %_ptrb %_colb OpStore %_ptrc %_colc OpStore %_ptrd %_cold %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_ptrmat = OpAccessChain %ptr_Uniform_float4x4 %buffer %uint_0 %_mat = OpLoad %float4x4 %_ptrmat %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec )EOTEST", R"EOTEST( %_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3 %_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7 %_colc = OpCompositeConstruct %float4 %randf_8 %randf_9 %randf_10 %randf_11 %_cold = OpCompositeConstruct %float4 %randf_12 %randf_13 %randf_14 %randf_15 %_ptra = OpAccessChain %ptr_Uniform_float4 %buffer %uint_1 %uint_0 %_ptrb = OpAccessChain %ptr_Uniform_float4 %buffer %uint_1 %uint_1 %_ptrc = OpAccessChain %ptr_Uniform_float4 %buffer %uint_1 %uint_2 %_ptrd = OpAccessChain %ptr_Uniform_float4 %buffer %uint_1 %uint_3 OpStore %_ptra %_cola OpStore %_ptrb %_colb OpStore %_ptrc %_colc OpStore %_ptrd %_cold %_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19 %_ptrmat = OpAccessChain %ptr_Uniform_float4x4 %buffer %uint_1 %_mat = OpLoad %float4x4 %_ptrmat %_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec )EOTEST", }); // test variables with initialisers append_tests({ R"EOTEST( ; this has a constant initialiser, so should already be ready %_out_float4 = OpLoad %float4 %priv_float4_init )EOTEST", R"EOTEST( ; this is uninitialised, but unforuntately that means we can't test our debugging ; against the real thing when it's undefined. But we can at least expose it so that ; when manually checking we see the uninitialised values %_uninit = OpLoad %float4 %priv_float4 %_x = OpExtInst %float4 %glsl450 NClamp %_uninit %float4_0000 %float4_0000 %_out_float4 = OpFAdd %float4 %_x %float4_1234 )EOTEST", R"EOTEST( ; this is uninitialised, but unforuntately that means we can't test our debugging ; against the real thing when it's undefined. But we can at least expose it so that ; when manually checking we see the uninitialised values %_uninit = OpLoad %float4 %Color %_x = OpExtInst %float4 %glsl450 NClamp %_uninit %float4_0000 %float4_0000 %_out_float4 = OpFAdd %float4 %_x %float4_1234 )EOTEST", }); // test naming structs. Since we can't easily name auto-generated IDs we use a guid to give the // ID a unique name append_tests({ R"EOTEST( %_a = OpCompositeConstruct %float4 %float_dyn_4_2 %float_dyn_1_0 %float_dyn_9_5 %float_dyn_0_01 %C14FA880_4F83_4982_BEAD_CE9103446C76 = OpCompositeInsert %parent %_a %null_parent 0 %_out_float4 = OpCompositeExtract %float4 %C14FA880_4F83_4982_BEAD_CE9103446C76 0 )EOTEST", }); spv_debug += "OpName %C14FA880_4F83_4982_BEAD_CE9103446C76 \"C14FA880_4F83_4982_BEAD_CE9103446C76\"\n"; // test OpPhi append_tests({ // basic simple test R"EOTEST( OpBranch %_toplabel %_toplabel = OpLabel %_val = OpDot %float %inpos %float2_12 %_cond = OpFOrdGreaterThan %bool %_val %float_37_0 %_parent1 = OpFMul %float %float_2_0 %float_0_5 OpSelectionMerge %_merge None OpBranchConditional %_cond %_merge %_branchlabel %_branchlabel = OpLabel %_parent2 = OpFMul %float %float_2_0 %float_0_25 OpBranch %_merge %_merge = OpLabel ; choose either parent1 or parent2, depending on if we branched %_out_float = OpPhi %float %_parent1 %_toplabel %_parent2 %_branchlabel OpBranch %_bottomlabel %_bottomlabel = OpLabel )EOTEST", // test with a function call in each branch to ensure we still track the last block // accurately R"EOTEST( OpBranch %_toplabel %_toplabel = OpLabel %_val = OpDot %float %inpos %float2_12 %_cond = OpFOrdGreaterThan %bool %_val %float_37_0 %_parent1 = OpFunctionCall %float %doubler %float_0_5 OpSelectionMerge %_merge None OpBranchConditional %_cond %_merge %_branchlabel %_branchlabel = OpLabel %_parent2 = OpFunctionCall %float %doubler %float_0_25 OpBranch %_merge %_merge = OpLabel ; choose either parent1 or parent2, depending on if we branched %_out_float = OpPhi %float %_parent1 %_toplabel %_parent2 %_branchlabel OpBranch %_bottomlabel %_bottomlabel = OpLabel )EOTEST", }); // test switch for different integer types std::vector intTypes = {"int", "uint"}; std::vector caseLiterals = {"0x12345678", "0xF2345678"}; if(features.shaderInt64) { intTypes.push_back("i64"); intTypes.push_back("u64"); caseLiterals.push_back("0x1234567812345678"); caseLiterals.push_back("0xF234567812345678"); } for(size_t i = 0; i < intTypes.size(); ++i) { append_tests({fmt::format( "%_test_switch_{0} = OpIAdd %{0} %{0}_0 %{0}_{1}\n" "OpSelectionMerge %_break_{0} None\n" "OpSwitch %_test_switch_{0} %_default_{0} 2 %_case_{0}_2 {1} %_case_{0}_{1}\n" "%_case_{0}_2 = OpLabel\n" "OpUnreachable\n" "%_case_{0}_{1} = OpLabel\n" "%_out_{0} = OpIAdd %{0} %{0}_0 %{0}_7\n" "OpBranch %_break_{0}\n" "%_default_{0} = OpLabel\n" "OpUnreachable\n" "%_break_{0} = OpLabel\n", intTypes[i], caseLiterals[i])}); } // test buffer device address if(bdaFeatures.bufferDeviceAddress) { // bitcast uint2 address to pointer append_tests({ R"EOTEST( %_ptr_addr_bda_data_struct = OpAccessChain %ptr_PushConstant_uint2 %push_data %int_1 %_addr_bda_data_struct = OpLoad %uint2 %_ptr_addr_bda_data_struct %_ptr_bda_data_struct = OpBitcast %ptr_PhysicalStorageBuffer_bda_data_struct %_addr_bda_data_struct %_ptr_first = OpAccessChain %ptr_PhysicalStorageBuffer_bda_data_struct_first %_ptr_bda_data_struct %int_0 %_out_float4 = OpLoad %float4 %_ptr_first Aligned 16 )EOTEST", // OpPtrAccessChain : float[] : ArrayStride 4 R"EOTEST( %_ptr_addr_bda_data_struct = OpAccessChain %ptr_PushConstant_uint2 %push_data %int_1 %_addr_bda_data_struct = OpLoad %uint2 %_ptr_addr_bda_data_struct %_ptr_bda_data_struct = OpBitcast %ptr_PhysicalStorageBuffer_bda_data_struct_f32_4 %_addr_bda_data_struct %_ptr_f32 = OpPtrAccessChain %ptr_PhysicalStorageBuffer_f32 %_ptr_bda_data_struct %int_dyn_1 %_out_float = OpLoad %float %_ptr_f32 Aligned 16 )EOTEST", // OpPtrAccessChain : float[] : ArrayStride 8 R"EOTEST( %_ptr_addr_bda_data_struct = OpAccessChain %ptr_PushConstant_uint2 %push_data %int_1 %_addr_bda_data_struct = OpLoad %uint2 %_ptr_addr_bda_data_struct %_ptr_bda_data_struct = OpBitcast %ptr_PhysicalStorageBuffer_bda_data_struct_f32_8 %_addr_bda_data_struct %_ptr_f32 = OpPtrAccessChain %ptr_PhysicalStorageBuffer_f32 %_ptr_bda_data_struct %int_dyn_1 %_out_float = OpLoad %float %_ptr_f32 Aligned 16 )EOTEST", // OpPtrAccessChain : float[] : ArrayStride 12 R"EOTEST( %_ptr_addr_bda_data_struct = OpAccessChain %ptr_PushConstant_uint2 %push_data %int_1 %_addr_bda_data_struct = OpLoad %uint2 %_ptr_addr_bda_data_struct %_ptr_bda_data_struct = OpBitcast %ptr_PhysicalStorageBuffer_bda_data_struct_f32_12 %_addr_bda_data_struct %_ptr_f32 = OpPtrAccessChain %ptr_PhysicalStorageBuffer_f32 %_ptr_bda_data_struct %int_dyn_1 %_out_float = OpLoad %float %_ptr_f32 Aligned 16 )EOTEST", }); if(features.shaderInt64) { append_tests({ // Convert u64 address to pointer R"EOTEST( %_ptr_addr_bda_data_struct = OpAccessChain %ptr_PushConstant_u64 %push_data %int_4 %_addr_bda_data_struct = OpLoad %u64 %_ptr_addr_bda_data_struct %_ptr_bda_data_struct = OpConvertUToPtr %ptr_PhysicalStorageBuffer_bda_data_struct %_addr_bda_data_struct %_ptr_first = OpAccessChain %ptr_PhysicalStorageBuffer_bda_data_struct_first %_ptr_bda_data_struct %int_1 %_out_float4 = OpLoad %float4 %_ptr_first Aligned 16 )EOTEST", // Convert u64 address to pointer back to u64 address R"EOTEST( %_ptr_addr_bda_data_struct = OpAccessChain %ptr_PushConstant_u64 %push_data %int_4 %_addr = OpLoad %u64 %_ptr_addr_bda_data_struct %_addr_bda_data_struct = OpIAdd %u64 %_addr %u64_dyn_8 %_ptr_bda_data_struct = OpConvertUToPtr %ptr_PhysicalStorageBuffer_bda_data_struct %_addr_bda_data_struct %_out_u64 = OpConvertPtrToU %u64 %_ptr_bda_data_struct )EOTEST", // arithmetic on u64 address then convert u64 address to pointer R"EOTEST( %_ptr_addr_bda_data_struct = OpAccessChain %ptr_PushConstant_u64 %push_data %int_4 %_addr = OpLoad %u64 %_ptr_addr_bda_data_struct %_addr2 = OpIAdd %u64 %_addr %u64_dyn_1023 %_addr3 = OpISub %u64 %_addr2 %u64_dyn_1023 %_addr_bda_data_struct = OpIAdd %u64 %_addr3 %u64_dyn_16 %_ptr_bda_data_struct = OpConvertUToPtr %ptr_PhysicalStorageBuffer_bda_data_struct %_addr_bda_data_struct %_ptr_first = OpInBoundsAccessChain %ptr_PhysicalStorageBuffer_bda_data_struct_first %_ptr_bda_data_struct %int_0 %_out_float4 = OpLoad %float4 %_ptr_first Aligned 16 )EOTEST", // form u64 address by arithmetic from two u32 values R"EOTEST( %_ptr_addr_bda_data_struct_hi = OpAccessChain %ptr_PushConstant_uint %push_data %int_2 %_addr_bda_data_struct_hi = OpLoad %uint %_ptr_addr_bda_data_struct_hi %_ptr_addr_bda_data_struct_lo = OpAccessChain %ptr_PushConstant_uint %push_data %int_3 %_addr_bda_data_struct_lo = OpLoad %uint %_ptr_addr_bda_data_struct_lo %_addr_u64_hi = OpUConvert %u64 %_addr_bda_data_struct_hi %_addr_u64_lo = OpUConvert %u64 %_addr_bda_data_struct_lo %_addr_u64 = OpShiftLeftLogical %u64 %_addr_u64_hi %uint_32 %_addr_bda_data_struct = OpIAdd %u64 %_addr_u64 %_addr_u64_lo %_ptr_bda_data_struct = OpConvertUToPtr %ptr_PhysicalStorageBuffer_bda_data_struct %_addr_bda_data_struct %_ptr_first = OpAccessChain %ptr_PhysicalStorageBuffer_bda_data_struct_first %_ptr_bda_data_struct %int_0 %_out_float4 = OpLoad %float4 %_ptr_first Aligned 16 )EOTEST", }); } } } std::string make_pixel_asm() { std::string switch_str = R"EOSHADER( OpSelectionMerge %break None OpSwitch %test %default )EOSHADER"; std::set null_constants; std::set float_constants = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f}; std::set int_constants = {7}; std::set uint_constants; std::set i64_constants; std::set u64_constants; std::set u8_constants; std::set u16_constants; std::string cases; for(size_t i = 0; i < asm_tests.size(); i++) { std::string &test = asm_tests[i]; // append a newline just so that searching for whitespace always finds it even if the last // thing in the test is a %_foo test += "\n"; // add the test's case switch_str += fmt::format("{0} %test_{0}\n", i); cases += fmt::format("%test_{} = OpLabel\n", i); std::string test_suffix = fmt::format("_{}", i); // find any identifiers with the prefix %_ in the test, and append _testindex size_t offs = test.find("%_"); while(offs != std::string::npos) { offs = test.find_first_of("\n\t ", offs); test.insert(offs, test_suffix); offs = test.find("%_", offs); } // find any null constants referenced offs = test.find("%null_"); while(offs != std::string::npos) { offs += 6; // past %null_ size_t begin = offs; offs = test.find_first_of("\n\t ", offs); null_constants.insert(test.substr(begin, offs - begin)); offs = test.find("%null_", offs); } // find any float constants referenced for(std::string prefix : {"%float_", "%double_", "%half_"}) { offs = test.find(prefix); while(offs != std::string::npos) { offs += prefix.size(); // we generate dynamic and negative versions of all constants, skip to the first digit offs = test.find_first_of("0123456789", offs); size_t begin = offs; offs = test.find_first_of("\n\t ", offs); std::string val = test.substr(begin, offs - begin); // convert any _ to a . for(char &c : val) if(c == '_') c = '.'; float_constants.insert(std::strtof(val.c_str(), NULL)); offs = test.find(prefix, offs); } } // find any u8 constants referenced offs = test.find("%u8_"); while(offs != std::string::npos) { offs += 4; // past %u8_ // we generate dynamic and negative versions of all constants, skip to the first digit offs = test.find_first_of("0123456789", offs); // handle hex prefix int base = 10; if(test[offs] == '0' && test[offs + 1] == 'x') { base = 16; offs += 2; } uint8_t val = (uint8_t)std::strtoul(&test[offs], NULL, base); u8_constants.insert(val); // if it's a hex constant we'll name it in decimal, rename if(base == 16) { size_t end = test.find_first_of("\n\t ", offs); test.replace(offs - 2, end - offs + 2, fmt::format("{}", val)); } offs = test.find("%u8_", offs); } // find any u16 constants referenced offs = test.find("%u16_"); while(offs != std::string::npos) { offs += 5; // past %u16_ // we generate dynamic and negative versions of all constants, skip to the first digit offs = test.find_first_of("0123456789", offs); // handle hex prefix int base = 10; if(test[offs] == '0' && test[offs + 1] == 'x') { base = 16; offs += 2; } uint16_t val = (uint16_t)std::strtoul(&test[offs], NULL, base); u16_constants.insert(val); // if it's a hex constant we'll name it in decimal, rename if(base == 16) { size_t end = test.find_first_of("\n\t ", offs); test.replace(offs - 2, end - offs + 2, fmt::format("{}", val)); } offs = test.find("%u16_", offs); } // find any int constants referenced offs = test.find("%int_"); while(offs != std::string::npos) { offs += 5; // past %int_ // we generate dynamic and negative versions of all constants, skip to the first digit offs = test.find_first_of("0123456789", offs); // handle hex prefix int base = 10; if(test[offs] == '0' && test[offs + 1] == 'x') { base = 16; offs += 2; } int32_t val = (int32_t)std::strtol(&test[offs], NULL, base); int_constants.insert(val); // if it's a hex constant we'll name it in decimal, rename if(base == 16) { size_t end = test.find_first_of("\n\t ", offs); test.replace(offs - 2, end - offs + 2, fmt::format("{}", val)); } offs = test.find("%int_", offs); } // find any uint constants referenced offs = test.find("%uint_"); while(offs != std::string::npos) { offs += 6; // past %uint_ // we generate dynamic and negative versions of all constants, skip to the first digit offs = test.find_first_of("0123456789", offs); // handle hex prefix int base = 10; if(test[offs] == '0' && test[offs + 1] == 'x') { base = 16; offs += 2; } uint32_t val = (uint32_t)std::strtoul(&test[offs], NULL, base); uint_constants.insert(val); // if it's a hex constant we'll name it in decimal, rename if(base == 16) { size_t end = test.find_first_of("\n\t ", offs); test.replace(offs - 2, end - offs + 2, fmt::format("{}", val)); } offs = test.find("%uint_", offs); } // find any i64 constants referenced offs = test.find("%i64_"); while(offs != std::string::npos) { offs += 5; // past %i64_ // we generate dynamic and negative versions of all constants, skip to the first digit offs = test.find_first_of("0123456789", offs); // handle hex prefix int base = 10; if(test[offs] == '0' && test[offs + 1] == 'x') { base = 16; offs += 2; } int64_t val = std::strtoll(&test[offs], NULL, base); i64_constants.insert(val); // if it's a hex constant we'll name it in decimal, rename if(base == 16) { size_t end = test.find_first_of("\n\t ", offs); test.replace(offs - 2, end - offs + 2, fmt::format("{}", val)); } offs = test.find("%i64_", offs); } // find any u64 constants referenced offs = test.find("%u64_"); while(offs != std::string::npos) { offs += 5; // past %u64_ // we generate dynamic and negative versions of all constants, skip to the first digit offs = test.find_first_of("0123456789", offs); // handle hex prefix int base = 10; if(test[offs] == '0' && test[offs + 1] == 'x') { base = 16; offs += 2; } uint64_t val = std::strtoull(&test[offs], NULL, base); u64_constants.insert(val); // if it's a hex constant we'll name it in decimal, rename if(base == 16) { size_t end = test.find_first_of("\n\t ", offs); test.replace(offs - 2, end - offs + 2, fmt::format("{}", val)); } offs = test.find("%u64_", offs); } // add the test itself now cases += "\n"; cases += test; cases += "\n"; bool store_out = true; if(test.find("%_out_float4") != std::string::npos) { // if the test outputted a float4, we can dump it directly cases += fmt::format("OpStore %Color %_out_float4_{}\n", i); } else { // otherwise convert and up-swizzle to float4 as needed if(test.find("%_out_float_") != std::string::npos) { cases += fmt::format( "%Color_{0} = OpCompositeConstruct %float4 " " %_out_float_{0} %_out_float_{0} %_out_float_{0} %_out_float_{0}\n", i); } else if(test.find("%_out_float2_") != std::string::npos) { cases += fmt::format( "%Color_{0} = OpVectorShuffle %float4 %_out_float2_{0} %_out_float2_{0} 0 1 0 1\n", i); } else if(test.find("%_out_float3_") != std::string::npos) { cases += fmt::format( "%Color_{0} = OpVectorShuffle %float4 %_out_float3_{0} %_out_float3_{0} 0 1 2 0\n", i); } else if(test.find("%_out_double_") != std::string::npos) { cases += fmt::format( "%_out_float_{0} = OpFConvert %float %_out_double_{0}\n" "%Color_{0} = OpCompositeConstruct %float4 " " %_out_float_{0} %_out_float_{0} %_out_float_{0} %_out_float_{0}\n", i); } else if(test.find("%_out_double2_") != std::string::npos) { cases += fmt::format( "%_out_float2_{0} = OpFConvert %float2 %_out_double2_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_out_float2_{0} %_out_float2_{0} 0 1 0 1\n", i); } else if(test.find("%_out_double3_") != std::string::npos) { cases += fmt::format( "%_out_float3_{0} = OpFConvert %float3 %_out_double3_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_out_float3_{0} %_out_float3_{0} 0 1 2 0\n", i); } else if(test.find("%_out_double4_") != std::string::npos) { cases += fmt::format("%Color_{0} = OpFConvert %float4 %_out_double4_{0}\n", i); } else if(test.find("%_out_int_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertSToF %float %_out_int_{0}\n" "%Color_{0} = OpCompositeConstruct %float4 %_f_{0} %_f_{0} %_f_{0} %_f_{0}\n", i); } else if(test.find("%_out_int2_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertSToF %float2 %_out_int2_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_f_{0} %_f_{0} 0 1 0 1\n", i); } else if(test.find("%_out_int3_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertSToF %float3 %_out_int3_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_f_{0} %_f_{0} 0 1 2 0\n", i); } else if(test.find("%_out_int4_") != std::string::npos) { cases += fmt::format("%Color_{0} = OpConvertSToF %float4 %_out_int4_{0}\n", i); } else if(test.find("%_out_uint_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertUToF %float %_out_uint_{0}\n" "%Color_{0} = OpCompositeConstruct %float4 %_f_{0} %_f_{0} %_f_{0} %_f_{0}\n", i); } else if(test.find("%_out_uint2_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertUToF %float2 %_out_uint2_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_f_{0} %_f_{0} 0 1 0 1\n", i); } else if(test.find("%_out_uint3_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertUToF %float3 %_out_uint3_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_f_{0} %_f_{0} 0 1 2 0\n", i); } else if(test.find("%_out_uint4_") != std::string::npos) { cases += fmt::format("%Color_{0} = OpConvertUToF %float4 %_out_uint4_{0}\n", i); } else if(test.find("%_out_i64_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertSToF %float %_out_i64_{0}\n" "%Color_{0} = OpCompositeConstruct %float4 %_f_{0} %_f_{0} %_f_{0} " "%_f_{0}\n", i); } else if(test.find("%_out_u64_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertUToF %float %_out_u64_{0}\n" "%Color_{0} = OpCompositeConstruct %float4 %_f_{0} %_f_{0} %_f_{0} " "%_f_{0}\n", i); } else if(test.find("%_out_u8v2_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertUToF %float2 %_out_u8v2_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_f_{0} %_f_{0} 0 1 0 1\n", i); } else if(test.find("%_out_u8v4_") != std::string::npos) { cases += fmt::format("%Color_{0} = OpConvertUToF %float4 %_out_u8v4_{0}\n", i); } else if(test.find("%_out_u16_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertUToF %float %_out_u16_{0}\n" "%Color_{0} = OpCompositeConstruct %float4 %_f_{0} %_f_{0} %_f_{0} %_f_{0}\n", i); } else if(test.find("%_out_u16v2_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpConvertUToF %float2 %_out_u16v2_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_f_{0} %_f_{0} 0 1 0 1\n", i); } else if(test.find("%_out_u16v4_") != std::string::npos) { cases += fmt::format("%Color_{0} = OpConvertUToF %float4 %_out_u16v4_{0}\n", i); } else if(test.find("%_out_half2_") != std::string::npos) { cases += fmt::format( "%_f_{0} = OpFConvert %float2 %_out_half2_{0}\n" "%Color_{0} = OpVectorShuffle %float4 %_f_{0} %_f_{0} 0 1 0 1\n", i); } else if(test.find("; no_out") != std::string::npos) { store_out = false; } else { TEST_FATAL("Test with no recognised output"); } if(store_out) cases += fmt::format("OpStore %Color %Color_{}\n", i); } cases += "OpBranch %break\n"; } if(features.shaderFloat64) { typesConstants += "%double = OpTypeFloat 64\n" "%double2 = OpTypeVector %double 2\n" "%double3 = OpTypeVector %double 3\n" "%double4 = OpTypeVector %double 4\n" "%double2x2 = OpTypeMatrix %double2 2\n" "%double3x3 = OpTypeMatrix %double3 3\n" "%double2x4 = OpTypeMatrix %double2 4\n" "%double4x2 = OpTypeMatrix %double4 2\n" "%double4x4 = OpTypeMatrix %double4 4\n"; typesConstants += "%ptr_Uniform_double = OpTypePointer Uniform %double\n"; capabilities += "OpCapability Float64\n"; } if(float16Int8Features.shaderFloat16) { typesConstants += "%half = OpTypeFloat 16\n" "%half2 = OpTypeVector %half 2\n"; capabilities += "OpCapability Float16\n"; } if(float16Int8Features.shaderInt8 || storage8Features.storageBuffer8BitAccess || storage8Features.uniformAndStorageBuffer8BitAccess || storage8Features.storagePushConstant8) { typesConstants += "%i8 = OpTypeInt 8 1\n" "%u8 = OpTypeInt 8 0\n" "%u8v2 = OpTypeVector %u8 2\n" "%u8v4 = OpTypeVector %u8 4\n"; capabilities += "OpCapability Int8\n"; } if(features.shaderInt64) { typesConstants += "%i64 = OpTypeInt 64 1\n" "%u64 = OpTypeInt 64 0\n"; capabilities += "OpCapability Int64\n"; } if(features.shaderInt16 || storage16Features.storageBuffer16BitAccess || storage16Features.uniformAndStorageBuffer16BitAccess || storage16Features.storagePushConstant16 || storage16Features.storageInputOutput16) { typesConstants += "%i16 = OpTypeInt 16 1\n" "%u16 = OpTypeInt 16 0\n" "%u16v2 = OpTypeVector %u16 2\n" "%u16v4 = OpTypeVector %u16 4\n"; capabilities += "OpCapability Int16\n"; } if(bdaFeatures.bufferDeviceAddress) { capabilities += "OpCapability PhysicalStorageBufferAddresses\n"; spv_extensions += R"EOSHADER( OpExtension "SPV_KHR_physical_storage_buffer" )EOSHADER"; typesConstants += "%pushdata_struct = OpTypeStruct %int4 %uint2 %uint %uint"; if(features.shaderInt64) typesConstants += " %u64\n"; else typesConstants += " %uint2\n"; typesConstants += R"EOSHADER( %ptr_PushConstant_pushdata_struct = OpTypePointer PushConstant %pushdata_struct %push_data = OpVariable %ptr_PushConstant_pushdata_struct PushConstant %ptr_PushConstant_uint = OpTypePointer PushConstant %uint %ptr_PushConstant_uint2 = OpTypePointer PushConstant %uint2 )EOSHADER"; if(features.shaderInt64) typesConstants += "%ptr_PushConstant_u64 = OpTypePointer PushConstant %u64\n"; typesConstants += "%bda_data_struct = OpTypeStruct %float4 %float4"; typesConstants += R"EOSHADER( %ptr_PhysicalStorageBuffer_bda_data_struct = OpTypePointer PhysicalStorageBuffer %bda_data_struct %ptr_PhysicalStorageBuffer_bda_data_struct_first = OpTypePointer PhysicalStorageBuffer %float4 %ptr_PhysicalStorageBuffer_bda_data_struct_f32_4 = OpTypePointer PhysicalStorageBuffer %float %ptr_PhysicalStorageBuffer_bda_data_struct_f32_8 = OpTypePointer PhysicalStorageBuffer %float %ptr_PhysicalStorageBuffer_bda_data_struct_f32_12 = OpTypePointer PhysicalStorageBuffer %float %ptr_PhysicalStorageBuffer_f32 = OpTypePointer PhysicalStorageBuffer %float )EOSHADER"; decorations += R"EOSHADER( OpDecorate %ptr_PhysicalStorageBuffer_bda_data_struct_f32_4 ArrayStride 4 OpDecorate %ptr_PhysicalStorageBuffer_bda_data_struct_f32_8 ArrayStride 8 OpDecorate %ptr_PhysicalStorageBuffer_bda_data_struct_f32_12 ArrayStride 12 OpDecorate %pushdata_struct Block OpMemberDecorate %pushdata_struct 0 Offset 16 ; int4 data OpMemberDecorate %pushdata_struct 1 Offset 32 ; uint2 bda_uvec2 OpMemberDecorate %pushdata_struct 2 Offset 40 ; uint bda_hi OpMemberDecorate %pushdata_struct 3 Offset 44 ; uint bda_lo OpMemberDecorate %pushdata_struct 4 Offset 48 ; uint64_t bda_u64 OpDecorate %bda_data_struct Block OpMemberDecorate %bda_data_struct 0 Offset 0 ; float f32[0..3] OpMemberDecorate %bda_data_struct 1 Offset 16 ; float f32[4..7] )EOSHADER"; } std::string cbuffer = "%cbuffer_struct = OpTypeStruct %float4 %float4 %float4 %float4 %float4 %float4 %float4 " " %float4 %float4 %float4 %float4 %float4 %uint %uint %uint " " %uint %uint2"; if(features.shaderFloat64) cbuffer += " %double"; else cbuffer += " %uint2"; cbuffer += "\n"; typesConstants += cbuffer; decorations += R"EOSHADER( OpDecorate %cbuffer_struct Block OpDecorate %cbuffer DescriptorSet 0 OpDecorate %cbuffer Binding 10 OpMemberDecorate %cbuffer_struct 0 Offset 0 ; vec4 first OpMemberDecorate %cbuffer_struct 1 Offset 16 ; vec4 pad1 OpMemberDecorate %cbuffer_struct 2 Offset 32 ; vec4 second OpMemberDecorate %cbuffer_struct 3 Offset 48 ; vec4 nan OpMemberDecorate %cbuffer_struct 4 Offset 64 ; vec4 third OpMemberDecorate %cbuffer_struct 5 Offset 80 ; vec4 pad3 OpMemberDecorate %cbuffer_struct 6 Offset 96 ; vec4 fourth OpMemberDecorate %cbuffer_struct 7 Offset 112 ; vec4 unorm2PackSource OpMemberDecorate %cbuffer_struct 8 Offset 128 ; vec4 snorm2PackSource OpMemberDecorate %cbuffer_struct 9 Offset 144 ; vec4 unorm4PackSource OpMemberDecorate %cbuffer_struct 10 Offset 160 ; vec4 snorm4PackSource OpMemberDecorate %cbuffer_struct 11 Offset 176 ; vec4 halfPackSource OpMemberDecorate %cbuffer_struct 12 Offset 192 ; uint unormUnpackSource OpMemberDecorate %cbuffer_struct 13 Offset 196 ; uint snormUnpackSource OpMemberDecorate %cbuffer_struct 14 Offset 200 ; uint halfUnpackSource OpMemberDecorate %cbuffer_struct 15 Offset 204 ; uint pad OpMemberDecorate %cbuffer_struct 16 Offset 208 ; uint2 doubleUnpackSource OpMemberDecorate %cbuffer_struct 17 Offset 216 ; double doublePackSource )EOSHADER"; typesConstants += "%ptr_Uniform_cbuffer_struct = OpTypePointer Uniform %cbuffer_struct\n" "%cbuffer = OpVariable %ptr_Uniform_cbuffer_struct Uniform\n"; // now generate all the constants for(const std::string &n : null_constants) typesConstants += fmt::format("%null_{0} = OpConstantNull %{0}\n", n); typesConstants += "\n"; for(float f : float_constants) { std::string name = fmt::format("{}", f); for(char &c : name) if(c == '.') c = '_'; typesConstants += fmt::format("%float_{} = OpConstant %float {}\n", name, f); typesConstants += fmt::format("%float_neg{} = OpConstant %float -{}\n", name, f); if(float16Int8Features.shaderFloat16) { typesConstants += fmt::format("%half_{} = OpConstant %half {}\n", name, f); typesConstants += fmt::format("%half_neg{} = OpConstant %half -{}\n", name, f); } if(features.shaderFloat64) { typesConstants += fmt::format("%double_{} = OpConstant %double {}\n", name, f); typesConstants += fmt::format("%double_neg{} = OpConstant %double -{}\n", name, f); } } typesConstants += "\n"; if(float16Int8Features.shaderInt8) { typesConstants += "\n"; for(uint8_t u : u8_constants) typesConstants += fmt::format("%u8_{0} = OpConstant %u8 {0}\n", u); } if(features.shaderInt16) { typesConstants += "\n"; for(uint16_t u : u16_constants) typesConstants += fmt::format("%u16_{0} = OpConstant %u16 {0}\n", u); } for(int32_t i : int_constants) { typesConstants += fmt::format("%int_{0} = OpConstant %int {0}\n", i); typesConstants += fmt::format("%int_neg{0} = OpConstant %int -{0}\n", i); } typesConstants += "\n"; for(uint32_t u : uint_constants) typesConstants += fmt::format("%uint_{0} = OpConstant %uint {0}\n", u); typesConstants += "\n"; if(features.shaderInt64) { for(int64_t i : i64_constants) { typesConstants += fmt::format("%i64_{0} = OpConstant %i64 {0}\n", i); typesConstants += fmt::format("%i64_neg{0} = OpConstant %i64 -{0}\n", i); } typesConstants += "\n"; for(uint64_t u : u64_constants) { typesConstants += fmt::format("%u64_{0} = OpConstant %u64 {0}\n", u); } typesConstants += "\n"; } else { if(!i64_constants.empty()) TEST_FATAL("Test using i64 constants without shaderInt64 capability"); if(!u64_constants.empty()) TEST_FATAL("Test using u64 constants without shaderInt64 capability"); } for(size_t i = 0; i < 32; i++) typesConstants += fmt::format("%randf_{} = OpConstant %float {:.3}\n", i, RANDF(0.0f, 1.0f)); typesConstants += "\n"; // vector constants here manually, as we can't pull these out easily typesConstants += R"EOSHADER( %float4_0000 = OpConstantComposite %float4 %float_0_0 %float_0_0 %float_0_0 %float_0_0 %float4_1234 = OpConstantComposite %float4 %float_1_0 %float_2_0 %float_3_0 %float_4_0 %float3_000 = OpConstantComposite %float3 %float_0_0 %float_0_0 %float_0_0 %float3_123 = OpConstantComposite %float3 %float_1_0 %float_2_0 %float_3_0 %float2_00 = OpConstantComposite %float2 %float_0_0 %float_0_0 %float2_12 = OpConstantComposite %float2 %float_1_0 %float_2_0 %priv_float4_init = OpVariable %ptr_Private_float4 Private %float4_1234 )EOSHADER"; std::string memory_model = (bdaFeatures.bufferDeviceAddress) ? "PhysicalStorageBuffer64" : "Logical"; std::string ret = capabilities + spv_extensions + extinstimport + R"EOSHADER( OpMemoryModel )EOSHADER" + memory_model + " GLSL450\n" + R"EOSHADER( OpEntryPoint Fragment %main "main" %flatData %linearData %Color %gl_FragCoord )EOSHADER" + executionmodes + spv_debug + decorations + typesConstants + functions + R"EOSHADER( %main = OpFunction %void None %mainfunc %main_begin = OpLabel %test_ptr = OpAccessChain %ptr_Input_uint %flatData %flatv2f_test_idx %test = OpLoad %uint %test_ptr %zeroVal_ptr = OpAccessChain %ptr_Input_float2 %linearData %v2f_zeroVal_idx %zeroVal = OpLoad %float2 %zeroVal_ptr %zeroVal_x = OpCompositeExtract %float %zeroVal 0 %zeroVal_y = OpCompositeExtract %float %zeroVal 1 %zerof = OpCompositeExtract %float %zeroVal 0 %inpos_ptr = OpAccessChain %ptr_Input_float2 %linearData %v2f_inpos_idx %inpos = OpLoad %float2 %inpos_ptr %inposIncreased_ptr = OpAccessChain %ptr_Input_float2 %linearData %v2f_inposIncreased_idx %inposIncreased = OpLoad %float2 %inposIncreased_ptr %tinyVal_ptr = OpAccessChain %ptr_Input_float %linearData %v2f_tinyVal_idx %tinyVal = OpLoad %float %tinyVal_ptr %oneVal_ptr = OpAccessChain %ptr_Input_float %linearData %v2f_oneVal_idx %oneVal = OpLoad %float %oneVal_ptr %negoneVal_ptr = OpAccessChain %ptr_Input_float %linearData %v2f_negoneVal_idx %negoneVal = OpLoad %float %negoneVal_ptr %posinf = OpFDiv %float %oneVal %zerof %neginf = OpFDiv %float %negoneVal %zerof ; NaN generation is hard and we want to avoid compilers compiling it out, so generate ; it in shader and multiply by one from a UBO so we get NaN either way ; (since NaN * anything = NaN) %nan_shad = OpFDiv %float %zerof %zerof %nan_ptr = OpAccessChain %ptr_Uniform_float4 %cbuffer %uint_3 %nan_ubo = OpLoad %float4 %nan_ptr %nan_ubo_x = OpCompositeExtract %float %nan_ubo 0 %nan = OpFMul %float %nan_shad %nan_ubo_x %intval_ptr = OpAccessChain %ptr_Input_uint %flatData %flatv2f_intval_idx %intval = OpLoad %uint %intval_ptr %tmp = OpISub %uint %intval %test %zerou = OpISub %uint %tmp %int_7 %zeroi = OpBitcast %int %zerou )EOSHADER"; if(features.shaderFloat64) ret += "%zerof64 = OpFConvert %double %zerof\n"; if(features.shaderInt64) { ret += "%_temp = OpCompositeConstruct %uint2 %zerou %zerou\n" "%zerou64 = OpBitcast %u64 %_temp\n"; } // generate dynamic versions of the constants for(float f : float_constants) { std::string name = fmt::format("{}", f); for(char &c : name) if(c == '.') c = '_'; ret += fmt::format("%float_dyn_{0} = OpFAdd %float %zerof %float_{0}\n", name); ret += fmt::format("%float_dyn_neg{0} = OpFAdd %float %zerof %float_neg{0}\n", name); if(features.shaderFloat64) { ret += fmt::format("%double_dyn_{0} = OpFAdd %double %zerof64 %double_{0}\n", name); ret += fmt::format("%double_dyn_neg{0} = OpFAdd %double %zerof64 %double_neg{0}\n", name); } } ret += "\n"; for(int32_t i : int_constants) { ret += fmt::format("%int_dyn_{0} = OpIAdd %int %zeroi %int_{0}\n", i); ret += fmt::format("%int_dyn_neg{0} = OpIAdd %int %zeroi %int_neg{0}\n", i); } ret += "\n"; for(uint32_t u : uint_constants) ret += fmt::format("%uint_dyn_{0} = OpIAdd %uint %zerou %uint_{0}\n", u); for(uint64_t u : u64_constants) ret += fmt::format("%u64_dyn_{0} = OpIAdd %u64 %zerou64 %u64_{0}\n", u); ret += "\n"; for(size_t i = 0; i < 32; i++) ret += fmt::format("%randf_dyn_{0} = OpFAdd %float %zerof %randf_{0}\n", i); ret += "\n"; ret += R"EOSHADER( %float4_dyn_0000 = OpCompositeConstruct %float4 %float_dyn_0_0 %float_dyn_0_0 %float_dyn_0_0 %float_dyn_0_0 %float4_dyn_1234 = OpCompositeConstruct %float4 %float_dyn_1_0 %float_dyn_2_0 %float_dyn_3_0 %float_dyn_4_0 %float3_dyn_000 = OpCompositeConstruct %float3 %float_dyn_0_0 %float_dyn_0_0 %float_dyn_0_0 %float3_dyn_123 = OpCompositeConstruct %float3 %float_dyn_1_0 %float_dyn_2_0 %float_dyn_3_0 %float2_dyn_00 = OpCompositeConstruct %float2 %float_dyn_0_0 %float_dyn_0_0 %float2_dyn_12 = OpCompositeConstruct %float2 %float_dyn_1_0 %float_dyn_2_0 )EOSHADER"; ret += switch_str; ret += cases; ret += R"EOSHADER( %default = OpLabel OpStore %Color %float4_0000 OpBranch %break %break = OpLabel OpReturn OpFunctionEnd )EOSHADER"; return ret; } uint32_t vk_version = 0x10; VkPhysicalDevice16BitStorageFeaturesKHR storage16Features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR, }; VkPhysicalDevice8BitStorageFeaturesKHR storage8Features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR, }; VkPhysicalDeviceFloat16Int8FeaturesKHR float16Int8Features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR, }; VkPhysicalDeviceBufferDeviceAddressFeaturesEXT bdaFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR, }; void Prepare(int argc, char **argv) { // require descriptor indexing optDevExts.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); // dependencies of VK_EXT_descriptor_indexing optDevExts.push_back(VK_KHR_MAINTENANCE3_EXTENSION_NAME); // add float16/int8 extensions optDevExts.push_back(VK_KHR_8BIT_STORAGE_EXTENSION_NAME); optDevExts.push_back(VK_KHR_16BIT_STORAGE_EXTENSION_NAME); optDevExts.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); // dependencies of VK_KHR_8bit_storage optDevExts.push_back(VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME); // add BDA extension optDevExts.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); // we require this to pixel shader debug anyway, so we might as well require it for all tests. features.fragmentStoresAndAtomics = VK_TRUE; // this is so widely supported just require it without fallback features.imageCubeArray = VK_TRUE; VulkanGraphicsTest::Prepare(argc, argv); if(!Avail.empty()) return; const bool descIndexing = std::find(devExts.begin(), devExts.end(), VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME) != devExts.end(); const bool storage16 = std::find(devExts.begin(), devExts.end(), VK_KHR_16BIT_STORAGE_EXTENSION_NAME) != devExts.end(); const bool storage8 = std::find(devExts.begin(), devExts.end(), VK_KHR_8BIT_STORAGE_EXTENSION_NAME) != devExts.end(); const bool float16int8 = std::find(devExts.begin(), devExts.end(), VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME) != devExts.end(); const bool bda = std::find(devExts.begin(), devExts.end(), VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) != devExts.end(); vk_version = 0x10; if(physProperties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) vk_version = 0x11; if(physProperties.apiVersion >= VK_MAKE_VERSION(1, 2, 0)) vk_version = 0x12; #define LIMIT_CHECK(limit, req) \ if(physProperties.limits.limit < req) \ Avail = fmt::format("Limit '" #limit "' {} is insufficient (need at least {})", \ physProperties.limits.limit, req); if(descIndexing) { LIMIT_CHECK(maxPerStageDescriptorSampledImages, 128); LIMIT_CHECK(maxPerStageDescriptorSamplers, 64); LIMIT_CHECK(maxPerStageDescriptorStorageBuffers, 16); LIMIT_CHECK(maxPerStageDescriptorStorageImages, 64); } VkFormatProperties props = {}; vkGetPhysicalDeviceFormatProperties(phys, VK_FORMAT_A2B10G10R10_UINT_PACK32, &props); if((props.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) == 0) { Avail = "VK_FORMAT_A2B10G10R10_UINT_PACK32 not supported in texel buffers"; return; } if((props.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) == 0) { Avail = "VK_FORMAT_A2B10G10R10_UINT_PACK32 not supported in texel buffers"; return; } vkGetPhysicalDeviceFormatProperties(phys, VK_FORMAT_A2B10G10R10_UNORM_PACK32, &props); if((props.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) == 0) { Avail = "VK_FORMAT_A2B10G10R10_UNORM_PACK32 not supported in texel buffers"; return; } if((props.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) == 0) { Avail = "VK_FORMAT_A2B10G10R10_UNORM_PACK32 not supported in texel buffers"; return; } // enable features we can optionally test with. VkPhysicalDeviceFeatures supported; vkGetPhysicalDeviceFeatures(phys, &supported); if(supported.shaderFloat64) features.shaderFloat64 = VK_TRUE; if(supported.shaderInt64) features.shaderInt64 = VK_TRUE; if(supported.shaderInt16) features.shaderInt16 = VK_TRUE; if(descIndexing) { static VkPhysicalDeviceDescriptorIndexingFeaturesEXT descIndexingFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT, }; getPhysFeatures2(&descIndexingFeatures); // enable descriptor indexing on arrays of all types if(!descIndexingFeatures.runtimeDescriptorArray) Avail = "Descriptor indexing feature 'runtimeDescriptorArray' not available"; else if(!descIndexingFeatures.shaderUniformTexelBufferArrayDynamicIndexing) Avail = "Descriptor indexing feature 'shaderUniformTexelBufferArrayDynamicIndexing' not " "available"; else if(!descIndexingFeatures.shaderStorageTexelBufferArrayDynamicIndexing) Avail = "Descriptor indexing feature 'shaderStorageTexelBufferArrayDynamicIndexing' not " "available"; else if(!descIndexingFeatures.shaderUniformBufferArrayNonUniformIndexing) Avail = "Descriptor indexing feature 'shaderUniformBufferArrayNonUniformIndexing' not " "available"; else if(!descIndexingFeatures.shaderSampledImageArrayNonUniformIndexing) Avail = "Descriptor indexing feature 'shaderSampledImageArrayNonUniformIndexing' not available"; else if(!descIndexingFeatures.shaderStorageBufferArrayNonUniformIndexing) Avail = "Descriptor indexing feature 'shaderStorageBufferArrayNonUniformIndexing' not " "available"; else if(!descIndexingFeatures.shaderStorageImageArrayNonUniformIndexing) Avail = "Descriptor indexing feature 'shaderStorageImageArrayNonUniformIndexing' not available"; else if(!descIndexingFeatures.shaderUniformTexelBufferArrayNonUniformIndexing) Avail = "Descriptor indexing feature 'shaderUniformTexelBufferArrayNonUniformIndexing' not " "available"; else if(!descIndexingFeatures.shaderStorageTexelBufferArrayNonUniformIndexing) Avail = "Descriptor indexing feature 'shaderStorageTexelBufferArrayNonUniformIndexing' not " "available"; devInfoNext = &descIndexingFeatures; } if(storage16) { // enable all available features getPhysFeatures2(&storage16Features); storage16Features.pNext = (void *)devInfoNext; devInfoNext = &storage16Features; } if(storage8) { // enable all available features getPhysFeatures2(&storage8Features); storage8Features.pNext = (void *)devInfoNext; devInfoNext = &storage8Features; } if(float16int8) { // enable all available features getPhysFeatures2(&float16Int8Features); float16Int8Features.pNext = (void *)devInfoNext; devInfoNext = &float16Int8Features; } if(bda) { getPhysFeatures2(&bdaFeatures); bdaFeatures.pNext = (void *)devInfoNext; devInfoNext = &bdaFeatures; } } int main() { // initialise, create window, create context, etc if(!Init()) return 3; make_asm_tests(); const bool descIndexing = std::find(devExts.begin(), devExts.end(), VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME) != devExts.end(); const bool storage16 = std::find(devExts.begin(), devExts.end(), VK_KHR_16BIT_STORAGE_EXTENSION_NAME) != devExts.end(); const bool storage8 = std::find(devExts.begin(), devExts.end(), VK_KHR_8BIT_STORAGE_EXTENSION_NAME) != devExts.end(); const bool float16int8 = std::find(devExts.begin(), devExts.end(), VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME) != devExts.end(); const bool bda = std::find(devExts.begin(), devExts.end(), VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) != devExts.end(); if(storage16) TEST_LOG("Running tests on 16-bit storage"); if(storage8) TEST_LOG("Running tests on 8-bit storage"); if(float16int8) TEST_LOG("Running tests on half and int8 arithmetic"); if(bda) TEST_LOG("Running tests on buffer device address"); if(features.shaderFloat64) TEST_LOG("Running tests on doubles"); if(features.shaderInt64) TEST_LOG("Running tests on int64"); if(features.shaderInt16) TEST_LOG("Running tests on int16 arithmetic"); pixel_glsl1.replace(pixel_glsl1.find("#define TEST_DESC_INDEXING"), sizeof("#define TEST_DESC_INDEXING"), fmt::format("#define TEST_DESC_INDEXING {}", descIndexing ? 1 : 0)); pixel_glsl2.replace(pixel_glsl2.find("#define TEST_DESC_INDEXING"), sizeof("#define TEST_DESC_INDEXING"), fmt::format("#define TEST_DESC_INDEXING {}", descIndexing ? 1 : 0)); size_t lastTest = pixel_glsl1.rfind("case "); lastTest += sizeof("case ") - 1; const uint32_t numGLSL1Tests = atoi(pixel_glsl1.c_str() + lastTest) + 1; lastTest = pixel_glsl2.rfind("case "); lastTest += sizeof("case ") - 1; const uint32_t numGLSL2Tests = atoi(pixel_glsl2.c_str() + lastTest) + 1; const uint32_t numASMTests = (uint32_t)asm_tests.size(); VkDescriptorSetLayout setlayout0 = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ {0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT}, {10, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {11, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {12, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {13, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {14, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {15, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {16, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {17, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {18, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {19, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {20, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {21, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {22, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {30, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {31, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {32, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {33, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {34, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {35, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {36, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, })); std::vector setLayouts = {setlayout0}; // this set layout has arrays of each type. We'll uniformly, dynamic-uniformly, and // non-uniformly access each of these VkDescriptorSetLayout setlayout1 = VK_NULL_HANDLE; VkDescriptorSetLayout setlayout2 = VK_NULL_HANDLE; if(descIndexing) { setlayout1 = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ {1, VK_DESCRIPTOR_TYPE_SAMPLER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {2, VK_DESCRIPTOR_TYPE_SAMPLER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {3, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {7, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {8, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {9, VK_DESCRIPTOR_TYPE_SAMPLER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {20, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, {21, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 14, VK_SHADER_STAGE_FRAGMENT_BIT}, })); setlayout2 = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {6, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {7, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {8, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {9, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {10, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {11, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {12, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {13, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {14, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {15, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {16, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {17, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {18, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {19, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {20, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {21, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {22, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {23, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {24, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {25, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {26, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {27, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {28, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {29, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {30, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {31, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {32, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {33, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {34, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {35, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {36, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {37, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {38, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {39, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {40, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {41, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {42, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {43, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {44, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {45, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {46, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {47, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {48, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {49, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {50, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {51, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {52, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {53, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {54, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {55, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {56, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {57, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {58, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, {59, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, })); setLayouts.push_back(setlayout1); setLayouts.push_back(setlayout2); } VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo( setLayouts, { vkh::PushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 16, sizeof(PushData)), })); // calculate number of tests, wrapping each row at 256 uint32_t texWidth = AlignUp(std::max(std::max(numGLSL1Tests, numGLSL2Tests), numASMTests), 256U); uint32_t texHeight = std::max(1U, texWidth / 256U); texWidth /= texHeight; // 4x4 for each test texWidth *= 4; texHeight *= 4; AllocatedImage img( this, vkh::ImageCreateInfo(texWidth, texHeight, 0, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView imgview = createImageView( vkh::ImageViewCreateInfo(img.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT)); vkh::RenderPassCreator renderPassCreateInfo; renderPassCreateInfo.attachments.push_back( vkh::AttachmentDescription(VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_CLEAR)); renderPassCreateInfo.addSubpass({VkAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL})}); VkRenderPass renderPass = createRenderPass(renderPassCreateInfo); VkFramebuffer framebuffer = createFramebuffer(vkh::FramebufferCreateInfo(renderPass, {imgview}, {texWidth, texHeight})); vkh::GraphicsPipelineCreateInfo pipeCreateInfo; pipeCreateInfo.layout = layout; pipeCreateInfo.renderPass = renderPass; pipeCreateInfo.vertexInputState.vertexBindingDescriptions = {vkh::vertexBind(0, ConstsA2V)}; pipeCreateInfo.vertexInputState.vertexAttributeDescriptions = { vkh::vertexAttr(0, 0, ConstsA2V, pos), vkh::vertexAttr(1, 0, ConstsA2V, zero), vkh::vertexAttr(2, 0, ConstsA2V, one), vkh::vertexAttr(3, 0, ConstsA2V, negone), vkh::vertexAttr(4, 0, ConstsA2V, uv), }; pipeCreateInfo.stages = { CompileShaderModule(vertex, ShaderLang::glsl, ShaderStage::vert, "main"), CompileShaderModule(pixel_glsl1, ShaderLang::glsl, ShaderStage::frag, "main"), }; VkPipeline glslpipe1 = createGraphicsPipeline(pipeCreateInfo); pipeCreateInfo.stages = { CompileShaderModule(vertex2, ShaderLang::glsl, ShaderStage::vert, "main"), CompileShaderModule(pixel_glsl2, ShaderLang::glsl, ShaderStage::frag, "main"), }; VkPipeline glslpipe2 = createGraphicsPipeline(pipeCreateInfo); SPIRVTarget target = SPIRVTarget::vulkan; if(vk_version >= 0x11) target = SPIRVTarget::vulkan11; if(vk_version >= 0x12) target = SPIRVTarget::vulkan12; pipeCreateInfo.stages = { CompileShaderModule(vertex, ShaderLang::glsl, ShaderStage::vert, "main"), CompileShaderModule(make_pixel_asm(), ShaderLang::spvasm, ShaderStage::frag, "main", {}, target), }; VkPipeline asmpipe = createGraphicsPipeline(pipeCreateInfo); float triWidth = 8.0f / float(texWidth); float triHeight = 8.0f / float(texHeight); ConstsA2V triangle[] = { {Vec4f(-1.0f, -1.0f, triWidth, triHeight), 0.0f, 1.0f, -1.0f, Vec2f(0.0f, 0.0f)}, {Vec4f(-1.0f + triWidth, -1.0f, triWidth, triHeight), 0.0f, 1.0f, -1.0f, Vec2f(1.0f, 0.0f)}, {Vec4f(-1.0f, -1.0f + triHeight, triWidth, triHeight), 0.0f, 1.0f, -1.0f, Vec2f(0.0f, 1.0f)}, }; AllocatedBuffer vb(this, vkh::BufferCreateInfo(sizeof(triangle), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); vb.upload(triangle); Texture rgba8; LoadXPM(SmileyTexture, rgba8); AllocatedImage queryTest(this, vkh::ImageCreateInfo(183, 347, 0, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT, 4, 3), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView queryTestView = createImageView(vkh::ImageViewCreateInfo( queryTest.image, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_FORMAT_R8G8B8A8_UNORM)); AllocatedImage queryTestMS( this, vkh::ImageCreateInfo(183, 347, 0, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT, 1, 5, VK_SAMPLE_COUNT_4_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView queryTestMSView = createImageView(vkh::ImageViewCreateInfo( queryTestMS.image, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_FORMAT_R8G8B8A8_UNORM)); AllocatedImage smiley( this, vkh::ImageCreateInfo(rgba8.width, rgba8.height, 0, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView smileyview = createImageView( vkh::ImageViewCreateInfo(smiley.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM)); AllocatedBuffer uploadBuf(this, vkh::BufferCreateInfo(rgba8.data.size() * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); AllocatedImage shadowimg(this, vkh::ImageCreateInfo(16, 16, 0, VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView shadowview = createImageView( vkh::ImageViewCreateInfo(shadowimg.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_D32_SFLOAT, {}, vkh::ImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT))); uploadBuf.upload(rgba8.data.data(), rgba8.data.size() * sizeof(uint32_t)); std::vector typeData; typeData.resize(sizeof(Vec4f) * 16 * 16 * 32 * 3); uint32_t typeOffset[] = { // float data sizeof(Vec4f) * 16 * 16 * 32 * 0, // uint data sizeof(Vec4f) * 16 * 16 * 32 * 1, // int data sizeof(Vec4f) * 16 * 16 * 32 * 2, }; for(size_t typeVariant = 0; typeVariant < 3; typeVariant++) { byte *dst = typeData.data() + typeOffset[typeVariant]; union { float f[4]; int i[4]; } rnd; memset(&rnd, 0, sizeof(rnd)); for(size_t x = 0; x < 16; x++) { for(size_t y = 0; y < 16; y++) { for(size_t z = 0; z < 32; z++) { if(typeVariant == 0) { rnd.f[0] = RANDF(-10.0f, 10.0f); rnd.f[1] = RANDF(-10.0f, 10.0f); rnd.f[2] = RANDF(-10.0f, 10.0f); rnd.f[3] = RANDF(-10.0f, 10.0f); } else if(typeVariant == 1) { rnd.i[0] = (int32_t)RANDF(100.0f, 500.0f); rnd.i[1] = (int32_t)RANDF(100.0f, 500.0f); rnd.i[2] = (int32_t)RANDF(100.0f, 500.0f); rnd.i[3] = (int32_t)RANDF(100.0f, 500.0f); } else if(typeVariant == 2) { rnd.i[0] = (int32_t)RANDF(-200.0f, 200.0f); rnd.i[1] = (int32_t)RANDF(-200.0f, 200.0f); rnd.i[2] = (int32_t)RANDF(-200.0f, 200.0f); rnd.i[3] = (int32_t)RANDF(-200.0f, 200.0f); } memcpy(dst, &rnd.f, sizeof(Vec4f)); } } } } AllocatedBuffer typeDataBuf( this, vkh::BufferCreateInfo(typeData.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); typeDataBuf.upload(typeData.data(), typeData.size()); AllocatedImage randomcube( this, vkh::ImageCreateInfo(rgba8.width, rgba8.height, 0, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 1, 6, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView randomcubeview = createImageView(vkh::ImageViewCreateInfo( randomcube.image, VK_IMAGE_VIEW_TYPE_CUBE, VK_FORMAT_R8G8B8A8_UNORM)); { VkCommandBuffer cmd = GetCommandBuffer(); vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); vkh::cmdPipelineBarrier( cmd, { vkh::ImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, smiley.image), vkh::ImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, randomcube.image), vkh::ImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, queryTest.image), vkh::ImageMemoryBarrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, queryTestMS.image), }); VkBufferImageCopy copy = {}; copy.imageExtent = {rgba8.width, rgba8.height, 1}; copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy.imageSubresource.layerCount = 1; vkCmdCopyBufferToImage(cmd, uploadBuf.buffer, smiley.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); for(uint32_t i = 0; i < 6; i++) { copy.imageSubresource.baseArrayLayer = i; vkCmdCopyBufferToImage(cmd, typeDataBuf.buffer, randomcube.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©); } vkh::cmdPipelineBarrier( cmd, { vkh::ImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, smiley.image), vkh::ImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, randomcube.image), }); vkEndCommandBuffer(cmd); Submit(99, 99, {cmd}); vkDeviceWaitIdle(device); } VkSampler pointsampler = createSampler(vkh::SamplerCreateInfo(VK_FILTER_NEAREST)); VkSampler linearsampler = createSampler(vkh::SamplerCreateInfo(VK_FILTER_LINEAR)); VkSampler mipsampler = createSampler(vkh::SamplerCreateInfo(VK_FILTER_LINEAR)); VkSampler shadowsampler = createSampler(vkh::SamplerCreateInfo( VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, 0.0f, VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, 0.0f, 0.0f, 0.0f, VK_COMPARE_OP_LESS_OR_EQUAL)); VkDescriptorSet descset0 = allocateDescriptorSet(setlayout0); VkDescriptorSet descset1 = VK_NULL_HANDLE; VkDescriptorSet descset2 = VK_NULL_HANDLE; if(descIndexing) { descset1 = allocateDescriptorSet(setlayout1); descset2 = allocateDescriptorSet(setlayout2); } Vec4f cbufferdata[64] = {}; AllocatedBuffer cb( this, vkh::BufferCreateInfo(sizeof(cbufferdata) * 2, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); cbufferdata[1] = Vec4f(1.1f, 2.2f, 3.3f, 4.4f); cbufferdata[2] = Vec4f(5.5f, 6.6f, 7.7f, 8.8f); cbufferdata[3] = Vec4f(std::numeric_limits::quiet_NaN()); cbufferdata[4] = Vec4f(9.9f, 9.99f, 9.999f, 9.999f); cbufferdata[6] = Vec4f(100.0f, 200.0f, 300.0f, 400.0f); // unorm2PackSource cbufferdata[7] = Vec4f(99.0f, 28099.0f / 65535.0f, 0.0f, 0.0f); // snorm2PackSource cbufferdata[8] = Vec4f(99.0f, -28099.0f / 32767.0f, 0.0f, 0.0f); // unorm4PackSource cbufferdata[9] = Vec4f(99.0f, 28.0f / 255.0f, 99.0f / 255.0f, 182.0f / 255.0f); // snorm4PackSource cbufferdata[10] = Vec4f(99.0f, -28.0f / 127.0f, 99.0f / 127.0f, -102.0f / 127.0f); // halfPackSource - we pick exact half values to avoid rounding problems cbufferdata[11] = Vec4f(98.125f, 76.375f, 54.5625f, 32.78125f); uint32_t index = 4; memcpy(&cbufferdata[1], &index, sizeof(index)); Vec4u unpack = {}; // unormUnpackSource unpack.x = 0xf0dd103c; // snormUnpackSource unpack.y = 0xf0dd103c; // halfUnpackSource unpack.z = (uint32_t(MakeHalf(81.5f)) << 16) | MakeHalf(101.03f); // unpack sources memcpy(&cbufferdata[12], &unpack, sizeof(unpack)); double unpackDouble = 3.1415926535; memcpy(&cbufferdata[13].x, &unpackDouble, sizeof(unpackDouble)); memcpy(&cbufferdata[14].z, &unpackDouble, sizeof(unpackDouble)); // move to account for offset memmove(&cbufferdata[16], &cbufferdata[0], sizeof(Vec4f) * 16); memset(&cbufferdata[0], 0, sizeof(Vec4f) * 16); cb.upload(cbufferdata); AllocatedBuffer texbuffer( this, vkh::BufferCreateInfo(sizeof(cbufferdata), VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); texbuffer.upload(cbufferdata); AllocatedBuffer store_buffer( this, vkh::BufferCreateInfo(1024 * sizeof(Vec4f), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); AllocatedBuffer atomic_buffer( this, vkh::BufferCreateInfo(texWidth * texHeight * sizeof(Vec4f), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); AllocatedBuffer store_texbuffer( this, vkh::BufferCreateInfo(1024 * sizeof(Vec4f), VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); AllocatedBuffer texbuffer_1010102unorm( this, vkh::BufferCreateInfo(1024 * sizeof(uint32_t), VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); AllocatedBuffer store_texbuffer_1010102unorm( this, vkh::BufferCreateInfo(1024 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); uint32_t unormdata[64] = {}; memset(unormdata, 0x42, sizeof(unormdata)); texbuffer_1010102unorm.upload(unormdata); AllocatedBuffer texbuffer_1010102uint( this, vkh::BufferCreateInfo(1024 * sizeof(uint32_t), VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); texbuffer_1010102uint.upload(unormdata); AllocatedBuffer store_texbuffer_1010102uint( this, vkh::BufferCreateInfo(1024 * sizeof(uint32_t), VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkBuffer bda_data_buffer = VK_NULL_HANDLE; VkDeviceMemory bda_deviceMem = VK_NULL_HANDLE; byte *bda_base_gpuptr = NULL; if(bda) { vkh::BufferCreateInfo bda_buffer_info(sizeof(BDA_Data), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR); VkMemoryAllocateInfo memAllocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO}; VkMemoryAllocateFlagsInfo memAllocFlags = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO}; memAllocFlags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; memAllocInfo.pNext = &memAllocFlags; const VkPhysicalDeviceMemoryProperties *memProps = NULL; vmaGetMemoryProperties(allocator, &memProps); vkCreateBuffer(device, bda_buffer_info, NULL, &bda_data_buffer); VkMemoryRequirements mrq; vkGetBufferMemoryRequirements(device, bda_data_buffer, &mrq); memAllocInfo.allocationSize = mrq.size; for(uint32_t i = 0; i < memProps->memoryTypeCount; i++) { if((mrq.memoryTypeBits & (1u << i)) && (memProps->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { memAllocInfo.memoryTypeIndex = i; break; } } vkAllocateMemory(device, &memAllocInfo, NULL, &bda_deviceMem); vkBindBufferMemory(device, bda_data_buffer, bda_deviceMem, 0); VkBufferDeviceAddressInfoKHR bda_info = {VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR}; bda_info.buffer = bda_data_buffer; VkDeviceAddress bda_Addr = vkGetBufferDeviceAddressKHR(device, &bda_info); bda_base_gpuptr = (byte *)bda_Addr; // not a valid cpu pointer byte *bda_base_cpuptr = NULL; vkMapMemory(device, bda_deviceMem, 0, mrq.size, 0, (void **)&bda_base_cpuptr); BDA_Data *bda_data_cpu = (BDA_Data *)bda_base_cpuptr; bda_data_cpu->f32[0] = 0.1f; bda_data_cpu->f32[1] = 0.2f; bda_data_cpu->f32[2] = 0.3f; bda_data_cpu->f32[3] = 0.8f; bda_data_cpu->f32[4] = 0.3f; bda_data_cpu->f32[5] = 0.2f; bda_data_cpu->f32[6] = 0.1f; bda_data_cpu->f32[7] = 0.9f; } AllocatedImage store_image( this, vkh::ImageCreateInfo(128, 128, 0, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView store_view = createImageView(vkh::ImageViewCreateInfo( store_image.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT)); AllocatedImage atomic_image( this, vkh::ImageCreateInfo(texWidth, texHeight, 0, VK_FORMAT_R32_UINT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView atomic_view = createImageView( vkh::ImageViewCreateInfo(atomic_image.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32_UINT)); VkBufferView bufview = createBufferView(vkh::BufferViewCreateInfo(texbuffer.buffer, VK_FORMAT_R32G32B32A32_SFLOAT)); VkBufferView store_bufview = createBufferView( vkh::BufferViewCreateInfo(store_texbuffer.buffer, VK_FORMAT_R32G32B32A32_SFLOAT)); VkBufferView bufview_1010102unorm = createBufferView(vkh::BufferViewCreateInfo( texbuffer_1010102unorm.buffer, VK_FORMAT_A2B10G10R10_UNORM_PACK32, 96)); VkBufferView store_bufview_1010102unorm = createBufferView(vkh::BufferViewCreateInfo( store_texbuffer_1010102unorm.buffer, VK_FORMAT_A2B10G10R10_UNORM_PACK32, 96)); VkBufferView bufview_1010102uint = createBufferView(vkh::BufferViewCreateInfo( texbuffer_1010102uint.buffer, VK_FORMAT_A2B10G10R10_UINT_PACK32, 96)); VkBufferView store_bufview_1010102uint = createBufferView(vkh::BufferViewCreateInfo( store_texbuffer_1010102uint.buffer, VK_FORMAT_A2B10G10R10_UINT_PACK32, 96)); setName(pointsampler, "pointsampler"); setName(linearsampler, "linearsampler"); setName(mipsampler, "mipsampler"); setName(queryTest.image, "queryTest"); setName(queryTestMS.image, "queryTestMS"); setName(smiley.image, "smiley"); setName(texbuffer.buffer, "texbuffer"); setName(store_buffer.buffer, "store_buffer"); setName(atomic_buffer.buffer, "atomic_buffer"); setName(store_texbuffer.buffer, "store_texbuffer"); setName(store_image.image, "store_image"); setName(atomic_image.image, "atomic_image"); setName(bufview_1010102unorm, "bufview_1010102unorm"); setName(store_bufview_1010102unorm, "store_texbuffer_1010102unorm"); setName(bufview_1010102uint, "bufview_1010102uint"); setName(store_bufview_1010102uint, "store_bufview_1010102uint"); AllocatedImage storezoo_u2D( this, vkh::ImageCreateInfo(16, 16, 0, VK_FORMAT_R32G32B32A32_UINT, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT), VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); VkImageView storezoo_u2D_view = createImageView(vkh::ImageViewCreateInfo( storezoo_u2D.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_UINT)); setName(storezoo_u2D.image, "storezoo_u2D"); vkh::updateDescriptorSets( device, { vkh::WriteDescriptorSet(descset0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, {vkh::DescriptorBufferInfo(cb.buffer, 0, sizeof(cbufferdata))}), vkh::WriteDescriptorSet(descset0, 10, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, {vkh::DescriptorBufferInfo(cb.buffer, 0, sizeof(cbufferdata))}), vkh::WriteDescriptorSet( descset0, 11, VK_DESCRIPTOR_TYPE_SAMPLER, {vkh::DescriptorImageInfo(VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, pointsampler)}), vkh::WriteDescriptorSet( descset0, 12, VK_DESCRIPTOR_TYPE_SAMPLER, {vkh::DescriptorImageInfo(VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, linearsampler)}), vkh::WriteDescriptorSet( descset0, 13, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, {vkh::DescriptorImageInfo(smileyview, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_NULL_HANDLE)}), vkh::WriteDescriptorSet( descset0, 14, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, {vkh::DescriptorImageInfo(smileyview, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, linearsampler)}), vkh::WriteDescriptorSet(descset0, 15, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, {vkh::DescriptorBufferInfo(store_buffer.buffer)}), vkh::WriteDescriptorSet( descset0, 16, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, {vkh::DescriptorImageInfo(store_view, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE)}), vkh::WriteDescriptorSet(descset0, 17, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, {bufview}), vkh::WriteDescriptorSet(descset0, 18, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, {store_bufview}), vkh::WriteDescriptorSet( descset0, 19, VK_DESCRIPTOR_TYPE_SAMPLER, {vkh::DescriptorImageInfo(VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, shadowsampler)}), vkh::WriteDescriptorSet( descset0, 20, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, {vkh::DescriptorImageInfo(randomcubeview, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, linearsampler)}), vkh::WriteDescriptorSet(descset0, 21, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, {vkh::DescriptorBufferInfo(atomic_buffer.buffer)}), vkh::WriteDescriptorSet( descset0, 22, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, {vkh::DescriptorImageInfo(atomic_view, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE)}), vkh::WriteDescriptorSet( descset0, 30, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, {vkh::DescriptorImageInfo(queryTestView, VK_IMAGE_LAYOUT_GENERAL, mipsampler)}), vkh::WriteDescriptorSet( descset0, 31, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, {vkh::DescriptorImageInfo(queryTestMSView, VK_IMAGE_LAYOUT_GENERAL, mipsampler)}), vkh::WriteDescriptorSet( descset0, 32, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, {vkh::DescriptorImageInfo(shadowview, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE)}), vkh::WriteDescriptorSet(descset0, 33, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, {bufview_1010102unorm}), vkh::WriteDescriptorSet(descset0, 34, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, {store_bufview_1010102unorm}), vkh::WriteDescriptorSet(descset0, 35, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, {bufview_1010102uint}), vkh::WriteDescriptorSet(descset0, 36, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, {store_bufview_1010102uint}), }); if(descIndexing) { vkh::updateDescriptorSets( device, { vkh::WriteDescriptorSet( descset2, 41, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, {vkh::DescriptorImageInfo(storezoo_u2D_view, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE)}), }); for(uint32_t i = 0; i < 14; i++) { vkh::updateDescriptorSets( device, { vkh::WriteDescriptorSet(descset1, 1, i, VK_DESCRIPTOR_TYPE_SAMPLER, {vkh::DescriptorImageInfo( VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, pointsampler)}), vkh::WriteDescriptorSet( descset1, 2, i, VK_DESCRIPTOR_TYPE_SAMPLER, {vkh::DescriptorImageInfo(VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, linearsampler)}), vkh::WriteDescriptorSet( descset1, 3, i, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, {vkh::DescriptorImageInfo(shadowview, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE)}), vkh::WriteDescriptorSet( descset1, 4, i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, {vkh::DescriptorImageInfo(smileyview, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, linearsampler)}), vkh::WriteDescriptorSet(descset1, 5, i, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, {vkh::DescriptorBufferInfo(store_buffer.buffer)}), vkh::WriteDescriptorSet( descset1, 6, i, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, {vkh::DescriptorImageInfo(store_view, VK_IMAGE_LAYOUT_GENERAL, VK_NULL_HANDLE)}), vkh::WriteDescriptorSet(descset1, 7, i, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, {bufview}), vkh::WriteDescriptorSet(descset1, 8, i, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, {store_bufview}), vkh::WriteDescriptorSet( descset1, 9, i, VK_DESCRIPTOR_TYPE_SAMPLER, {vkh::DescriptorImageInfo(VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, shadowsampler)}), vkh::WriteDescriptorSet( descset1, 20, i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, {vkh::DescriptorImageInfo(queryTestView, VK_IMAGE_LAYOUT_GENERAL, mipsampler)}), vkh::WriteDescriptorSet( descset1, 21, i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, {vkh::DescriptorImageInfo(queryTestMSView, VK_IMAGE_LAYOUT_GENERAL, mipsampler)}), }); } } while(Running()) { VkCommandBuffer cmd = GetCommandBuffer(); vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); VkImage swapimg = StartUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); vkCmdClearColorImage(cmd, swapimg, VK_IMAGE_LAYOUT_GENERAL, vkh::ClearColorValue(0.2f, 0.2f, 0.2f, 1.0f), 1, vkh::ImageSubresourceRange()); vkh::cmdPipelineBarrier( cmd, { vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, store_image.image), vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, atomic_image.image), vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, storezoo_u2D.image), vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, shadowimg.image, vkh::ImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT)), }, { vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, store_buffer.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, atomic_buffer.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, store_texbuffer.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, store_texbuffer_1010102uint.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, store_texbuffer_1010102unorm.buffer), }); vkCmdClearDepthStencilImage(cmd, shadowimg.image, VK_IMAGE_LAYOUT_GENERAL, vkh::ClearDepthStencilValue({0.5f, 0}), 1, vkh::ImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT)); vkCmdClearColorImage(cmd, store_image.image, VK_IMAGE_LAYOUT_GENERAL, vkh::ClearColorValue(6.66f, 6.66f, 6.66f, 6.66f), 1, vkh::ImageSubresourceRange()); vkCmdClearColorImage(cmd, atomic_image.image, VK_IMAGE_LAYOUT_GENERAL, vkh::ClearColorValue(0x42424242U, 0x42424242U, 0x42424242U, 0x42424242U), 1, vkh::ImageSubresourceRange()); vkCmdClearColorImage(cmd, storezoo_u2D.image, VK_IMAGE_LAYOUT_GENERAL, vkh::ClearColorValue(8U, 18U, 28U, 38U), 1, vkh::ImageSubresourceRange()); vkCmdFillBuffer(cmd, store_buffer.buffer, 0, VK_WHOLE_SIZE, 0x42424242); vkCmdFillBuffer(cmd, atomic_buffer.buffer, 0, VK_WHOLE_SIZE, 0x42424242); const float val = 1.234f; vkCmdFillBuffer(cmd, store_texbuffer.buffer, 0, 128, *(uint32_t *)&val); vkCmdFillBuffer(cmd, store_texbuffer.buffer, 128, VK_WHOLE_SIZE, 0); vkCmdFillBuffer(cmd, store_texbuffer_1010102uint.buffer, 0, 104, 0x42424242); vkCmdFillBuffer(cmd, store_texbuffer_1010102uint.buffer, 104, VK_WHOLE_SIZE, 0); vkCmdFillBuffer(cmd, store_texbuffer_1010102unorm.buffer, 0, 104, 0x42424242); vkCmdFillBuffer(cmd, store_texbuffer_1010102unorm.buffer, 104, VK_WHOLE_SIZE, 0); vkh::cmdPipelineBarrier( cmd, { vkh::ImageMemoryBarrier( VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, store_image.image), vkh::ImageMemoryBarrier( VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, atomic_image.image), vkh::ImageMemoryBarrier( VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, storezoo_u2D.image), }, { vkh::BufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, store_buffer.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, atomic_buffer.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, store_texbuffer.buffer), }); VkViewport v = {}; v.maxDepth = 1.0f; v.width = (float)texWidth; v.height = (float)texHeight; VkRect2D s = {}; s.extent.width = texWidth; s.extent.height = texHeight; vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, glslpipe1); vkCmdSetViewport(cmd, 0, 1, &v); vkCmdSetScissor(cmd, 0, 1, &s); vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0}); BDA_Data *bda_gpuptr = (BDA_Data *)bda_base_gpuptr; PushData pushData; pushData.push = Vec4i(101, 103, 107, 109); pushData.bda_uvec2 = *(Vec2u *)(&bda_gpuptr); pushData.bda_hi = (uint64_t)bda_gpuptr >> 32; pushData.bda_lo = (uint64_t)bda_gpuptr & 0xFFFFFFFF; pushData.bda_u64 = *(uint64_t *)(&bda_gpuptr); std::vector descSets = {descset0}; if(descIndexing) { descSets.push_back(descset1); descSets.push_back(descset2); } vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descSets, {0, sizeof(Vec4f) * 16}); vkCmdPushConstants(cmd, layout, VK_SHADER_STAGE_FRAGMENT_BIT, 16, sizeof(PushData), &pushData); vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s, {vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}), VK_SUBPASS_CONTENTS_INLINE); pushMarker(cmd, "GLSL1 tests"); uint32_t numTests = numGLSL1Tests; uint32_t offset = 0; // loop drawing 256 tests at a time while(numTests > 0) { uint32_t num = std::min(numTests, 256U); vkCmdDraw(cmd, 3, num, 0, offset); offset += num; numTests -= num; } popMarker(cmd); vkCmdEndRenderPass(cmd); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, asmpipe); vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s, {vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}), VK_SUBPASS_CONTENTS_INLINE); pushMarker(cmd, "ASM tests"); numTests = numASMTests; offset = 0; // loop drawing 256 tests at a time while(numTests > 0) { uint32_t num = std::min(numTests, 256U); vkCmdDraw(cmd, 3, num, 0, offset); offset += num; numTests -= num; } popMarker(cmd); vkCmdEndRenderPass(cmd); // sync all the storage work vkh::cmdPipelineBarrier( cmd, { vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, store_image.image), vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, atomic_image.image), vkh::ImageMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, storezoo_u2D.image), }, { vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, store_buffer.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, atomic_buffer.buffer), vkh::BufferMemoryBarrier(VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, store_texbuffer.buffer), }); vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, glslpipe2); vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, s, {vkh::ClearValue(0.0f, 0.0f, 0.0f, 0.0f)}), VK_SUBPASS_CONTENTS_INLINE); pushMarker(cmd, "GLSL2 tests"); numTests = numGLSL2Tests; offset = 0; // loop drawing 256 tests at a time while(numTests > 0) { uint32_t num = std::min(numTests, 256U); vkCmdDraw(cmd, 3, num, 0, offset); offset += num; numTests -= num; } popMarker(cmd); vkCmdEndRenderPass(cmd); FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); vkEndCommandBuffer(cmd); Submit(0, 1, {cmd}); Present(); } CHECK_VKR(vkDeviceWaitIdle(device)); if(bda) { vkDestroyBuffer(device, bda_data_buffer, NULL); vkUnmapMemory(device, bda_deviceMem); vkFreeMemory(device, bda_deviceMem, NULL); } return 0; } }; REGISTER_TEST();