WebGL: Are there cases where gl.MAX_TEXTURE_IMAGE_UNITS == 1 - webgl

Sorry to ask such a strange question, but I'm working on some logic for a WebGL visualization and would like to know, are there cases where:
gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)
equals 1?
I ask because I'm trying to figure out how many vertices I can draw in each draw call, and each vertex needs some content from one of several textures. The minimal case I'm wanting to support is one in which I load two textures for each draw call, but if there are cards that don't support multiple textures per draw call I'll need to rethink my life.

The minimum value for MAX_TEXTURE_IMAGE_UNITS WebGL is required to support is 8. You can look up the limits in the spec section 6.2. Note: Search for "MAX TEXTURE IMAGE UNITS" (with the spaces not underscores)
That said WebGL has a different limit for textures used in a fragment shader vs textures used in a vertex shader.
For a vertex shader the minimum requires is 0 on WebGL1. You can check the number of textures supported in a vertex shader by looking at MAX_VERTEX_TEXTURE_IMAGE_UNITS.
Fortunately most machines support at least 4 in the vertex shader
There is also yet another limit MAX_COMBINED_TEXTURE_IMAGE_UNITS which is how many textures total you can use combined. In other words if MAX_COMBINED_TEXTURE_IMAGE_UNITS is 8, MAX_VERTEX_TEXTURE_IMAGE_UNITS is 8 and MAX_VERTEX_TEXTURE_IMAGE_UNITS is 4 that means you could use 8 textures at once of which up to 4 could be used in the vertex shader. You could not use 12 textures at once.
Other minimums
MAX VERTEX ATTRIBS 8
MAX VERTEX UNIFORM VECTORS 128
MAX VARYING VECTORS 8
MAX COMBINED TEXTURE IMAGE UNITS 8
MAX VERTEX TEXTURE IMAGE UNITS 0
MAX TEXTURE IMAGE UNITS 8
MAX FRAGMENT UNIFORM VECTORS 16

Related

What can vertex function do except for mapping to clip space?

The Metal Shading Language includes a lot of mathematic functions, but it seems most of the codes inside Metal official documentation just use it to map vertexes from pixel space to clip space like
RasterizerData out;
out.clipSpacePosition = vector_float4(0.0, 0.0, 0.0, 1.0);
float2 pixelSpacePosition = vertices[vertexID].position.xy;
vector_float2 viewportSize = vector_float2(*viewportSizePointer);
out.clipSpacePosition.xy = pixelSpacePosition / (viewportSize / 2.0);
out.color = vertices[vertexID].color;
return out;
Except for GPGPU using kernel functions to do parallel computation, what things that vertex function can do, with some examples? In a game, if all vertices positions are calculated by the CPU, why GPU still matters? What does vertex function do usually?
Vertex shaders compute properties for vertices. That's their point. In addition to vertex positions, they also calculate lighting normals at each vertex. And potentially texture coordinates. And various material properties used by lighting and shading routines. Then, in the fragment processing stage, those values are interpolated and sent to the fragment shader for each fragment.
In general, you don't modify vertices on the CPU. In a game, you'd usually load them from a file into main memory, put them into a buffer and send them to the GPU. Once they're on the GPU you pass them to the vertex shader on each frame along with model, view, and projection matrices. A single buffer containing the vertices of, say, a tree or a car's wheel might be used multiple times. Each time all the CPU sends is the model, view, and projection matrices. The model matrix is used in the vertex shader to reposition and scale the vertice's positions in world space. The view matrix then moves and rotates the world around so that the virtual camera is at the origin and facing the appropriate way. Then the projection matrix modifies the vertices to put them into clip space.
There are other things a vertex shader can do, too. You can pass in vertices that are in a grid in the x-y plane, for example. Then in your vertex shader you can sample a texture and use that to generate the z-value. This gives you a way to change the geometry using a height map.
On older hardware (and some lower-end mobile hardware) it was expensive to do calculations on a texture coordinate before using it to sample from a texture because you lose some cache coherency. For example, if you wanted to sample several pixels in a column, you might loop over them adding an offset to the current texture coordinate and then sampling with the result. One trick was to do the calculation on the texture coordinates in the vertex shader and have them automatically interpolated before being sent to the fragment shader, then doing a normal look-up in the fragment shader. (I don't think this is an optimization on modern hardware, but it was a big win on some older models.)
First, I'll address this statement
In a game, if all vertices positions are calculated by the CPU, why GPU still matters? What does vertex function do usually?
I don't believe I've seen anyone calculating positions for meshes that will be later used to render them on a GPU. It's slow, you would need to get all this data from CPU to a GPU (which means copying it through a bus if you have a dedicated GPU). And it's just not that flexible. There are much more things other than vertex positions that are required to produce any meaningful image and calculating all this stuff on CPU is just wasteful, since CPU doesn't care for this data for the most part.
The sole purpose of vertex shader is to provide rasterizer with primitives that are in clip space. But there are some other uses that are mostly tricks based on different GPU features.
For example, vertex shaders can write out some data to buffers, so, for example, you can stream out transformed geometry if you don't want to transform it again at a later vertex stage if you have multi-pass rendering that uses the same geometry in more than one pass.
You can also use vertex shaders to output just one triangle that covers the whole screen, so that fragment shaders gets called one time per pixel for the whole screen (but, honestly, you are better of using compute (kernel) shaders for this).
You can also write out data from vertex shader and not generate any primitives. You can do that by generating degenerate triangles. You can use this to generate bounding boxes. Using atomic operations you can update min/max positions and read them at a later stage. This is useful for light culling, frustum culling, tile-based processing and many other things.
But, and it's a BIG BUT, you can do most of this stuff in a compute shader without incurring GPU to run all the vertex assembly pipeline. That means, you can do full-screen effects using just a compute shader (instead of vertex and fragment shader and many pipeline stages in between, such as rasterizer, primitive culling, depth testing and output merging). You can calculate bounding boxes and do light culling or frustum culling in compute shader.
There are reasons to fire up the whole rendering pipeline instead of just running a compute shader, for example, if you will still use triangles that are output from vertex shader, or if you aren't sure how primitives are laid out in memory so you need vertex assembler to do the heavy lifting of assembling primitives. But, getting back to your point, almost all of the reasonable uses for vertex shader include outputting primitives in clip space. If you aren't using resulting primitives, it's probably best to stick to compute shaders.

Writing Textures using Kernel

In single pass (In a single draw cycle) to the shader How many maximum Textures we can draw at once in metal using Kernel ? I have tried to draw six squared textures in a draw cycle.When the textures points overlap actual texture is not presented as expected. Some glitches are available

What is the max size for an array to be uploaded using gl.uniform1fv?

Is there any limit on the above call? Is that limit different for WebGL 1.0 vs WebGL 2.0?
If there is no limit, would there be a reason to use that vs Textures for input data?
thanks
For vertex shaders the maximum size is specified by the gl.MAX_VERTEX_UNIFORM_VECTORS parameter.
Minimum for WebGL 1 is 128.
Minimum for WebGL 2 is 256.
gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);
For fragment shaders the maximum size is specified by the gl.MAX_FRAGMENT_UNIFORM_VECTORS parameter.
Minimum for WebGL 1 is 16.
Minimum for WebGL 2 is 224.
gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
You can quickly check these limits in your browser on the Webgl Report site.
Note: Other uniform variables decrease that limits and for example a mat4 uniform in a shader counts as 4 uniforms.

