This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

GLES Disjoint timer query unexpected value

Hi,

I'm having an issue getting plausible values at certain times with a disjoint timer query. I've read the discussion in here but my issue seems slightly different.

I'm not trying to time individual draw calls but rather the time it takes for complete the backbuffer.

I'm getting "roughly" consistent numbers for a large part of the frames, but frequently get 18446744073709551615 (2^64-1). This happens even when glGetQueryObjectuiv() returns true for an available query. Here's a snippet of the code (which is a slightly modified version this Unity plugin to use a 64-bit query):

GLuint available = 0;
glGetQueryObjectuiv(queryObject, GL_QUERY_RESULT_AVAILABLE, &available);
if (available == GL_TRUE) 
{
  GLuint64 elapsed_time_ns;
  glGetQueryObjectui64vEXT(queryObject, GL_QUERY_RESULT, &elapsed_time_ns);
  if (glGetError() == GL_NO_ERROR) 
  {
    ...
  }
  ...
}

I've tried forcing a synchronous call by ignoring the availability of the result. In such cases, the MAX_UINT above doesn't seem to occur and the values are "roughly" consistent (sometimes a few ms apart, but that's perhaps due HW pipelining).

I've gone through the extension spec but I can't find anything that might explain this. Could I've missed something?

I'm running this on a Samsung A20 with a Mali-G71. I've tried the same test on a device with an old Adreno 330 and I don't seem to get the same issue though.

GLuint available = 0;
glGetQueryObjectuiv(queryObject, GL_QUERY_RESULT_AVAILABLE, &available);
if (available == GL_TRUE) 
{
  GLuint64 elapsed_time_ns;
  glGetQueryObjectui64vEXT(queryObject, GL_QUERY_RESULT, &elapsed_time_ns);
  if (glGetError() == GL_NO_ERROR) 
  {
    ...
  }
  ...
}

Parents
  • Hi Sunny, thanks for the reply. Here's some abbreviated pseudo-code of what I'm doing (this is largely based on an open source Unity plugin :

    void BeforeRenderingStarts()
    {
    	// on disjoint exception, clear query buffer
    	GLint disjointOccurred = false;
    	glGetIntegerv(GL_GPU_DISJOINT, &disjointOccurred);
    	if (disjointOccurred)
    	{
    		query_buffer_n = 0;
    		__android_log_print(ANDROID_LOG_ERROR, "Timer", "Disjoint Exception occurred");
    	}
    
    	// read result of oldest pending query
      // We use buffering to avoid blocking when reading results.
    	elapsed_time_seconds = NAN; // NOTE_JPJ: if ran synchronously below NAN is caught by the thread reading this value - consider using the last frame's one
    	if (query_buffer_n > 0)
    	{
    		int index = (query_buffer_next_index + (BUFFER_SIZE - query_buffer_n)) % BUFFER_SIZE;
    		GLuint available = 0;
    		glGetQueryObjectuiv(queries[index], GL_QUERY_RESULT_AVAILABLE, &available);
    		if (available == GL_TRUE)
    		{
    			GLuint64 elapsed_time_ns;
    			glGetQueryObjectui64vEXT(queries[index], GL_QUERY_RESULT, &elapsed_time_ns);
    			if (glGetError() == GL_NO_ERROR)
    			{
    				__android_log_print(ANDROID_LOG_VERBOSE, "Timer", "The value of the timestamp is elapsed %llu. ", elapsed_time_ns);
    			}
    			else 
    			{
    				// log error 
    			}
    			--query_buffer_n;
    		}
    	}
    
    	// start new query
    	if (query_buffer_n < BUFFER_SIZE) 
    	{
    		glBeginQuery(GL_TIME_ELAPSED, queries[query_buffer_next_index]);
    		if (glGetError() == GL_NO_ERROR) 
    		{
    			query_buffer_next_index = (query_buffer_next_index + 1) % BUFFER_SIZE;
    			++query_buffer_n;
    		}
    		else 
    		{
    			// log error
    		}
    	}
    	else
    	{
    		// log overflow
    	}
    }
    
    void AfterRenderingEnds()
    {
    	glEndQuery(GL_TIME_ELAPSED);
    	if (glGetError() != GL_NO_ERROR)
    	{
    		// log error
    	}
    }


    Is there anything in particular that catches your eye?

    I'll have a look at exactly where the START/END functions above are placed in the GL pipeline since this is triggered from Unity callbacks.

Reply
  • Hi Sunny, thanks for the reply. Here's some abbreviated pseudo-code of what I'm doing (this is largely based on an open source Unity plugin :

    void BeforeRenderingStarts()
    {
    	// on disjoint exception, clear query buffer
    	GLint disjointOccurred = false;
    	glGetIntegerv(GL_GPU_DISJOINT, &disjointOccurred);
    	if (disjointOccurred)
    	{
    		query_buffer_n = 0;
    		__android_log_print(ANDROID_LOG_ERROR, "Timer", "Disjoint Exception occurred");
    	}
    
    	// read result of oldest pending query
      // We use buffering to avoid blocking when reading results.
    	elapsed_time_seconds = NAN; // NOTE_JPJ: if ran synchronously below NAN is caught by the thread reading this value - consider using the last frame's one
    	if (query_buffer_n > 0)
    	{
    		int index = (query_buffer_next_index + (BUFFER_SIZE - query_buffer_n)) % BUFFER_SIZE;
    		GLuint available = 0;
    		glGetQueryObjectuiv(queries[index], GL_QUERY_RESULT_AVAILABLE, &available);
    		if (available == GL_TRUE)
    		{
    			GLuint64 elapsed_time_ns;
    			glGetQueryObjectui64vEXT(queries[index], GL_QUERY_RESULT, &elapsed_time_ns);
    			if (glGetError() == GL_NO_ERROR)
    			{
    				__android_log_print(ANDROID_LOG_VERBOSE, "Timer", "The value of the timestamp is elapsed %llu. ", elapsed_time_ns);
    			}
    			else 
    			{
    				// log error 
    			}
    			--query_buffer_n;
    		}
    	}
    
    	// start new query
    	if (query_buffer_n < BUFFER_SIZE) 
    	{
    		glBeginQuery(GL_TIME_ELAPSED, queries[query_buffer_next_index]);
    		if (glGetError() == GL_NO_ERROR) 
    		{
    			query_buffer_next_index = (query_buffer_next_index + 1) % BUFFER_SIZE;
    			++query_buffer_n;
    		}
    		else 
    		{
    			// log error
    		}
    	}
    	else
    	{
    		// log overflow
    	}
    }
    
    void AfterRenderingEnds()
    {
    	glEndQuery(GL_TIME_ELAPSED);
    	if (glGetError() != GL_NO_ERROR)
    	{
    		// log error
    	}
    }


    Is there anything in particular that catches your eye?

    I'll have a look at exactly where the START/END functions above are placed in the GL pipeline since this is triggered from Unity callbacks.

Children