Compute shader link failure on Intel HD 4xxx / 5xxx GPUs - opengl

The following compute shader is causing troubles on Intels HD 4xxx / 5xxx series GPUs, using an OpenGL 4.3 Core context.
It compiles, but then fails to link with an absolutely useless error message:
SHADER_ID_LINK error has been generated. GLSL link failed for program 4, "": Out of resource error.
As far as I understand this shader should be completely legal on a GPU which claims to be OpenGL 4.3 compliant, and it does in fact work on newer GPUs just fine.
Seen the error happening on 20.19.15.5126 and a number of different, all up-to-date driver versions. OS Windows 8 and Windows 10, 64bit variants.
#version 430 core
// DO NOT CHANGE, must match game internal layout
struct TileData {
// TF_ flags 0:32
uint flags;
// TF_ flags 32:64
uint flags2;
// Sprites are all:
// spriteID=0:16, spriteFlags=16:32
uint floorSpriteUID ;
uint wallSpriteUID;
uint itemSpriteUID;
uint creatureSpriteUID;
uint jobSpriteFloorUID;
uint jobSpriteWallUID;
// fluidLevel=0:8, lightLevel=0:8, vegetationLevel=8:16
uint packedLevels;
};
struct TileDataUpdate {
uint id;
TileData tile;
};
layout(std430, binding = 0) writeonly restrict buffer tileData1
{
TileData data[];
} tileData;
layout(std430, binding = 1) readonly restrict buffer tileDataUpdate1
{
TileDataUpdate data[];
} tileDataUpdate;
uniform int uUpdateSize;
layout(local_size_x = 64) in;
void main()
{
uint id = gl_GlobalInvocationID.x;
if(id < uUpdateSize)
{
TileDataUpdate data = tileDataUpdate.data[id];
tileData.data[data.id] = data.tile;
}
}
Does anyone have a clue what could possibly be the cause for the link error? I don't have access to any such GPU myself, so I'm unable to test that by myself.
EDIT:
Testing with a 5 years old driver version (20.19.15.4624) it does actually work out of the box. So this is (yet another) regression in Intels drivers. Still clueless what exactly is triggering the bug or how to work around it.

Related

Vulkan VMA buffer is empty

I have been trying to implement Vulkan Memory Allocator in my application, but all I get is a blank screen. I use deferred and HDR pipeline and I allocate all my attachments using VMA. I tried outputting solid color in the fragment shader and it worked, so I suppose that the problem is that my vertex and index buffers are empty. I use staging buffer to copy data into vertex buffer. I fill the staging buffer like this:
void* data;
vmaMapMemory(_allocator, stagingAllocation, &data);
memcpy(data, bufferData, bufferSize);
vmaUnmapMemory(_allocator, stagingAllocation);
I also tried using vertex buffer without staging buffer and setting the flags
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
and copying data directly to vertex buffer with
memcpy(allocInfo.pMappedData, bufferData, bufferSize);
but that does not seem to work either.
Full code:
VkBuffer stagingBuffer;
VkBuffer vertexBuffer;
VmaAllocation stagingAllocation = createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY, stagingBuffer);
void* data;
vmaMapMemory(_allocator, stagingAllocation, &data);
memcpy(data, bufferData, bufferSize);
vmaUnmapMemory(_allocator, stagingAllocation);
VmaAllocation allocation = createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VMA_MEMORY_USAGE_GPU_ONLY, vertexBuffer);
copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
vmaDestroyBuffer(_allocator, stagingBuffer, stagingAllocation);
createBuffer function:
VmaAllocation createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage, VkBuffer &buffer) {
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.usage = memoryUsage;
VmaAllocation allocation;
if (vmaCreateBuffer(_allocation, &bufferInfo, & allocCreateInfo, &buffer, &allocation, nullptr) != VK_SUCCESS) {
throw std::runtime_error("Failed to create buffer");
}
return allocation;
}
If I set allocCreateInfo.flags to 0, I get weird flickering.
I have looked at many examples and all of them seem to be similar to my code.
I should also mention that it was working before I started using VMA and I have only modified the code I listed (plus the same code for image creation, but that seems to work fine).
I am on MacOS, Vulkan 1.2.
Any help would be greatly appreciated.
EDIT:
So after some hours of debugging, I figured it out. The problem was not in my vertex buffers, but rather in uniform buffers. I used flag VMA_MEMORY_USAGE_CPU_TO_GPU. After setting it to VMA_MEMORY_USAGE_CPU_ONLY, it started to work. This is only a temporary solution, since I do not want to store all my uniform buffers in cpu memory. If somebody knows what is wrong, please let me know.
Thank you
EDIT 2:
So turns out that VMA does not use VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT or VK_MEMORY_PROPERTY_HOST_COHERENT_BIT automatically when you set usage to be VMA_MEMORY_USAGE_CPU_TO_GPU. You need to include these flags in allocCreateInfo.requiredFlags. After doing this it works fine. However, I could not find this in the docs, so it was quite hard to debug.

