Commit a20fc005 by Geoff Lang Committed by Commit Bot

Implement GL_CHROMIUM_sync_query for GL.

BUG=angleproject:1366 Change-Id: I9e44679754eb704b390191c28206dedc3dc7cc4f Reviewed-on: https://chromium-review.googlesource.com/367082 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 9f09037b
......@@ -84,13 +84,13 @@ class ScopedGLState : public angle::NonCopyable
mStateManager->setRasterizerDiscardEnabled(false);
mStateManager->pauseTransformFeedback();
mStateManager->pauseQueries();
mStateManager->pauseAllQueries();
}
~ScopedGLState()
{
// XFB resuming will be done automatically
mStateManager->resumeQueries();
mStateManager->resumeAllQueries();
}
void willUseTextureUnit(int unit)
......
......@@ -90,7 +90,14 @@ VertexArrayImpl *ContextGL::createVertexArray(const gl::VertexArrayState &data)
QueryImpl *ContextGL::createQuery(GLenum type)
{
return new QueryGL(type, getFunctions(), getStateManager());
switch (type)
{
case GL_COMMANDS_COMPLETED_CHROMIUM:
return new SyncQueryGL(type, getFunctions(), getStateManager());
default:
return new StandardQueryGL(type, getFunctions(), getStateManager());
}
}
FenceNVImpl *ContextGL::createFenceNV()
......
......@@ -11,6 +11,7 @@
#include "common/debug.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
namespace
{
......@@ -43,8 +44,18 @@ GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResu
namespace rx
{
QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager)
: QueryImpl(type),
QueryGL::QueryGL(GLenum type) : QueryImpl(type)
{
}
QueryGL::~QueryGL()
{
}
StandardQueryGL::StandardQueryGL(GLenum type,
const FunctionsGL *functions,
StateManagerGL *stateManager)
: QueryGL(type),
mType(type),
mFunctions(functions),
mStateManager(stateManager),
......@@ -54,7 +65,7 @@ QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stat
{
}
QueryGL::~QueryGL()
StandardQueryGL::~StandardQueryGL()
{
mStateManager->deleteQuery(mActiveQuery);
mStateManager->onDeleteQueryObject(this);
......@@ -65,19 +76,19 @@ QueryGL::~QueryGL()
}
}
gl::Error QueryGL::begin()
gl::Error StandardQueryGL::begin()
{
mResultSum = 0;
mStateManager->onBeginQuery(this);
return resume();
}
gl::Error QueryGL::end()
gl::Error StandardQueryGL::end()
{
return pause();
}
gl::Error QueryGL::queryCounter()
gl::Error StandardQueryGL::queryCounter()
{
ASSERT(mType == GL_TIMESTAMP);
......@@ -92,7 +103,7 @@ gl::Error QueryGL::queryCounter()
}
template <typename T>
gl::Error QueryGL::getResultBase(T *params)
gl::Error StandardQueryGL::getResultBase(T *params)
{
ASSERT(mActiveQuery == 0);
......@@ -108,27 +119,27 @@ gl::Error QueryGL::getResultBase(T *params)
return gl::Error(GL_NO_ERROR);
}
gl::Error QueryGL::getResult(GLint *params)
gl::Error StandardQueryGL::getResult(GLint *params)
{
return getResultBase(params);
}
gl::Error QueryGL::getResult(GLuint *params)
gl::Error StandardQueryGL::getResult(GLuint *params)
{
return getResultBase(params);
}
gl::Error QueryGL::getResult(GLint64 *params)
gl::Error StandardQueryGL::getResult(GLint64 *params)
{
return getResultBase(params);
}
gl::Error QueryGL::getResult(GLuint64 *params)
gl::Error StandardQueryGL::getResult(GLuint64 *params)
{
return getResultBase(params);
}
gl::Error QueryGL::isResultAvailable(bool *available)
gl::Error StandardQueryGL::isResultAvailable(bool *available)
{
ASSERT(mActiveQuery == 0);
......@@ -142,7 +153,7 @@ gl::Error QueryGL::isResultAvailable(bool *available)
return gl::Error(GL_NO_ERROR);
}
gl::Error QueryGL::pause()
gl::Error StandardQueryGL::pause()
{
if (mActiveQuery != 0)
{
......@@ -162,7 +173,7 @@ gl::Error QueryGL::pause()
return gl::Error(GL_NO_ERROR);
}
gl::Error QueryGL::resume()
gl::Error StandardQueryGL::resume()
{
if (mActiveQuery == 0)
{
......@@ -180,7 +191,7 @@ gl::Error QueryGL::resume()
return gl::Error(GL_NO_ERROR);
}
gl::Error QueryGL::flush(bool force)
gl::Error StandardQueryGL::flush(bool force)
{
while (!mPendingQueries.empty())
{
......@@ -219,4 +230,194 @@ gl::Error QueryGL::flush(bool force)
return gl::Error(GL_NO_ERROR);
}
class SyncProviderGL
{
public:
virtual ~SyncProviderGL() {}
virtual gl::Error flush(bool force, bool *finished) = 0;
};
class SyncProviderGLSync : public SyncProviderGL
{
public:
SyncProviderGLSync(const FunctionsGL *functions) : mFunctions(functions), mSync(nullptr)
{
mSync = mFunctions->fenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
virtual ~SyncProviderGLSync() { mFunctions->deleteSync(mSync); }
gl::Error flush(bool force, bool *finished) override
{
if (force)
{
mFunctions->clientWaitSync(mSync, 0, 0);
*finished = true;
}
else
{
GLint value = 0;
mFunctions->getSynciv(mSync, GL_SYNC_STATUS, 1, nullptr, &value);
*finished = (value == GL_SIGNALED);
}
return gl::NoError();
}
private:
const FunctionsGL *mFunctions;
GLsync mSync;
};
class SyncProviderGLQuery : public SyncProviderGL
{
public:
SyncProviderGLQuery(const FunctionsGL *functions,
StateManagerGL *stateManager,
GLenum queryType)
: mFunctions(functions), mQuery(0)
{
mFunctions->genQueries(1, &mQuery);
stateManager->pauseQuery(queryType);
mFunctions->beginQuery(queryType, mQuery);
mFunctions->endQuery(queryType);
stateManager->resumeQuery(queryType);
}
virtual ~SyncProviderGLQuery() { mFunctions->deleteQueries(1, &mQuery); }
gl::Error flush(bool force, bool *finished) override
{
if (force)
{
GLint result = 0;
mFunctions->getQueryObjectiv(mQuery, GL_QUERY_RESULT, &result);
*finished = true;
}
else
{
GLint available = 0;
mFunctions->getQueryObjectiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &available);
*finished = (available == GL_TRUE);
}
return gl::NoError();
}
private:
const FunctionsGL *mFunctions;
GLuint mQuery;
};
SyncQueryGL::SyncQueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager)
: QueryGL(type),
mFunctions(functions),
mStateManager(stateManager),
mSyncProvider(nullptr),
mFinished(false)
{
ASSERT(IsSupported(mFunctions));
ASSERT(type == GL_COMMANDS_COMPLETED_CHROMIUM);
}
SyncQueryGL::~SyncQueryGL()
{
}
bool SyncQueryGL::IsSupported(const FunctionsGL *functions)
{
return nativegl::SupportsFenceSync(functions) || nativegl::SupportsOcclusionQueries(functions);
}
gl::Error SyncQueryGL::begin()
{
return gl::NoError();
}
gl::Error SyncQueryGL::end()
{
if (nativegl::SupportsFenceSync(mFunctions))
{
mSyncProvider.reset(new SyncProviderGLSync(mFunctions));
}
else if (nativegl::SupportsOcclusionQueries(mFunctions))
{
mSyncProvider.reset(
new SyncProviderGLQuery(mFunctions, mStateManager, GL_ANY_SAMPLES_PASSED));
}
else
{
ASSERT(false);
return gl::Error(GL_INVALID_OPERATION, "No native support for sync queries.");
}
return gl::NoError();
}
gl::Error SyncQueryGL::queryCounter()
{
UNREACHABLE();
return gl::NoError();
}
gl::Error SyncQueryGL::getResult(GLint *params)
{
return getResultBase(params);
}
gl::Error SyncQueryGL::getResult(GLuint *params)
{
return getResultBase(params);
}
gl::Error SyncQueryGL::getResult(GLint64 *params)
{
return getResultBase(params);
}
gl::Error SyncQueryGL::getResult(GLuint64 *params)
{
return getResultBase(params);
}
gl::Error SyncQueryGL::isResultAvailable(bool *available)
{
ANGLE_TRY(flush(false));
*available = mFinished;
return gl::NoError();
}
gl::Error SyncQueryGL::pause()
{
return gl::NoError();
}
gl::Error SyncQueryGL::resume()
{
return gl::NoError();
}
gl::Error SyncQueryGL::flush(bool force)
{
if (mSyncProvider == nullptr)
{
ASSERT(mFinished);
return gl::NoError();
}
ANGLE_TRY(mSyncProvider->flush(force, &mFinished));
if (mFinished)
{
mSyncProvider.reset();
}
return gl::NoError();
}
template <typename T>
gl::Error SyncQueryGL::getResultBase(T *params)
{
ANGLE_TRY(flush(true));
*params = static_cast<T>(mFinished ? GL_TRUE : GL_FALSE);
return gl::NoError();
}
}
......@@ -22,9 +22,25 @@ class StateManagerGL;
class QueryGL : public QueryImpl
{
public:
QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager);
QueryGL(GLenum type);
~QueryGL() override;
// OpenGL is only allowed to have one query of each type active at any given time. Since ANGLE
// virtualizes contexts, queries need to be able to be paused and resumed.
// A query is "paused" by ending it and pushing the ID into a list of queries awaiting readback.
// When it is "resumed", a new query is generated and started.
// When a result is required, the queries are "flushed" by iterating over the list of pending
// queries and merging their results.
virtual gl::Error pause() = 0;
virtual gl::Error resume() = 0;
};
class StandardQueryGL : public QueryGL
{
public:
StandardQueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager);
~StandardQueryGL() override;
gl::Error begin() override;
gl::Error end() override;
gl::Error queryCounter() override;
......@@ -34,14 +50,8 @@ class QueryGL : public QueryImpl
gl::Error getResult(GLuint64 *params) override;
gl::Error isResultAvailable(bool *available) override;
// OpenGL is only allowed to have one query of each type active at any given time. Since ANGLE
// virtualizes contexts, queries need to be able to be paused and resumed.
// A query is "paused" by ending it and pushing the ID into a list of queries awaiting readback.
// When it is "resumed", a new query is generated and started.
// When a result is required, the queries are "flushed" by iterating over the list of pending
// queries and merging their results.
gl::Error pause();
gl::Error resume();
gl::Error pause() override;
gl::Error resume() override;
private:
gl::Error flush(bool force);
......@@ -59,6 +69,39 @@ class QueryGL : public QueryImpl
GLuint64 mResultSum;
};
class SyncProviderGL;
class SyncQueryGL : public QueryGL
{
public:
SyncQueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager);
~SyncQueryGL() override;
static bool IsSupported(const FunctionsGL *functions);
gl::Error begin() override;
gl::Error end() override;
gl::Error queryCounter() override;
gl::Error getResult(GLint *params) override;
gl::Error getResult(GLuint *params) override;
gl::Error getResult(GLint64 *params) override;
gl::Error getResult(GLuint64 *params) override;
gl::Error isResultAvailable(bool *available) override;
gl::Error pause() override;
gl::Error resume() override;
private:
gl::Error flush(bool force);
template <typename T>
gl::Error getResultBase(T *params);
const FunctionsGL *mFunctions;
StateManagerGL *mStateManager;
std::unique_ptr<SyncProviderGL> mSyncProvider;
bool mFinished;
};
}
#endif // LIBANGLE_RENDERER_GL_QUERYGL_H_
......@@ -670,14 +670,26 @@ void StateManagerGL::pauseTransformFeedback()
}
}
void StateManagerGL::pauseQueries()
void StateManagerGL::pauseAllQueries()
{
for (QueryGL *prevQuery : mCurrentQueries)
{
prevQuery->pause();
}
}
void StateManagerGL::resumeQueries()
void StateManagerGL::pauseQuery(GLenum type)
{
for (QueryGL *prevQuery : mCurrentQueries)
{
if (prevQuery->getType() == type)
{
prevQuery->pause();
}
}
}
void StateManagerGL::resumeAllQueries()
{
for (QueryGL *prevQuery : mCurrentQueries)
{
......@@ -685,6 +697,17 @@ void StateManagerGL::resumeQueries()
}
}
void StateManagerGL::resumeQuery(GLenum type)
{
for (QueryGL *prevQuery : mCurrentQueries)
{
if (prevQuery->getType() == type)
{
prevQuery->resume();
}
}
}
gl::Error StateManagerGL::onMakeCurrent(const gl::ContextState &data)
{
const gl::State &state = data.getState();
......@@ -692,7 +715,7 @@ gl::Error StateManagerGL::onMakeCurrent(const gl::ContextState &data)
// If the context has changed, pause the previous context's queries
if (data.getContext() != mPrevDrawContext)
{
pauseQueries();
pauseAllQueries();
}
mCurrentQueries.clear();
mPrevDrawTransformFeedback = nullptr;
......
......@@ -151,8 +151,10 @@ class StateManagerGL final : angle::NonCopyable
const GLvoid **outIndices);
void pauseTransformFeedback();
void pauseQueries();
void resumeQueries();
void pauseAllQueries();
void pauseQuery(GLenum type);
void resumeAllQueries();
void resumeQuery(GLenum type);
gl::Error onMakeCurrent(const gl::ContextState &data);
void syncState(const gl::State &state, const gl::State::DirtyBits &glDirtyBits);
......
......@@ -16,6 +16,7 @@
#include "libANGLE/Caps.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/QueryGL.h"
#include "libANGLE/renderer/gl/WorkaroundsGL.h"
#include "libANGLE/renderer/gl/formatutilsgl.h"
......@@ -797,11 +798,7 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_draw_buffers");
extensions->textureStorage = true;
extensions->textureFilterAnisotropic = functions->hasGLExtension("GL_EXT_texture_filter_anisotropic") || functions->hasGLESExtension("GL_EXT_texture_filter_anisotropic");
extensions->occlusionQueryBoolean =
functions->isAtLeastGL(gl::Version(1, 5)) ||
functions->hasGLExtension("GL_ARB_occlusion_query2") ||
functions->isAtLeastGLES(gl::Version(3, 0)) ||
functions->hasGLESExtension("GL_EXT_occlusion_query_boolean");
extensions->occlusionQueryBoolean = nativegl::SupportsOcclusionQueries(functions);
extensions->maxTextureAnisotropy = extensions->textureFilterAnisotropic ? QuerySingleGLFloat(functions, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0.0f;
extensions->fence = functions->hasGLExtension("GL_NV_fence") || functions->hasGLESExtension("GL_NV_fence");
extensions->blendMinMax = functions->isAtLeastGL(gl::Version(1, 5)) || functions->hasGLExtension("GL_EXT_blend_minmax") ||
......@@ -860,6 +857,7 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
functions->hasGLESExtension("GL_EXT_robustness");
extensions->copyTexture = true;
extensions->syncQuery = SyncQueryGL::IsSupported(functions);
// NV_path_rendering
// We also need interface query which is available in
......@@ -963,6 +961,23 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround
}
namespace nativegl
{
bool SupportsFenceSync(const FunctionsGL *functions)
{
return functions->isAtLeastGL(gl::Version(3, 2)) || functions->hasGLExtension("GL_ARB_sync") ||
functions->isAtLeastGLES(gl::Version(3, 0));
}
bool SupportsOcclusionQueries(const FunctionsGL *functions)
{
return functions->isAtLeastGL(gl::Version(1, 5)) ||
functions->hasGLExtension("GL_ARB_occlusion_query2") ||
functions->isAtLeastGLES(gl::Version(3, 0)) ||
functions->hasGLESExtension("GL_EXT_occlusion_query_boolean");
}
}
bool CanMapBufferForRead(const FunctionsGL *functions)
{
return (functions->mapBufferRange != nullptr) ||
......
......@@ -43,6 +43,12 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds);
}
namespace nativegl
{
bool SupportsFenceSync(const FunctionsGL *functions);
bool SupportsOcclusionQueries(const FunctionsGL *functions);
}
bool CanMapBufferForRead(const FunctionsGL *functions);
uint8_t *MapBufferRangeWithFallback(const FunctionsGL *functions,
GLenum target,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment