In the general case, it is impossible to make a "non-blocking card", but you can display it without blocking.
The reason that there can be no "non-blocking card" is that at the moment when the function call returns, you can access the data, so the driver must make sure that he is there, positively. If the data has not been transferred, what else can the driver do, but block.
Threads don't do it better, and maybe make it worse (adding synchronization and context issues). Threads cannot magically remove the need for data transfer.
And this leads to how not to block the display: only the card when you are sure that the transfer is complete. One safe way to do this is to display the buffer after flipping the buffers or after glFinish or after waiting for the request / fencing object. Using a fence is the preferred method if you cannot wait for the buffers to be replaced. The fence will not stop the pipeline, but will tell you if your transfer will be completed ( glFinish may or may not, but will probably stop). Reading after replacing buffers is also 100% safe, but it may not be acceptable if you need data in the same frame (works great for screenshots or for calculating a histogram for creating tones).
A less secure way is to insert “some other things” and hope that the transfer is complete at this time.
Regarding the following comment:
This answer is
not incorrect. It is impossible to do better than access to data after its availability (this should be obvious). This means that you
have to synchronize / block, anyway, there is no choice.
Although from a very pedantic point of view, you can, of course, use
GL_MAP_UNSYNCHRONIZED_BIT to get a non-blocking map operation, it does not matter at all, since it does not work unless you explicitly reproduce implicit synchronization, as described above. A display that you cannot safely receive is unsuitable.
Matching and accessing the buffer that OpenGL passes data without synchronization / blocking (implicitly or explicitly) means "undefined behavior", which is only a more pleasant formulation for "probably garbage results, maybe a crash."
If, on the other hand, you are explicitly synchronizing (say, with a fence, as described above), then it does not matter if you use the unsynchronized flag, since in any case you no longer need implicit synchronization.