GLX Context Creation Error: GLXBadFBConfig

I used glXCreateContext to create the contexts, but the function is deprecated and always results in an OpenGL Version 3.0, where I would need at least 4. Now, if I have understood it right, GLXContext glXCreateContextAttribsARB(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int* attrib_list); replaced glXCreateContext. The "new" function allows for explicitly specifying the major version, minor version, profile et cetera in it's attrib_list like this for example:
int context_attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 5,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPABILITY_PROFILE_BIT_ARB,
None
};
Then use the function:
glXCreateContextAttribsARB(dpy, config, NULL, true, context_attribs);
That is how I have done it in my program. The window is already created and dpy is a valid pointer to Display. config I have defined like this:
// GLXFBConfig config; created at the beginning of the program
int attrib_list[] =
{
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_DOUBLEBUFFER, True,
None
};
int nAttribs;
config = glXChooseFBConfig(dpy, 0, attrib_list, &nAttribs);
Checking with glxinfo, I have the correct visual for it; vi has been set to 0x120, which I can confirm with glxinfo | grep 0x120. It exactly fulfills the above.
So far, so good. But when running the application (compiling works fine), I get the following error:
X Error of failed request: GLXBadFBConfig
Major opcode of failed request: 152 (GLX)
Minor opcode of failed request: 34 ()
Serial number of failed request: 31
Current serial number in output stream: 31
Now, this is what the error is about:
If <config> does not support compatible OpenGL contexts providing the requested API major and minor version, forward-compatible flag, and debug context flag, GLXBadFBConfig is generated.
So, the problem is pretty straightforward. I don't know how to solve it though. What it essentially means is that no OpenGL context corresponding both to the attributes I specified in attrib_list[] and the attributes in context_attribs can be found. With glxinfo | grep Max I confirmed that my highest possible OpenGL Version is 4.5. I would like to hear your advice on what I should do now. I have played around with the attributes in context_attribs for a while, but did not get anywhere. Maybe the problem really is in another place. Maybe my conception of the GLX functions is flawed in general, please point it out if so!
The specification of GLX_ARB_create_context is clear about when GLXBadFBConfig error may be returned:
* If <config> does not support compatible OpenGL contexts
providing the requested API major and minor version,
forward-compatible flag, and debug context flag, GLXBadFBConfig
is generated.
This maybe confusing (as error has nothing to do with already created GLXFBConfig), but I that's what we have. So the most obvious reason for the error you have is that your system doesn't actually support OpenGL 4.5 Compatible Profile you have requested - it might have, though, support OpenGL 4.5 Core Profile or compatible/core profiles of lower versions. This is a pretty common case for Mesa drivers supporting only OpenGL 3.3+ Core Profiles and just OpenGL 3.0 Compatible Profile for many GPUs (but not all - some gets better Compatible Profile support like Radeons).
If you are not familiar yet with conception of OpenGL profiles - you can start here.
glxinfo shows information about both Core and Compatible profiles, which could be filtered out like this:
glxinfo | grep -e "OpenGL version" -e "Core" -e "Compatible"
which returns this on a virtual Ubuntu 18.04 to me:
OpenGL core profile version string: 3.3 (Core Profile) Mesa 19.2.8
OpenGL version string: 3.1 Mesa 19.2.8
If your application really needs OpenGL 4.5 or higher, than just try creating a context with GLX_CONTEXT_CORE_PROFILE_BIT_ARB bit instead of GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB and ensure not using any deprecated functionality.
Note that requesting a Compatible Profile of specific version usually makes no sense - it is enough just skipping version parameters to get the highest supported one and filter out unsupported versions from GL_VERSION/GL_MAJOR_VERSION of already created context like it was done in days before profiles have been introduced. In case of a Core Profile, it might be tricky on some OpenGL drivers requesting the highest supported version (e.g. without disabled functionality of versions higher than requested) - the following code snippet could be useful:
//! A dummy XError handler which just skips errors
static int xErrorDummyHandler (Display* , XErrorEvent* ) { return 0; }
...
Window aWindow = ...;
Display* aDisp = ...;
GLXFBConfig anFBConfig = ...;
bool toDebugContext = false;
GLXContext aGContext = NULL
const char* aGlxExts = glXQueryExtensionsString (aDisp, aVisInfo.screen);
if (!checkGlExtension (aGlxExts, "GLX_ARB_create_context_profile"))
{
std::cerr << "GLX_ARB_create_context_profile is NOT supported\n";
return;
}
// Replace default XError handler to ignore errors.
// Warning - this is global for all threads!
typedef int (*xerrorhandler_t)(Display* , XErrorEvent* );
xerrorhandler_t anOldHandler = XSetErrorHandler(xErrorDummyHandler);
typedef GLXContext (*glXCreateContextAttribsARB_t)(Display* dpy, GLXFBConfig config,
GLXContext share_context, Bool direct,
const int* attrib_list);
glXCreateContextAttribsARB_t aCreateCtxProc = (glXCreateContextAttribsARB_t )glXGetProcAddress((const GLubyte* )"glXCreateContextAttribsARB");
int aCoreCtxAttribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_FLAGS_ARB, toDebugContext ? GLX_CONTEXT_DEBUG_BIT_ARB : 0,
0, 0
};
// try to create a Core Profile of highest OpenGL version (up to 4.6)
for (int aLowVer4 = 6; aLowVer4 >= 0 && aGContext == NULL; --aLowVer4)
{
aCoreCtxAttribs[1] = 4;
aCoreCtxAttribs[3] = aLowVer4;
aGContext = aCreateCtxProc (aDisp, anFBConfig, NULL, True, aCoreCtxAttribs);
}
for (int aLowVer3 = 3; aLowVer3 >= 2 && aGContext == NULL; --aLowVer3)
{
aCoreCtxAttribs[1] = 3;
aCoreCtxAttribs[3] = aLowVer3;
aGContext = aCreateCtxProc (aDisp, anFBConfig, NULL, True, aCoreCtxAttribs);
}
bool isCoreProfile = aGContext != NULL;
if (!isCoreProfile)
{
std::cerr << "glXCreateContextAttribsARB() failed to create Core Profile\n";
}
// try to create Compatible Profile
if (aGContext == NULL)
{
int aCtxAttribs[] =
{
GLX_CONTEXT_FLAGS_ARB, toDebugContext ? GLX_CONTEXT_DEBUG_BIT_ARB : 0,
0, 0
};
aGContext = aCreateCtxProc (aDisp, anFBConfig, NULL, True, aCtxAttribs);
}
XSetErrorHandler (anOldHandler);
// fallback to glXCreateContext() as last resort
if (aGContext == NULL)
{
aGContext = glXCreateContext (aDisp, aVis.get(), NULL, GL_TRUE);
if (aGContext == NULL) { std::cerr << "glXCreateContext() failed\n"; }
}