How does WebGL set values in the depth buffer?

In OpenGL, depth buffer values are calculated based on the near and far clipping planes of the scene. (Reference: Getting the true z value from the depth buffer)
How does this work in WebGL? My understanding is that WebGL is unaware of my scene's far and near clipping planes. The near and far clipping planes are used to calculate my projection matrix, but I never tell WebGL what they are explicitly so it can't use them to calculate depth buffer values.
How does WebGL set values in the depth buffer when my scene is rendered?
WebGL (like modern OpenGL and OpenGL ES) gets the depth value from the value you supply to gl_Position.z in your vertex shader (though you can also write directly to the depth buffer using certain extensions but that's far less common)
There is no scene in WebGL nor modern OpenGL. That concept of a scene is part of legacy OpenGL left over from the early 90s and long since deprecated. It doesn't exist in OpenGL ES (the OpenGL that runs on Android, iOS, ChromeOS, Raspberry PI, WebGL etc...)
Modern OpenGL and WebGL are just rasterization APIs. You write shaders which are small functions that run on the GPU. You provide those shaders with data through attributes (per iteration data), uniforms (global variables), textures (2d/3d arrays), varyings (data passed from vertex shaders to fragment shaders).
The rest is up to you and what your supplied shader functions do. Modern OpenGL and WebGL are for all intents and purposes just generic computing engines with certain limits. To get them to do anything is up to you to supply shaders.
See webglfundamentals.org for more.
In the Q&A you linked to it's the programmer supplied shaders that decide to use frustum math to decide how to set gl_Position.z. The frustum math is supplied by the programmer. WebGL/GL don't care how gl_Position.z is computed, only that it's a value between -1.0 and +1.0 so how to take a value from the depth buffer and go back to Z is solely up to how the programmer decided to calculate it in the first place.
This article covers the most commonly used math for setting gl_Position.z when rendering 3d with WebGL/OpenGL. Based on your question though I'd suggest reading the preceding articles linked at the beginning of that one.
As for what actual values get written to the depth buffer it's
ndcZ = gl_Position.z / gl_Position.w;
depthValue = (far - near) / 2 * ndcZ + (near - far) / 2
near and far default to 0 and 1 respectively though you can set them with gl.depthRange but assuming they are 0 and 1 then
ndcZ = gl_Position.z / gl_Position.w;
depthValue = .5 * ndcZ - .5
That depthValue would then be in the 0 to 1 range and converted to whatever bit depth the depth buffer is. It's common to have a 24bit depth buffer so
bitValue = depthValue * (2^24 - 1)

Is DirectX 11 compute capable of writing more than 10k vertices to a RWStructuredBuffer?

I have a vertex buffer with an unordered access view, which I'm using to fill the vertices using a compute shader, which treats the UAV as a RWStructuredBuffer, using an equivalent struct to the vertex definition. There are 216000 vertices (i.e. 60 x 60 x 60). But my compute shader seems to fill only about 8000 of them, leaving the rest with their initial values. Is there a limit on the number of elements in a structured buffer that can be written in this way?
As it turns out, if you turn on DirectX error-checking, assigning the UAV of a vertex buffer as a RWStructuredBuffer in the shader is considered to be an error. So although this actually works (for a limited number of vertices), it's not supported.

Resources