I have an application that uses OpenGL to draw output images. For testing purposes I'm trying to create reference images and then use precision hash to compare them to program output. While it works flawlessly within a context of a single computer I've encountered strange problems when using the same approach with computers running different GPUs. While the images generated on different GPUs appear absolutely identical to human eye they cannot pass prescision hash test when compared to one another and per-pixel comparison reveals that there are several pixels that are "off". I've been trying to find problems in my code for several days to no avail and this behaviour manifests itself on all the shaders that I use. Could this possibly be due to differences in OpenGL implementation from different hardware manufacturers? Is it a valid approach to compare images generated on different GPUs with phash for testing purposes?
Could this possibly be due to differences in OpenGL implementation
from different hardware manufacturers? Is it a valid approach to
compare images generated on different GPUs with phash for testing
purposes?
No, it is not. Quoting the OpenGL 4.6 core profile specification, Appendix A "Invariance" (emphaisis mine):
The OpenGL specification is not pixel exact. It therefore does not
guarantee an exact match between images produced by different GL
implementations. However, the specification does specify exact
matches, in some cases, for images produced by the same
implementation. The purpose of this appendix is to identify and
provide justification for those cases that require exact matches.
The guarantees for exact matches are made only within the same implementation, under very strict limits, and these are usueful for example for multi-pass approaches where you need to get exactly the same fragments in different passes.
Note that the other 3D rendering API are not pixel-exact either. The actual hardware implementations do vary between individual GPUs, and the specifications typically only specify broader rules that every implementation must fulfill, and you can rely on.
Related
I have found a few times differences between GPUs handling fragment shaders. One example was doing pow(x) where x is negative. One GPU handled it well while the other one failed.
Another situation was where I rewrote if() statements with step() statement and shader worked well. I blamed this to branching limit or something.
Now I am in situation where my fragment shader works on some GPUs and on some don't. I have tried to search for GPU/shader limits and similar information but found nothing.
The very current test which works everywhere I tried except on my GTX 780 is here online(Shadertoy)
I am asking for any directions or a link to shader limitations and most common issues in compatibility.
Shader limitations and specification, are vendor-specific, and are changing along with the GPU architecture versions.
Simply put, there's no unified way to "rule them all". Certain GPUs handle branching differently, some better, some worse. Some GPUs allow negative values in math functions, some don't. It quite depends on the architecture that's been used, version of the shading language and instructions that are allowed in the compiled version of the shader.
Instead of reading and trying to learn what works on which card, it's best to try/test shader on the specific GPU. That's probably the most reasonable decision regarding the resources spent trying to "fix the issue".
To answer the question directly, there's no (easy-to-find) resource which lists entire specification of the compiler used on the specific architecture, you simply follow tips'n'trick learned along the way and apply suggestions and observations made by others.
This may be a weird question, but I need to know if the way OpenGL aliases the edges of drawn geometry (polygons, lines, etc) is "consistant", meaning it looks the same across different platforms/hardware.
Aliasing in this case is the sharp edges that "anti-aliasing" aims to remove. I want aliasing however, and would like to use it for animation techniques that need the aliasing effect to be pixel perfect (it's for sprite-type effects). Is this feasible, or is it impossible to predict how it'll alias across different computers?
No it is not. To quote the spec (any version, Appendix A: Invariance):
The OpenGL specification is not pixel exact. It therefore does not guarantee an exact match between images produced by different GL implementations. However, the specification does specify exact matches, in some cases, for images produced by the same implementation.
So there might variation. Also consider that some graphics drivers allow the user to force antialiasing, overriding the application's settings.
The specification for the OpenGL method glTexImage2D() gives a large table of accepted internalFormat parameters. I'm wondering though, if it really matters what I set this parameter as, since the doc says
If an application wants to store the texture at a certain
resolution or in a certain format, it can request the resolution
and format with internalFormat. The GL will choose an internal
representation that closely approximates that requested by internalFormat, but
it may not match exactly.
which makes it seem as though OpenGL is just going to pick what it wants anyways. Should I bother getting an images bit depth and setting the internalFormat to something like GL_RGBA8 or GL_RGBA16? All the code examples I've seen just use GL_RGBA...
which makes it seem as though OpenGL is just going to pick what it wants anyways.
This is very misleading.
There are a number of formats that implementations are required to support more or less exactly as described. Implementations are indeed permitted to store them in larger storage. But they're not permitted to lose precision compared to them. And there are advantages to using them (besides the obvious knowledge of exactly what you're getting).
First, it allows you to use specialized formats like GL_RGB10_A2, which is handy in certain situations (storing linear color values for deferred rendering, etc). Second, FBOs are required to support any combination of image formats, but only if all of those image formats come from the list of required color formats for textures/renderbuffers (but not the texture-only). If you're using any other internal formats, FBOs can throw GL_FRAMEBUFFER_UNSUPPORTED at you.
Third, immutable texture storage functions require the use of sized internal formats. And you should use those whenever they're available.
In general, you should always use sized internal formats. There's no reason to use the generic ones.
Using a generic internal format OpenGL will choose whatever it "likes" best, and tell it that you don't care. With an explicit internal format, you're telling OpenGL, that you actually care about the internal representation (most likely because you need the precision). While an implementation is free to up- or downgrade if an exact match can not be made, the usual fallback is to upgrade to the next higher format precision that can satisfy the requested demands.
Should I bother getting an images bit depth and setting the internalFormat
If you absolutely require the precision, then yes. If your concerns are more about performance, then no, as the usual default of the OpenGL implementations being around, is to choose the internal format for best performance if no specific format has been requested.
for an application I'm developing I need to be able to
draw lines of different widths and colours
draw solid color filled triangles
draw textured (no alpha) quads
Very easy...but...
All coordinates are integer in pixel space and, very important: glReading all the pixels from the framebuffer
on two different machines, with two different graphic cards, running two different OS (Linux and freebsd),
must result in exactly the same sequence of bits (given an appropriate constant format conversion).
I think this is impossible to safely be achieved using opengl and hardware acceleration, since I bet different graphic
cards (from different vendors) may implement different algorithms for rasterization.
(OpenGl specs are clear about this, since they propose an algorithm but they also state that implementations may differ
under certain circumstances).
Also I don't really need hardware acceleration since I will be rendering very low speed and simple graphics.
Do you think I can achieve this by just disabling hardware acceleration? What happens in that case under linux, will I default on
MESA software rasterizer? And in that case, can I be sure it will always work or I am missing something?
That you're reading back in rendered pixels and strongly depend on their mathematical exactness/reproducability sounds like a design flaw. What's the purpose of this action? If you, for example, need to extract some information from the image, why don't you try to extract this information from the abstract, vectorized information prior to rendering?
Anyhow, if you depend on external rendering code and there's no way to make your reading code more robust to small errors, you're signing up for lots of pain and maintenance work. Other people could break your code with every tiny patch, because that kind of pixel exactness to the bit-level is usually a non-issue when they're doing their unit tests etc. Let alone the infinite permutations of hard- and software layers that are possible, and all might have influence on the exact pixel bits.
If you only need those two operatios: lines (with different widths and colors) and quads (with/without texture), I recommend writing your own rendering/rasterizer code which operates on a 8 bit uint array representing the image pixels (R8G8B8). The operations you're proposing aren't too nasty, so if performance is unimportant, this might actually be the better way to go on the long run.
I'm currently programming a scientific imaging application using OpenGL.
I would like to know if OpenGL rendering (in term of retrieved pixel from FBO) is supposed to be fully deterministic when my code (C++ / OpenGL and simple GLSL) is executed on different hardware (ATI vs NVidia, various NVidia generations and various OS)?
More precisely, I'd need the exact same pixels buffer everytime I run my code on any hardware (that can runs basic GLSL and OpenGL 3.0)...
Is that possible? Is there some advice I should consider?
If it's not possible, is there a specific brand of video card (perhaps Quadro?) that could do it while varying the host OS?
From the OpenGL spec (version 2.1 appendix A):
The OpenGL specification is not pixel exact. It therefore does not guarantee an exact match between images produced by different GL implementations. However, the specification does specify exact matches, in some cases, for images produced by the same implementation.
If you disable all anti-aliasing and texturing, you stand a good chance of getting consistent results across platforms. However, if you need antialiasing or texturing or a 100% pixel-perfect guarantee, use software rendering only: http://www.mesa3d.org/
By "Deterministic", I'm going to assume you mean what you said (rather than what the word actually means): that you can get pixel identical results cross-platform.
No. Not a chance.
You can change the pixel results you get from rendering just by playing with settings in your graphics driver's application. Driver revisions from the same hardware can change what you get.
The OpenGL specification has never required pixel-perfect results. Antialiasing and texture filtering especially are nebulous parts.
If you read through the OpenGL specification, there are a number of deterministic conditions that must be met in order for the implementation to comply with the standard, but there are also a significant number of implementation details that are left entirely up to the hardware vendor / driver developer. Unless you render with incredibly basic techniques that fall under the deterministic / invariant categories (which I believe will keep you from using filtered texturing, antialiasing, lighting, shaders, etc), the standard allows for pretty significant differences between different hardware and even different drivers on the same hardware.