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 ...@@ -84,13 +84,13 @@ class ScopedGLState : public angle::NonCopyable
mStateManager->setRasterizerDiscardEnabled(false); mStateManager->setRasterizerDiscardEnabled(false);
mStateManager->pauseTransformFeedback(); mStateManager->pauseTransformFeedback();
mStateManager->pauseQueries(); mStateManager->pauseAllQueries();
} }
~ScopedGLState() ~ScopedGLState()
{ {
// XFB resuming will be done automatically // XFB resuming will be done automatically
mStateManager->resumeQueries(); mStateManager->resumeAllQueries();
} }
void willUseTextureUnit(int unit) void willUseTextureUnit(int unit)
......
...@@ -90,7 +90,14 @@ VertexArrayImpl *ContextGL::createVertexArray(const gl::VertexArrayState &data) ...@@ -90,7 +90,14 @@ VertexArrayImpl *ContextGL::createVertexArray(const gl::VertexArrayState &data)
QueryImpl *ContextGL::createQuery(GLenum type) 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() FenceNVImpl *ContextGL::createFenceNV()
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "common/debug.h" #include "common/debug.h"
#include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h" #include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/renderergl_utils.h"
namespace namespace
{ {
...@@ -43,8 +44,18 @@ GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResu ...@@ -43,8 +44,18 @@ GLuint64 MergeQueryResults(GLenum type, GLuint64 currentResult, GLuint64 newResu
namespace rx namespace rx
{ {
QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager) QueryGL::QueryGL(GLenum type) : QueryImpl(type)
: QueryImpl(type), {
}
QueryGL::~QueryGL()
{
}
StandardQueryGL::StandardQueryGL(GLenum type,
const FunctionsGL *functions,
StateManagerGL *stateManager)
: QueryGL(type),
mType(type), mType(type),
mFunctions(functions), mFunctions(functions),
mStateManager(stateManager), mStateManager(stateManager),
...@@ -54,7 +65,7 @@ QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stat ...@@ -54,7 +65,7 @@ QueryGL::QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stat
{ {
} }
QueryGL::~QueryGL() StandardQueryGL::~StandardQueryGL()
{ {
mStateManager->deleteQuery(mActiveQuery); mStateManager->deleteQuery(mActiveQuery);
mStateManager->onDeleteQueryObject(this); mStateManager->onDeleteQueryObject(this);
...@@ -65,19 +76,19 @@ QueryGL::~QueryGL() ...@@ -65,19 +76,19 @@ QueryGL::~QueryGL()
} }
} }
gl::Error QueryGL::begin() gl::Error StandardQueryGL::begin()
{ {
mResultSum = 0; mResultSum = 0;
mStateManager->onBeginQuery(this); mStateManager->onBeginQuery(this);
return resume(); return resume();
} }
gl::Error QueryGL::end() gl::Error StandardQueryGL::end()
{ {
return pause(); return pause();
} }
gl::Error QueryGL::queryCounter() gl::Error StandardQueryGL::queryCounter()
{ {
ASSERT(mType == GL_TIMESTAMP); ASSERT(mType == GL_TIMESTAMP);
...@@ -92,7 +103,7 @@ gl::Error QueryGL::queryCounter() ...@@ -92,7 +103,7 @@ gl::Error QueryGL::queryCounter()
} }
template <typename T> template <typename T>
gl::Error QueryGL::getResultBase(T *params) gl::Error StandardQueryGL::getResultBase(T *params)
{ {
ASSERT(mActiveQuery == 0); ASSERT(mActiveQuery == 0);
...@@ -108,27 +119,27 @@ gl::Error QueryGL::getResultBase(T *params) ...@@ -108,27 +119,27 @@ gl::Error QueryGL::getResultBase(T *params)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error QueryGL::getResult(GLint *params) gl::Error StandardQueryGL::getResult(GLint *params)
{ {
return getResultBase(params); return getResultBase(params);
} }
gl::Error QueryGL::getResult(GLuint *params) gl::Error StandardQueryGL::getResult(GLuint *params)
{ {
return getResultBase(params); return getResultBase(params);
} }
gl::Error QueryGL::getResult(GLint64 *params) gl::Error StandardQueryGL::getResult(GLint64 *params)
{ {
return getResultBase(params); return getResultBase(params);
} }
gl::Error QueryGL::getResult(GLuint64 *params) gl::Error StandardQueryGL::getResult(GLuint64 *params)
{ {
return getResultBase(params); return getResultBase(params);
} }
gl::Error QueryGL::isResultAvailable(bool *available) gl::Error StandardQueryGL::isResultAvailable(bool *available)
{ {
ASSERT(mActiveQuery == 0); ASSERT(mActiveQuery == 0);
...@@ -142,7 +153,7 @@ gl::Error QueryGL::isResultAvailable(bool *available) ...@@ -142,7 +153,7 @@ gl::Error QueryGL::isResultAvailable(bool *available)
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error QueryGL::pause() gl::Error StandardQueryGL::pause()
{ {
if (mActiveQuery != 0) if (mActiveQuery != 0)
{ {
...@@ -162,7 +173,7 @@ gl::Error QueryGL::pause() ...@@ -162,7 +173,7 @@ gl::Error QueryGL::pause()
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error QueryGL::resume() gl::Error StandardQueryGL::resume()
{ {
if (mActiveQuery == 0) if (mActiveQuery == 0)
{ {
...@@ -180,7 +191,7 @@ gl::Error QueryGL::resume() ...@@ -180,7 +191,7 @@ gl::Error QueryGL::resume()
return gl::Error(GL_NO_ERROR); return gl::Error(GL_NO_ERROR);
} }
gl::Error QueryGL::flush(bool force) gl::Error StandardQueryGL::flush(bool force)
{ {
while (!mPendingQueries.empty()) while (!mPendingQueries.empty())
{ {
...@@ -219,4 +230,194 @@ gl::Error QueryGL::flush(bool force) ...@@ -219,4 +230,194 @@ gl::Error QueryGL::flush(bool force)
return gl::Error(GL_NO_ERROR); 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; ...@@ -22,9 +22,25 @@ class StateManagerGL;
class QueryGL : public QueryImpl class QueryGL : public QueryImpl
{ {
public: public:
QueryGL(GLenum type, const FunctionsGL *functions, StateManagerGL *stateManager); QueryGL(GLenum type);
~QueryGL() override; ~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 begin() override;
gl::Error end() override; gl::Error end() override;
gl::Error queryCounter() override; gl::Error queryCounter() override;
...@@ -34,14 +50,8 @@ class QueryGL : public QueryImpl ...@@ -34,14 +50,8 @@ class QueryGL : public QueryImpl
gl::Error getResult(GLuint64 *params) override; gl::Error getResult(GLuint64 *params) override;
gl::Error isResultAvailable(bool *available) 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 gl::Error pause() override;
// virtualizes contexts, queries need to be able to be paused and resumed. gl::Error resume() override;
// 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();
private: private:
gl::Error flush(bool force); gl::Error flush(bool force);
...@@ -59,6 +69,39 @@ class QueryGL : public QueryImpl ...@@ -59,6 +69,39 @@ class QueryGL : public QueryImpl
GLuint64 mResultSum; 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_ #endif // LIBANGLE_RENDERER_GL_QUERYGL_H_
...@@ -670,14 +670,26 @@ void StateManagerGL::pauseTransformFeedback() ...@@ -670,14 +670,26 @@ void StateManagerGL::pauseTransformFeedback()
} }
} }
void StateManagerGL::pauseQueries() void StateManagerGL::pauseAllQueries()
{ {
for (QueryGL *prevQuery : mCurrentQueries) for (QueryGL *prevQuery : mCurrentQueries)
{ {
prevQuery->pause(); 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) for (QueryGL *prevQuery : mCurrentQueries)
{ {
...@@ -685,6 +697,17 @@ void StateManagerGL::resumeQueries() ...@@ -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) gl::Error StateManagerGL::onMakeCurrent(const gl::ContextState &data)
{ {
const gl::State &state = data.getState(); const gl::State &state = data.getState();
...@@ -692,7 +715,7 @@ gl::Error StateManagerGL::onMakeCurrent(const gl::ContextState &data) ...@@ -692,7 +715,7 @@ gl::Error StateManagerGL::onMakeCurrent(const gl::ContextState &data)
// If the context has changed, pause the previous context's queries // If the context has changed, pause the previous context's queries
if (data.getContext() != mPrevDrawContext) if (data.getContext() != mPrevDrawContext)
{ {
pauseQueries(); pauseAllQueries();
} }
mCurrentQueries.clear(); mCurrentQueries.clear();
mPrevDrawTransformFeedback = nullptr; mPrevDrawTransformFeedback = nullptr;
......
...@@ -151,8 +151,10 @@ class StateManagerGL final : angle::NonCopyable ...@@ -151,8 +151,10 @@ class StateManagerGL final : angle::NonCopyable
const GLvoid **outIndices); const GLvoid **outIndices);
void pauseTransformFeedback(); void pauseTransformFeedback();
void pauseQueries(); void pauseAllQueries();
void resumeQueries(); void pauseQuery(GLenum type);
void resumeAllQueries();
void resumeQuery(GLenum type);
gl::Error onMakeCurrent(const gl::ContextState &data); gl::Error onMakeCurrent(const gl::ContextState &data);
void syncState(const gl::State &state, const gl::State::DirtyBits &glDirtyBits); void syncState(const gl::State &state, const gl::State::DirtyBits &glDirtyBits);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "libANGLE/Caps.h" #include "libANGLE/Caps.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/QueryGL.h"
#include "libANGLE/renderer/gl/WorkaroundsGL.h" #include "libANGLE/renderer/gl/WorkaroundsGL.h"
#include "libANGLE/renderer/gl/formatutilsgl.h" #include "libANGLE/renderer/gl/formatutilsgl.h"
...@@ -797,11 +798,7 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM ...@@ -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"); functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_draw_buffers");
extensions->textureStorage = true; extensions->textureStorage = true;
extensions->textureFilterAnisotropic = functions->hasGLExtension("GL_EXT_texture_filter_anisotropic") || functions->hasGLESExtension("GL_EXT_texture_filter_anisotropic"); extensions->textureFilterAnisotropic = functions->hasGLExtension("GL_EXT_texture_filter_anisotropic") || functions->hasGLESExtension("GL_EXT_texture_filter_anisotropic");
extensions->occlusionQueryBoolean = extensions->occlusionQueryBoolean = nativegl::SupportsOcclusionQueries(functions);
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->maxTextureAnisotropy = extensions->textureFilterAnisotropic ? QuerySingleGLFloat(functions, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0.0f; 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->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") || 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 ...@@ -860,6 +857,7 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
functions->hasGLESExtension("GL_EXT_robustness"); functions->hasGLESExtension("GL_EXT_robustness");
extensions->copyTexture = true; extensions->copyTexture = true;
extensions->syncQuery = SyncQueryGL::IsSupported(functions);
// NV_path_rendering // NV_path_rendering
// We also need interface query which is available in // We also need interface query which is available in
...@@ -963,6 +961,23 @@ void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workaround ...@@ -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) bool CanMapBufferForRead(const FunctionsGL *functions)
{ {
return (functions->mapBufferRange != nullptr) || return (functions->mapBufferRange != nullptr) ||
......
...@@ -43,6 +43,12 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM ...@@ -43,6 +43,12 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds); void GenerateWorkarounds(const FunctionsGL *functions, WorkaroundsGL *workarounds);
} }
namespace nativegl
{
bool SupportsFenceSync(const FunctionsGL *functions);
bool SupportsOcclusionQueries(const FunctionsGL *functions);
}
bool CanMapBufferForRead(const FunctionsGL *functions); bool CanMapBufferForRead(const FunctionsGL *functions);
uint8_t *MapBufferRangeWithFallback(const FunctionsGL *functions, uint8_t *MapBufferRangeWithFallback(const FunctionsGL *functions,
GLenum target, 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