#!amber # Copyright 2020 Google LLC. # Copyright 2020 The Khronos Group Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. SHADER vertex vert_shader PASSTHROUGH SHADER fragment frag_shader GLSL #version 430 layout(location = 0) out vec4 color; void main() { color = vec4(1); } END SHADER fragment frag_shader_tex GLSL #version 430 layout(location = 0) out vec4 color_out; uniform layout(set=0, binding=0, rgba8) readonly image2D texture; void main() { color_out = imageLoad(texture, ivec2(gl_FragCoord.xy)); } END SHADER compute compute_shader GLSL #version 430 layout(local_size_x=32, local_size_y=4) in; uniform layout (set=0, binding=0, rgba8) image2D img; int w = 256; int h = 256; vec4 bg = vec4(0, 0, 0, 1); vec4 marked = vec4(0, 1, 1, 1); vec4 error = vec4(1, 0, 0, 1); shared ivec2 stack[256]; shared int stackPtr; shared bool done; shared ivec2 pixel; void pushMarkedPixel(ivec2 p) { imageStore(img, p, marked); int slot = atomicAdd(stackPtr, 1); stack[slot] = p; } ivec2 popMarkedPixel() { int slot = atomicAdd(stackPtr, -1) - 1; ivec2 p = stack[slot]; imageStore(img, p, bg); return p; } void main () { if (gl_LocalInvocationIndex == 0) { stack[0] = ivec2(-1); stackPtr = 0; done = false; // Use this to break the lines and verify the checker is correct. //for (int x = 0; x < w; x++) // imageStore(img, ivec2(x, 128), bg); } barrier(); // Search for any pixel belonging to a line. // Use 32 x 4 block for the search. ivec2 p = ivec2(gl_LocalInvocationID) + ivec2(0, 128); vec4 c = imageLoad(img, p); // Any of the pixels found by a thread will do as a starting point. if (c != bg) stack[0] = p; barrier(); if (gl_LocalInvocationIndex == 0 && stack[0] != ivec2(-1)) { imageStore(img, stack[0], marked); stackPtr++; } barrier(); while (!done) { if (gl_LocalInvocationIndex == 0 && stackPtr != 0) pixel = popMarkedPixel(); barrier(); if (gl_LocalInvocationID.x < 3 && gl_LocalInvocationID.y < 3) { ivec2 p = pixel + ivec2(gl_LocalInvocationID) - ivec2(1); if (p.x >= 0 && p.y >= 0 && p.x < w && p.y < h) { vec4 c = imageLoad(img, p); if (c != marked && c != bg) { pushMarkedPixel(p); } } } barrier(); if (gl_LocalInvocationIndex == 0 && stackPtr < 1) done = true; barrier(); } } END BUFFER position DATA_TYPE R8G8_SNORM DATA -120 -120 -119 120 120 119 10 20 -80 20 -80 95 -83 95 -83 -95 -85 95 END BUFFER texture FORMAT R8G8B8A8_UNORM BUFFER framebuffer FORMAT B8G8R8A8_UNORM PIPELINE graphics pipeline ATTACH vert_shader ATTACH frag_shader VERTEX_DATA position LOCATION 0 BIND BUFFER texture AS color LOCATION 0 FRAMEBUFFER_SIZE 256 256 END PIPELINE graphics tex_pipeline ATTACH vert_shader ATTACH frag_shader_tex BIND BUFFER texture AS storage_image DESCRIPTOR_SET 0 BINDING 0 FRAMEBUFFER_SIZE 256 256 BIND BUFFER framebuffer AS color LOCATION 0 END PIPELINE compute verification_pipeline ATTACH compute_shader BIND BUFFER texture AS storage_image DESCRIPTOR_SET 0 BINDING 0 FRAMEBUFFER_SIZE 256 256 END CLEAR_COLOR pipeline 0 0 0 255 CLEAR pipeline RUN pipeline DRAW_ARRAY AS LINE_STRIP START_IDX 0 COUNT 9 RUN verification_pipeline 1 1 1 RUN tex_pipeline DRAW_RECT POS 0 0 SIZE 256 256 # Everything should be clear color since the checker consumes # the drawn pixels if they are continuous. EXPECT framebuffer IDX 0 0 SIZE 256 255 EQ_RGBA 0 0 0 255