1

Let's pretend I'm making a compute shader using WebGL and GLSL.

In this shader, each fragment (or pixel) would like to look at every pixel on a texture, then decide on it's own color.

Normally a fragment samples it's provided texture coordinate (UV value) from a few textures, but I want to sample effectively all UV values from a single texture for a single fragment.

Is this possible?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Adrian Seeley
  • 2,262
  • 2
  • 29
  • 37

2 Answers2

3

EDIT: I was able to sample from each pixel in a 128x128 texture, but moving to 256x256 causes Chrome to fail. Meaning each pixel can sample roughly 16384 different pixels from the same texture in one draw call. Very useful for machine learning!

Note: There may be an unsquare power of 2 texture to support a higher pixel sample count under 256x256 (65536 pixels), but I only use square textures so this wasn't tested.

GIST OF SOURCE CODE

void main() {
    vec4 tcol = vec4(0, 0, 0, 0);
    for (float x = 0.0; x < PIXELS_WIDE; x++) 
        for (float y = 0.0; y < PIXELS_TALL; y++) 
            tcol += texture2D(tex0, vec2(x / PIXELS_WIDE, y / PIXELS_TALL));
    tcol /= 100.;
    gl_FragColor = tcol;
}

In Chrome I was able to execute the following loops:

100 Passes (Works):

void main() {
    float reg = 0.0;
    for (int i = 0; i < 100; i++) {
        reg += 1.0 / 255.0;
    }
    gl_FragColor = vec4(reg, 0, 0, 1);
}

1 000 Passes (Works):

void main() {
    float reg = 0.0;
    for (int i = 0; i < 1000; i++) {
        reg += 0.1 / 255.0;
    }
    gl_FragColor = vec4(reg, 0, 0, 1);
}

10 000 Passes (Works):

void main() {
    float reg = 0.0;
    for (int i = 0; i < 10000; i++) {
        reg += 0.01 / 255.0;
    }
    gl_FragColor = vec4(reg, 0, 0, 1);
}

100 000 Passes (Shits the bed):

void main() {
    float reg = 0.0;
    for (int i = 0; i < 100000; i++) {
        reg += 0.001 / 255.0;
    }
    gl_FragColor = vec4(reg, 0, 0, 1);
}
GL_INVALID_ENUM : glBindFramebuffer: target was GL_READ_FRAMEBUFFER_ANGLE 
GL_INVALID_ENUM : glBindFramebuffer: target was GL_DRAW_FRAMEBUFFER_ANGLE 
WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost
Adrian Seeley
  • 2,262
  • 2
  • 29
  • 37
  • I find myself saying this a lot, but depending on what you are trying to do, mipmaps might help. They effectively turn textures into a tree-like data structure, you can gather information about larger blocks of texels by fetching from a higher LOD (higher -> lower resoltion in GL). For some things in machine learning, you might not actually need to know each and every value, you can effectively cluster data into the hierarchy of mipmap LODs. There are more effective approaches in modern GL, but for WebGL mipmaps are a pretty nifty universally supported data structure. – Andon M. Coleman May 04 '14 at 19:31
  • 100000 passes is basically DOSing your GPU. The OS and/or the Browser will kill WebGL because GPUs are not preempt-able. If you want to do that much work you need to split it up. Also your texcoord calculation is wrong. It should be `vec2((x + 0.5) / PIXELS_WIDE, (y + 0.5) / PIXELS_TALL)`. Without the +0.5 you're calculating the exact spot between pixels. Depending on the GPU and other things you'll get one pixel or the other. See: https://stackoverflow.com/a/27439675/128511 – gman Aug 25 '19 at 18:44
  • Also, on your 100000 passes. One speed up is to break up the problem into chunks. A modern GPU has over 2000 cores so it can do 2000 things in parallel but you have to give it parallel things to do. Drawing a single pixel is one thing to do. Drawing 2000 pixels is 2000 things to do. So for example computing 1000 sums of 1000 pixels each and then sum the resulting 1000 results will give the GPU a chance to parallelize 1000x where as computing one pixel that is the sum of 1000000 pixels will not parallelize anything. – gman Aug 25 '19 at 18:48
1

Is this possible?

It certainly is, however since each texture access requires a number of GPU instruction cycles you'll likely run into a hard limit on how many cycles a fragment shader may spend on each fragment, before it gets aborted.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • Legit, I had a strong feeling it would be the too many instructions error (or some similar error on unrolling a for loop of that size). Is there anyway at present to override the limit? – Adrian Seeley May 04 '14 at 11:59