How I can get my total GPU memory using Qt's native OpenGL?

I'm trying to get the total amount of GPU memory from my video card using native Qt's OpenGL, I have tried hundred of methods, but none do work.
This is what I have at the moment:
QOpenGLContext context;
context.create();
QOffscreenSurface surface;
surface.setFormat(context.format());
surface.create();
QOpenGLFunctions func;
context.makeCurrent(&surface);
func.initializeOpenGLFunctions();
GLint total_mem_kb = 0;
func.glGetIntegerv(GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX,&total_mem_kb);
qDebug()<<total_mem_kb;
The problem is that the variable total_mem_kb is always 0, It does not get the value inside of glGetIntegerv. By running this code I get 0. What can be the problem? Can you please give me a hint?
First an foremost check if the NVX_gpu_memory_info extension is supported.
Note that the extension requires OpenGL 2.0 at least.
GLint count;
glGetIntegerv(GL_NUM_EXTENSIONS, &count);
for (GLint i = 0; i < count; ++i)
{
const char *extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
if (!strcmp(extension, "GL_NVX_gpu_memory_info"))
printf("%d: %s\n", i, extension);
}
I know you just said that you have an Nvidia graphics card, but this doesn't by default guarantee support. Additionally if you have an integrated graphics card then make sure you are actually using your dedicated graphics card.
If you have an Nvidia GeForce graphics card, then then the following should result in something along the lines of "Nvidia" and "GeForce".
glGetString(GL_VENDOR);
glGetString(GL_RENDERER);
If it returns anything but "Nvidia" then you need to open your Nvidia Control Panel and set the preferred graphics card to your Nvidia graphics card.
After you've verified it being the Nvidia graphics card and that the extension is supported. Then you can try getting the total and current available memory:
GLint totalMemoryKb = 0;
glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &totalMemoryKb);
GLint currentMemoryKb = 0;
glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &currentMemoryKb);
I would also like to point out that the NVX_gpu_memory_info extension defines it as:
GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX
and not
GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX
Note the MEMORY vs MEM difference.
So suspecting you've defined GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX yourself or leveraging something else that has defined it. That tells it could be wrongly defined or referring to something else.
I use the following:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
LONG __stdcall glxGpuTotalMemory()
{
GLint total_mem_kb = 0;
glGetIntegerv(GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX, &total_mem_kb);
if (total_mem_kb == 0 && wglGetGPUIDsAMD)
{
UINT n = wglGetGPUIDsAMD(0, 0);
UINT *ids = new UINT[n];
size_t total_mem_mb = 0;
wglGetGPUIDsAMD(n, ids);
wglGetGPUInfoAMD(ids[0], WGL_GPU_RAM_AMD, GL_UNSIGNED_INT, sizeof(size_t), &total_mem_mb);
total_mem_kb = total_mem_mb * 1024;
}
return total_mem_kb;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
LONG __stdcall glxGpuAvailMemory()
{
GLint cur_avail_mem_kb = 0;
glGetIntegerv(GL_GPU_MEM_INFO_CURRENT_AVAILABLE_MEM_NVX, &cur_avail_mem_kb);
if (cur_avail_mem_kb == 0 && wglGetGPUIDsAMD)
{
glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, &cur_avail_mem_kb);
}
return cur_avail_mem_kb;
}

