Skip to content
Permalink
Browse files

Merge pull request #2092 from Sonicadvance1/gles_occlusion_queries

Implement full occlusion queries for the Nexus 9.
  • Loading branch information...
Sonicadvance1 committed Mar 8, 2015
2 parents 61591db + e9ac4d5 commit 70977fd6b163d38e1db875d1e3d303656b071043
@@ -776,6 +776,15 @@ PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;
PFNGLBUFFERSTORAGEPROC glBufferStorage;
PFNGLNAMEDBUFFERSTORAGEEXTPROC glNamedBufferStorageEXT;

// GL_NV_occlusion_query_samples
PFNGLGENOCCLUSIONQUERIESNVPROC glGenOcclusionQueriesNV;
PFNGLDELETEOCCLUSIONQUERIESNVPROC glDeleteOcclusionQueriesNV;
PFNGLISOCCLUSIONQUERYNVPROC glIsOcclusionQueryNV;
PFNGLBEGINOCCLUSIONQUERYNVPROC glBeginOcclusionQueryNV;
PFNGLENDOCCLUSIONQUERYNVPROC glEndOcclusionQueryNV;
PFNGLGETOCCLUSIONQUERYIVNVPROC glGetOcclusionQueryivNV;
PFNGLGETOCCLUSIONQUERYUIVNVPROC glGetOcclusionQueryuivNV;

// Creates a GLFunc object that requires a feature
#define GLFUNC_REQUIRES(x, y) { (void**)&x, #x, y }
// Creates a GLFunc object with a different function suffix
@@ -1254,6 +1263,15 @@ const GLFunc gl_function_array[] =
// EXT_geometry_shader
GLFUNC_SUFFIX(glFramebufferTexture, EXT, "GL_EXT_geometry_shader !VERSION_3_2"),

// NV_occlusion_query_samples
GLFUNC_REQUIRES(glGenOcclusionQueriesNV, "GL_NV_occlusion_query_samples"),
GLFUNC_REQUIRES(glDeleteOcclusionQueriesNV, "GL_NV_occlusion_query_samples"),
GLFUNC_REQUIRES(glIsOcclusionQueryNV, "GL_NV_occlusion_query_samples"),
GLFUNC_REQUIRES(glBeginOcclusionQueryNV, "GL_NV_occlusion_query_samples"),
GLFUNC_REQUIRES(glEndOcclusionQueryNV, "GL_NV_occlusion_query_samples"),
GLFUNC_REQUIRES(glGetOcclusionQueryivNV, "GL_NV_occlusion_query_samples"),
GLFUNC_REQUIRES(glGetOcclusionQueryuivNV, "GL_NV_occlusion_query_samples"),

// gl_1_1
// OpenGL 1.1 is at the end due to a bug in Android's EGL stack.
// eglGetProcAddress can only return a finite amount of function pointers
@@ -31,6 +31,7 @@
#include "VideoBackends/OGL/GLExtensions/gl_3_1.h"
#include "VideoBackends/OGL/GLExtensions/gl_3_2.h"
#include "VideoBackends/OGL/GLExtensions/KHR_debug.h"
#include "VideoBackends/OGL/GLExtensions/NV_occlusion_query_samples.h"
#include "VideoBackends/OGL/GLExtensions/NV_primitive_restart.h"

namespace GLExtensions
@@ -0,0 +1,13 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#include "VideoBackends/OGL/GLExtensions/gl_common.h"

extern PFNGLGENOCCLUSIONQUERIESNVPROC glGenOcclusionQueriesNV;
extern PFNGLDELETEOCCLUSIONQUERIESNVPROC glDeleteOcclusionQueriesNV;
extern PFNGLISOCCLUSIONQUERYNVPROC glIsOcclusionQueryNV;
extern PFNGLBEGINOCCLUSIONQUERYNVPROC glBeginOcclusionQueryNV;
extern PFNGLENDOCCLUSIONQUERYNVPROC glEndOcclusionQueryNV;
extern PFNGLGETOCCLUSIONQUERYIVNVPROC glGetOcclusionQueryivNV;
extern PFNGLGETOCCLUSIONQUERYUIVNVPROC glGetOcclusionQueryuivNV;
@@ -83,6 +83,7 @@
<ClInclude Include="GLExtensions\gl_3_2.h" />
<ClInclude Include="GLExtensions\gl_common.h" />
<ClInclude Include="GLExtensions\KHR_debug.h" />
<ClInclude Include="GLExtensions\NV_occlusion_query_samples.h" />
<ClInclude Include="GLExtensions\NV_primitive_restart.h" />
<ClInclude Include="GLInterface\WGL.h" />
<ClInclude Include="GLUtil.h" />
@@ -187,6 +187,9 @@
<ClInclude Include="GLExtensions\GLExtensions.h">
<Filter>GLExtensions</Filter>
</ClInclude>
<ClInclude Include="GLExtensions\NV_occlusion_query_samples.h">
<Filter>GLExtensions</Filter>
</ClInclude>
<ClInclude Include="GLExtensions\NV_primitive_restart.h">
<Filter>GLExtensions</Filter>
</ClInclude>
@@ -9,24 +9,90 @@

namespace OGL
{
PerfQueryBase* GetPerfQuery()
{
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 &&
GLExtensions::Supports("GL_NV_occlusion_query_samples"))
return new PerfQueryGLESNV();
else if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
return new PerfQueryGL(GL_ANY_SAMPLES_PASSED);
else
return new PerfQueryGL(GL_SAMPLES_PASSED);
}

PerfQuery::PerfQuery()
: m_query_read_pos()
, m_query_count()
{
ResetQuery();
}

void PerfQuery::EnableQuery(PerfQueryGroup type)
{
m_query->EnableQuery(type);
}