glewInit function throws error code 0x0000007F (C++) [duplicate]

I try to write down code from this tutorial. I have the code of InitializeOGL():
bool Ogl::InitializeOGL(bool vSync)
{
cout<<"Init OpenGL"<<endl;
int pixelFormat;
PIXELFORMATDESCRIPTOR pixelFormatDescriptor;
int result;
char *vendorChar, *rendererChar;
hDC = GetDC(hWnd);
if(!hDC)
return false;
pixelFormat = ChoosePixelFormat(hDC,&pixelFormatDescriptor);
if(pixelFormat==0)
return false;
result = SetPixelFormat(hDC,pixelFormat,&pixelFormatDescriptor);
if(result!=1)
return false;
HGLRC tempDeviceContext = wglCreateContext(hDC);
wglMakeCurrent(hDC,tempDeviceContext);
// glewExperimental = GL_TRUE;
if(glewInit()!=GLEW_OK)
return false;
int attribList[5] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 1, 0
};
hGLRC = wglCreateContextAttribsARB(hDC,0,attribList);
if(hGLRC!=NULL)
{
wglMakeCurrent(NULL,NULL);
wglDeleteContext(tempDeviceContext);
result = wglMakeCurrent(hDC,hGLRC);
if(result!=1)
return false;
}
vendorChar = (char*)glGetString(GL_VENDOR);
rendererChar = (char*)glGetString(GL_RENDERER);
strcpy_s(videoCardInfo,vendorChar);
strcat_s(videoCardInfo,"-");
strcat_s(videoCardInfo,rendererChar);
if(vSync)
result = wglSwapIntervalEXT(1);
else
result = wglSwapIntervalEXT(0);
if(result!=1)
return false;
int glVersion[2] = {-1,-1};
glGetIntegerv(GL_MAJOR_VERSION,&glVersion[0]);
glGetIntegerv(GL_MINOR_VERSION,&glVersion[1]);
cout<<"Initializing OpenGL"<<endl;
cout<<"OpenGL version"<<glVersion[0]<<"."<<glVersion[1]<<endl;
cout<<"GPU"<<videoCardInfo<<endl;
return 0;
}
When I try to change context version to OpenGL 3.1, here crashes wglCreateContextAttribsARB()
function (Pointer for this is getting in LoadExtensions() correctly). When I try to create OpenGL 4.0 here crashes function wglSwapIntervalEXT(). My graphic card handles only OpenGL 3.1.
My question is how to succefully init OpenGL context here? What I have to do to create OpenGL context in version 3.1.
There are a couple of things that need to be mentioned here:
1. Driver Version
If your graphics card / driver only support OpenGL 3.1, then WGL_CONTEXT_MAJOR_VERSION_ARB and friends are generally going to be undefined. Before OpenGL 3.2 introduced core / compatibility, context versions were not particularly meaningful.
This requires support for either WGL_ARB_create_context or WGL_ARB_create_conext_profile.
2. Incorrect usage of ChoosePixelFormat and SetPixelFormat
PIXELFORMATDESCRIPTOR pixelFormatDescriptor; // <--- Uninitialized
At minimum, the Win32 API needs you to initialize the size field of this structure. In years past, the size of structures was used to determine the version of Windows that a particular piece of code was written for. These days structures like PIXELFORMATDESCRIPTOR are generally static in size because they are used by a part of Windows that is deprecated (GDI), but if you do not set the size you can still thoroughly confuse Windows. Furthermore, you need to flag your pixel format to support OpenGL to guarantee that you can use it to create an OpenGL render context.
Also note that once you set the pixel format for a device context on Windows, it cannot be changed. Generally, this means if you want to create a dummy render context to initialize your extensions you should also create a dummy window with a dummy pixel format. After you initialize your extensions, you can use wglChoosePixelFormatARB (...) and its associated functions to select the pixel format for your main window's device context.
This is (was) particularly important back in the days before FBOs when you wanted to implement multi-sampling. You cannot get a multi-sample pixel format using ChoosePixelFormat (...), but you need to call ChoosePixelFormat (...) to setup the extension necessary to get a multi-sample pixel format. Kind of a catch 22.

Abnormal Execution after wglCreateContext in MFC based Application

We have a 32-bit Visual C++/MFC based (Multi-Document Interface-MDI) application which is compiled using Visual Studio 2005.
We are running the application on Windows Server 2008 R2 (64-bit) having ATI Graphics card (ATIES1000 version 8.240.50.5000 to be exact).
We are using OpenGL in certain parts of our software.
The problem is that the software is randomly crashing after executing the code related to initialization of an OpenGL based window. After including heavy tracing in the code, we found out that the program execution becomes abnormal after executing wglCreateContext() function; it skips the rest of the code for the current function for initializing of OpenGL based Window and instead starts executing the default View (drawing) function of the application (eg. ApplicationView::OnDraw).
After executing a few lines of code for the default view, the program generates an exception when trying to access a main document member variable. Our unhandled exception filter is able to catch the exception and generate an execution dump, but the execution dump does not provide much useful information either, other than specifying that the exception code is c0000090.
The problem is quite random and is only reported to appear on this Windows server environment only.
Any help or hints in solving this situation?
EDIT :
in other words, the program structure looks like this, with the execution randomly skipping the lines after wglCreateContext() function, executing a few lines of ApplicationView::onDraw and then causing an exception:
void 3DView::InitializeOpenGL()
{
....
Init3DWindow( m_b3DEnabled, m_pDC->GetSafeHdc());
m_Font->init();
....
}
bool 3DView::Init3DWindow( bool b3DEnabled, HDC pHDC)
{
...
static PIXELFORMATDESCRIPTOR pd = {
sizeof (PIXELFORMATDESCRIPTOR), // Specifies the size
1, // Specifies the version of this data structure
...
};
int iPixelFormat = ChoosePixelFormat(pHDC, &pd);
if(iPixelFormat == 0)
{
...
}
bSuccess = SetPixelFormat(pHDC, iPixelFormat, &pd);
m_hRC = wglCreateContext(pHDC);
//Execution becomes abnormal afterwards and control exits from 3DView::Init3DWindow
if(m_hRC==NULL)
{
...
}
bSuccess = wglMakeCurrent(pHDC, m_hRC);
....
return true;
}
void ApplicationView::OnDraw(CDC* pDC)
{
...
CApplicationDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
...
double currentValue = pDoc->m_CurrentValue;
//EXCEPTION raised at the above line
double nextValue = pDoc->nextValue;
}