void PerfQuery::DisableQuery(PerfQueryGroup type)
{
m_query->DisableQuery(type);
}

bool PerfQuery::IsFlushed() const
{
return 0 == m_query_count;
}

// TODO: could selectively flush things, but I don't think that will do much
void PerfQuery::FlushResults()
{
m_query->FlushResults();
}

void PerfQuery::ResetQuery()
{
m_query_count = 0;
std::fill_n(m_results, ArraySize(m_results), 0);
}

u32 PerfQuery::GetQueryResult(PerfQueryType type)
{
u32 result = 0;

if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
{
result = m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
{
result = m_results[PQG_ZCOMP];
}
else if (type == PQ_BLEND_INPUT)
{
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_EFB_COPY_CLOCKS)
{
result = m_results[PQG_EFB_COPY_CLOCKS];
}

return result / 4;
}

// Implementations
PerfQueryGL::PerfQueryGL(GLenum query_type)
: m_query_type(query_type)
{
for (ActiveQuery& query : m_query_buffer)
glGenQueries(1, &query.query_id);

ResetQuery();
}

PerfQuery::~PerfQuery()
PerfQueryGL::~PerfQueryGL()
{
for (ActiveQuery& query : m_query_buffer)
glDeleteQueries(1, &query.query_id);
}

void PerfQuery::EnableQuery(PerfQueryGroup type)
void PerfQueryGL::EnableQuery(PerfQueryGroup type)
{
// Is this sane?
if (m_query_count > m_query_buffer.size() / 2)
@@ -43,28 +109,42 @@ void PerfQuery::EnableQuery(PerfQueryGroup type)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()];

glBeginQuery(GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ? GL_SAMPLES_PASSED : GL_ANY_SAMPLES_PASSED, entry.query_id);
glBeginQuery(m_query_type, entry.query_id);
entry.query_type = type;

++m_query_count;
}
}

void PerfQuery::DisableQuery(PerfQueryGroup type)
void PerfQueryGL::DisableQuery(PerfQueryGroup type)
{
// stop query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
glEndQuery(GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ? GL_SAMPLES_PASSED : GL_ANY_SAMPLES_PASSED);
glEndQuery(m_query_type);
}
}

bool PerfQuery::IsFlushed() const
void PerfQueryGL::WeakFlush()
{
return 0 == m_query_count;
while (!IsFlushed())
{
auto& entry = m_query_buffer[m_query_read_pos];

GLuint result = GL_FALSE;
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result);

if (GL_TRUE == result)
{
FlushOne();
}
else
{
break;
}
}
}

void PerfQuery::FlushOne()
void PerfQueryGL::FlushOne()
{
auto& entry = m_query_buffer[m_query_read_pos];

@@ -79,20 +159,64 @@ void PerfQuery::FlushOne()
}

// TODO: could selectively flush things, but I don't think that will do much
void PerfQuery::FlushResults()
void PerfQueryGL::FlushResults()
{
while (!IsFlushed())
FlushOne();
}

void PerfQuery::WeakFlush()
PerfQueryGLESNV::PerfQueryGLESNV()
{
for (ActiveQuery& query : m_query_buffer)
glGenOcclusionQueriesNV(1, &query.query_id);
}

PerfQueryGLESNV::~PerfQueryGLESNV()
{
for (ActiveQuery& query : m_query_buffer)
glDeleteOcclusionQueriesNV(1, &query.query_id);
}

void PerfQueryGLESNV::EnableQuery(PerfQueryGroup type)
{
// Is this sane?
if (m_query_count > m_query_buffer.size() / 2)
WeakFlush();

if (m_query_buffer.size() == m_query_count)
{
FlushOne();
//ERROR_LOG(VIDEO, "Flushed query buffer early!");
}

// start query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()];

glBeginOcclusionQueryNV(entry.query_id);
entry.query_type = type;

++m_query_count;
}
}
void PerfQueryGLESNV::DisableQuery(PerfQueryGroup type)
{
// stop query
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
{
glEndOcclusionQueryNV();
}
}

void PerfQueryGLESNV::WeakFlush()
{
while (!IsFlushed())
{
auto& entry = m_query_buffer[m_query_read_pos];

GLuint result = GL_FALSE;
glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result);
glGetOcclusionQueryuivNV(entry.query_id, GL_PIXEL_COUNT_AVAILABLE_NV, &result);

if (GL_TRUE == result)
{
@@ -105,34 +229,25 @@ void PerfQuery::WeakFlush()
}
}

void PerfQuery::ResetQuery()
void PerfQueryGLESNV::FlushOne()
{
m_query_count = 0;
std::fill_n(m_results, ArraySize(m_results), 0);
}
auto& entry = m_query_buffer[m_query_read_pos];

u32 PerfQuery::GetQueryResult(PerfQueryType type)
{
u32 result = 0;
GLuint result = 0;
glGetOcclusionQueryuivNV(entry.query_id, GL_OCCLUSION_TEST_RESULT_HP, &result);

if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
{
result = m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
{
result = m_results[PQG_ZCOMP];
}
else if (type == PQ_BLEND_INPUT)
{
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
}
else if (type == PQ_EFB_COPY_CLOCKS)
{
result = m_results[PQG_EFB_COPY_CLOCKS];
}
// NOTE: Reported pixel metrics should be referenced to native resolution
m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();

return result / 4;
m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
--m_query_count;
}

// TODO: could selectively flush things, but I don't think that will do much
void PerfQueryGLESNV::FlushResults()
{
while (!IsFlushed())
FlushOne();
}

} // namespace

0 comments on commit 70977fd

Please sign in to comment.
You can’t perform that action at this time.