summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libANGLE/Context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/Context.cpp')
-rw-r--r--src/3rdparty/angle/src/libANGLE/Context.cpp1333
1 files changed, 1085 insertions, 248 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/Context.cpp b/src/3rdparty/angle/src/libANGLE/Context.cpp
index 1da5fdae95..26f2970068 100644
--- a/src/3rdparty/angle/src/libANGLE/Context.cpp
+++ b/src/3rdparty/angle/src/libANGLE/Context.cpp
@@ -33,22 +33,124 @@
#include "libANGLE/validationES.h"
#include "libANGLE/renderer/Renderer.h"
-namespace gl
+namespace
+{
+
+template <typename T>
+gl::Error GetQueryObjectParameter(gl::Context *context, GLuint id, GLenum pname, T *params)
+{
+ gl::Query *queryObject = context->getQuery(id, false, GL_NONE);
+ ASSERT(queryObject != nullptr);
+
+ switch (pname)
+ {
+ case GL_QUERY_RESULT_EXT:
+ return queryObject->getResult(params);
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ {
+ bool available;
+ gl::Error error = queryObject->isResultAvailable(&available);
+ if (!error.isError())
+ {
+ *params = static_cast<T>(available ? GL_TRUE : GL_FALSE);
+ }
+ return error;
+ }
+ default:
+ UNREACHABLE();
+ return gl::Error(GL_INVALID_OPERATION, "Unreachable Error");
+ }
+}
+
+void MarkTransformFeedbackBufferUsage(gl::TransformFeedback *transformFeedback)
+{
+ if (transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
+ {
+ for (size_t tfBufferIndex = 0; tfBufferIndex < transformFeedback->getIndexedBufferCount();
+ tfBufferIndex++)
+ {
+ const OffsetBindingPointer<gl::Buffer> &buffer =
+ transformFeedback->getIndexedBuffer(tfBufferIndex);
+ if (buffer.get() != nullptr)
+ {
+ buffer->onTransformFeedback();
+ }
+ }
+ }
+}
+
+// Attribute map queries.
+EGLint GetClientVersion(const egl::AttributeMap &attribs)
+{
+ return attribs.get(EGL_CONTEXT_CLIENT_VERSION, 1);
+}
+
+GLenum GetResetStrategy(const egl::AttributeMap &attribs)
+{
+ EGLenum attrib = attribs.get(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT,
+ EGL_NO_RESET_NOTIFICATION_EXT);
+ switch (attrib)
+ {
+ case EGL_NO_RESET_NOTIFICATION:
+ return GL_NO_RESET_NOTIFICATION_EXT;
+ case EGL_LOSE_CONTEXT_ON_RESET:
+ return GL_LOSE_CONTEXT_ON_RESET_EXT;
+ default:
+ UNREACHABLE();
+ return GL_NONE;
+ }
+}
+
+bool GetRobustAccess(const egl::AttributeMap &attribs)
+{
+ return (attribs.get(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_FALSE) == EGL_TRUE);
+}
+
+bool GetDebug(const egl::AttributeMap &attribs)
{
+ return (attribs.get(EGL_CONTEXT_OPENGL_DEBUG, EGL_FALSE) == EGL_TRUE);
+}
-Context::Context(const egl::Config *config, int clientVersion, const Context *shareContext, rx::Renderer *renderer, bool notifyResets, bool robustAccess)
- : mRenderer(renderer)
+bool GetNoError(const egl::AttributeMap &attribs)
{
- ASSERT(robustAccess == false); // Unimplemented
+ return (attribs.get(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, EGL_FALSE) == EGL_TRUE);
+}
- initCaps(clientVersion);
- mState.initialize(mCaps, clientVersion);
+} // anonymous namespace
- mClientVersion = clientVersion;
+namespace gl
+{
- mConfigID = config->configID;
- mClientType = EGL_OPENGL_ES_API;
- mRenderBuffer = EGL_NONE;
+Context::Context(const egl::Config *config,
+ const Context *shareContext,
+ rx::Renderer *renderer,
+ const egl::AttributeMap &attribs)
+ : ValidationContext(GetClientVersion(attribs),
+ mState,
+ mCaps,
+ mTextureCaps,
+ mExtensions,
+ nullptr,
+ mLimitations,
+ GetNoError(attribs)),
+ mCompiler(nullptr),
+ mRenderer(renderer),
+ mClientVersion(GetClientVersion(attribs)),
+ mConfig(config),
+ mClientType(EGL_OPENGL_ES_API),
+ mHasBeenCurrent(false),
+ mContextLost(false),
+ mResetStatus(GL_NO_ERROR),
+ mResetStrategy(GetResetStrategy(attribs)),
+ mRobustAccess(GetRobustAccess(attribs)),
+ mCurrentSurface(nullptr),
+ mResourceManager(nullptr)
+{
+ ASSERT(!mRobustAccess); // Unimplemented
+
+ initCaps(mClientVersion);
+
+ mState.initialize(mCaps, mExtensions, mClientVersion, GetDebug(attribs));
mFenceNVHandleAllocator.setBaseHandle(0);
@@ -62,6 +164,8 @@ Context::Context(const egl::Config *config, int clientVersion, const Context *sh
mResourceManager = new ResourceManager(mRenderer);
}
+ mData.resourceManager = mResourceManager;
+
// [OpenGL ES 2.0.24] section 3.7 page 83:
// In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional
// and cube map texture state vectors respectively associated with them.
@@ -90,8 +194,6 @@ Context::Context(const egl::Config *config, int clientVersion, const Context *sh
bindArrayBuffer(0);
bindElementArrayBuffer(0);
- bindReadFramebuffer(0);
- bindDrawFramebuffer(0);
bindRenderbuffer(0);
bindGenericUniformBuffer(0);
@@ -100,70 +202,73 @@ Context::Context(const egl::Config *config, int clientVersion, const Context *sh
bindIndexedUniformBuffer(0, i, 0, -1);
}
- bindGenericTransformFeedbackBuffer(0);
- for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++)
- {
- bindIndexedTransformFeedbackBuffer(0, i, 0, -1);
- }
-
bindCopyReadBuffer(0);
bindCopyWriteBuffer(0);
bindPixelPackBuffer(0);
bindPixelUnpackBuffer(0);
- // [OpenGL ES 3.0.2] section 2.14.1 pg 85:
- // In the initial state, a default transform feedback object is bound and treated as
- // a transform feedback object with a name of zero. That object is bound any time
- // BindTransformFeedback is called with id of zero
- mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0));
- bindTransformFeedback(0);
-
- mHasBeenCurrent = false;
- mContextLost = false;
- mResetStatus = GL_NO_ERROR;
- mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT);
- mRobustAccess = robustAccess;
+ if (mClientVersion >= 3)
+ {
+ // [OpenGL ES 3.0.2] section 2.14.1 pg 85:
+ // In the initial state, a default transform feedback object is bound and treated as
+ // a transform feedback object with a name of zero. That object is bound any time
+ // BindTransformFeedback is called with id of zero
+ bindTransformFeedback(0);
+ }
- mCompiler = new Compiler(mRenderer->createCompiler(getData()));
+ mCompiler = new Compiler(mRenderer, getData());
}
Context::~Context()
{
mState.reset();
- while (!mFramebufferMap.empty())
+ for (auto framebuffer : mFramebufferMap)
{
- // Delete the framebuffer in reverse order to destroy the framebuffer zero last.
- deleteFramebuffer(mFramebufferMap.rbegin()->first);
+ // Default framebuffer are owned by their respective Surface
+ if (framebuffer.second != nullptr && framebuffer.second->id() != 0)
+ {
+ SafeDelete(framebuffer.second);
+ }
}
- while (!mFenceNVMap.empty())
+ for (auto fence : mFenceNVMap)
{
- deleteFenceNV(mFenceNVMap.begin()->first);
+ SafeDelete(fence.second);
}
- while (!mQueryMap.empty())
+ for (auto query : mQueryMap)
{
- deleteQuery(mQueryMap.begin()->first);
+ if (query.second != nullptr)
+ {
+ query.second->release();
+ }
}
- while (!mVertexArrayMap.empty())
+ for (auto vertexArray : mVertexArrayMap)
{
- deleteVertexArray(mVertexArrayMap.begin()->first);
+ SafeDelete(vertexArray.second);
}
- mTransformFeedbackZero.set(NULL);
- while (!mTransformFeedbackMap.empty())
+ for (auto transformFeedback : mTransformFeedbackMap)
{
- deleteTransformFeedback(mTransformFeedbackMap.begin()->first);
+ if (transformFeedback.second != nullptr)
+ {
+ transformFeedback.second->release();
+ }
}
- for (auto it = mZeroTextures.begin(); it != mZeroTextures.end(); ++it)
+ for (auto &zeroTexture : mZeroTextures)
{
- it->second.set(NULL);
+ zeroTexture.second.set(NULL);
}
mZeroTextures.clear();
+ if (mCurrentSurface != nullptr)
+ {
+ releaseSurface();
+ }
+
if (mResourceManager)
{
mResourceManager->release();
@@ -174,6 +279,8 @@ Context::~Context()
void Context::makeCurrent(egl::Surface *surface)
{
+ ASSERT(surface != nullptr);
+
if (!mHasBeenCurrent)
{
initRendererString();
@@ -185,12 +292,55 @@ void Context::makeCurrent(egl::Surface *surface)
mHasBeenCurrent = true;
}
- // TODO(jmadill): do not allocate new pointers here
- Framebuffer *framebufferZero = new DefaultFramebuffer(mCaps, mRenderer, surface);
+ // TODO(jmadill): Rework this when we support ContextImpl
+ mState.setAllDirtyBits();
- setFramebufferZero(framebufferZero);
+ if (mCurrentSurface)
+ {
+ releaseSurface();
+ }
+ surface->setIsCurrent(true);
+ mCurrentSurface = surface;
+
+ // Update default framebuffer, the binding of the previous default
+ // framebuffer (or lack of) will have a nullptr.
+ {
+ Framebuffer *newDefault = surface->getDefaultFramebuffer();
+ if (mState.getReadFramebuffer() == nullptr)
+ {
+ mState.setReadFramebufferBinding(newDefault);
+ }
+ if (mState.getDrawFramebuffer() == nullptr)
+ {
+ mState.setDrawFramebufferBinding(newDefault);
+ }
+ mFramebufferMap[0] = newDefault;
+ }
- mRenderBuffer = surface->getRenderBuffer();
+ // Notify the renderer of a context switch
+ mRenderer->onMakeCurrent(getData());
+}
+
+void Context::releaseSurface()
+{
+ ASSERT(mCurrentSurface != nullptr);
+
+ // Remove the default framebuffer
+ {
+ Framebuffer *currentDefault = mCurrentSurface->getDefaultFramebuffer();
+ if (mState.getReadFramebuffer() == currentDefault)
+ {
+ mState.setReadFramebufferBinding(nullptr);
+ }
+ if (mState.getDrawFramebuffer() == currentDefault)
+ {
+ mState.setDrawFramebufferBinding(nullptr);
+ }
+ mFramebufferMap.erase(0);
+ }
+
+ mCurrentSurface->setIsCurrent(false);
+ mCurrentSurface = nullptr;
}
// NOTE: this function should not assume that this context is current!
@@ -218,7 +368,7 @@ GLuint Context::createProgram()
GLuint Context::createShader(GLenum type)
{
- return mResourceManager->createShader(getData(), type);
+ return mResourceManager->createShader(mRenderer->getRendererLimitations(), type);
}
GLuint Context::createTexture()
@@ -240,14 +390,9 @@ GLsync Context::createFenceSync()
GLuint Context::createVertexArray()
{
- GLuint handle = mVertexArrayHandleAllocator.allocate();
-
- // Although the spec states VAO state is not initialized until the object is bound,
- // we create it immediately. The resulting behaviour is transparent to the application,
- // since it's not currently possible to access the state until the object is bound.
- VertexArray *vertexArray = new VertexArray(mRenderer->createVertexArray(), handle, MAX_VERTEX_ATTRIBS);
- mVertexArrayMap[handle] = vertexArray;
- return handle;
+ GLuint vertexArray = mVertexArrayHandleAllocator.allocate();
+ mVertexArrayMap[vertexArray] = nullptr;
+ return vertexArray;
}
GLuint Context::createSampler()
@@ -257,11 +402,9 @@ GLuint Context::createSampler()
GLuint Context::createTransformFeedback()
{
- GLuint handle = mTransformFeedbackAllocator.allocate();
- TransformFeedback *transformFeedback = new TransformFeedback(mRenderer->createTransformFeedback(), handle);
- transformFeedback->addRef();
- mTransformFeedbackMap[handle] = transformFeedback;
- return handle;
+ GLuint transformFeedback = mTransformFeedbackAllocator.allocate();
+ mTransformFeedbackMap[transformFeedback] = nullptr;
+ return transformFeedback;
}
// Returns an unused framebuffer name
@@ -339,20 +482,23 @@ void Context::deleteFenceSync(GLsync fenceSync)
// wait commands finish. However, since the name becomes invalid, we cannot query the fence,
// and since our API is currently designed for being called from a single thread, we can delete
// the fence immediately.
- mResourceManager->deleteFenceSync(reinterpret_cast<uintptr_t>(fenceSync));
+ mResourceManager->deleteFenceSync(static_cast<GLuint>(reinterpret_cast<uintptr_t>(fenceSync)));
}
void Context::deleteVertexArray(GLuint vertexArray)
{
- auto vertexArrayObject = mVertexArrayMap.find(vertexArray);
-
- if (vertexArrayObject != mVertexArrayMap.end())
+ auto iter = mVertexArrayMap.find(vertexArray);
+ if (iter != mVertexArrayMap.end())
{
- detachVertexArray(vertexArray);
+ VertexArray *vertexArrayObject = iter->second;
+ if (vertexArrayObject != nullptr)
+ {
+ detachVertexArray(vertexArray);
+ delete vertexArrayObject;
+ }
- mVertexArrayHandleAllocator.release(vertexArrayObject->first);
- delete vertexArrayObject->second;
- mVertexArrayMap.erase(vertexArrayObject);
+ mVertexArrayMap.erase(iter);
+ mVertexArrayHandleAllocator.release(vertexArray);
}
}
@@ -371,10 +517,15 @@ void Context::deleteTransformFeedback(GLuint transformFeedback)
auto iter = mTransformFeedbackMap.find(transformFeedback);
if (iter != mTransformFeedbackMap.end())
{
- detachTransformFeedback(transformFeedback);
- mTransformFeedbackAllocator.release(transformFeedback);
- iter->second->release();
+ TransformFeedback *transformFeedbackObject = iter->second;
+ if (transformFeedbackObject != nullptr)
+ {
+ detachTransformFeedback(transformFeedback);
+ transformFeedbackObject->release();
+ }
+
mTransformFeedbackMap.erase(iter);
+ mTransformFeedbackAllocator.release(transformFeedback);
}
}
@@ -418,7 +569,7 @@ void Context::deleteQuery(GLuint query)
}
}
-Buffer *Context::getBuffer(GLuint handle)
+Buffer *Context::getBuffer(GLuint handle) const
{
return mResourceManager->getBuffer(handle);
}
@@ -438,28 +589,20 @@ Texture *Context::getTexture(GLuint handle) const
return mResourceManager->getTexture(handle);
}
-Renderbuffer *Context::getRenderbuffer(GLuint handle)
+Renderbuffer *Context::getRenderbuffer(GLuint handle) const
{
return mResourceManager->getRenderbuffer(handle);
}
FenceSync *Context::getFenceSync(GLsync handle) const
{
- return mResourceManager->getFenceSync(reinterpret_cast<uintptr_t>(handle));
+ return mResourceManager->getFenceSync(static_cast<GLuint>(reinterpret_cast<uintptr_t>(handle)));
}
VertexArray *Context::getVertexArray(GLuint handle) const
{
auto vertexArray = mVertexArrayMap.find(handle);
-
- if (vertexArray == mVertexArrayMap.end())
- {
- return NULL;
- }
- else
- {
- return vertexArray->second;
- }
+ return (vertexArray != mVertexArrayMap.end()) ? vertexArray->second : nullptr;
}
Sampler *Context::getSampler(GLuint handle) const
@@ -469,17 +612,45 @@ Sampler *Context::getSampler(GLuint handle) const
TransformFeedback *Context::getTransformFeedback(GLuint handle) const
{
- if (handle == 0)
- {
- return mTransformFeedbackZero.get();
- }
- else
+ auto iter = mTransformFeedbackMap.find(handle);
+ return (iter != mTransformFeedbackMap.end()) ? iter->second : nullptr;
+}
+
+LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const
+{
+ switch (identifier)
{
- TransformFeedbackMap::const_iterator iter = mTransformFeedbackMap.find(handle);
- return (iter != mTransformFeedbackMap.end()) ? iter->second : NULL;
+ case GL_BUFFER:
+ return getBuffer(name);
+ case GL_SHADER:
+ return getShader(name);
+ case GL_PROGRAM:
+ return getProgram(name);
+ case GL_VERTEX_ARRAY:
+ return getVertexArray(name);
+ case GL_QUERY:
+ return getQuery(name);
+ case GL_TRANSFORM_FEEDBACK:
+ return getTransformFeedback(name);
+ case GL_SAMPLER:
+ return getSampler(name);
+ case GL_TEXTURE:
+ return getTexture(name);
+ case GL_RENDERBUFFER:
+ return getRenderbuffer(name);
+ case GL_FRAMEBUFFER:
+ return getFramebuffer(name);
+ default:
+ UNREACHABLE();
+ return nullptr;
}
}
+LabeledObject *Context::getLabeledObjectFromPtr(const void *ptr) const
+{
+ return getFenceSync(reinterpret_cast<GLsync>(const_cast<void *>(ptr)));
+}
+
bool Context::isSampler(GLuint samplerName) const
{
return mResourceManager->isSampler(samplerName);
@@ -518,24 +689,16 @@ void Context::bindTexture(GLenum target, GLuint handle)
mState.setSamplerTexture(target, texture);
}
-void Context::bindReadFramebuffer(GLuint framebuffer)
+void Context::bindReadFramebuffer(GLuint framebufferHandle)
{
- if (!getFramebuffer(framebuffer))
- {
- mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer);
- }
-
- mState.setReadFramebufferBinding(getFramebuffer(framebuffer));
+ Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle);
+ mState.setReadFramebufferBinding(framebuffer);
}
-void Context::bindDrawFramebuffer(GLuint framebuffer)
+void Context::bindDrawFramebuffer(GLuint framebufferHandle)
{
- if (!getFramebuffer(framebuffer))
- {
- mFramebufferMap[framebuffer] = new Framebuffer(mCaps, mRenderer, framebuffer);
- }
-
- mState.setDrawFramebufferBinding(getFramebuffer(framebuffer));
+ Framebuffer *framebuffer = checkFramebufferAllocation(framebufferHandle);
+ mState.setDrawFramebufferBinding(framebuffer);
}
void Context::bindRenderbuffer(GLuint renderbuffer)
@@ -547,11 +710,7 @@ void Context::bindRenderbuffer(GLuint renderbuffer)
void Context::bindVertexArray(GLuint vertexArray)
{
- if (!getVertexArray(vertexArray))
- {
- VertexArray *vertexArrayObject = new VertexArray(mRenderer->createVertexArray(), vertexArray, MAX_VERTEX_ATTRIBS);
- mVertexArrayMap[vertexArray] = vertexArrayObject;
- }
+ checkVertexArrayAllocation(vertexArray);
mState.setVertexArrayBinding(getVertexArray(vertexArray));
}
@@ -582,14 +741,14 @@ void Context::bindGenericTransformFeedbackBuffer(GLuint buffer)
{
mResourceManager->checkBufferAllocation(buffer);
- mState.setGenericTransformFeedbackBufferBinding(getBuffer(buffer));
+ mState.getCurrentTransformFeedback()->bindGenericBuffer(getBuffer(buffer));
}
void Context::bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size)
{
mResourceManager->checkBufferAllocation(buffer);
- mState.setIndexedTransformFeedbackBufferBinding(index, getBuffer(buffer), offset, size);
+ mState.getCurrentTransformFeedback()->bindIndexedBuffer(index, getBuffer(buffer), offset, size);
}
void Context::bindCopyReadBuffer(GLuint buffer)
@@ -627,6 +786,8 @@ void Context::useProgram(GLuint program)
void Context::bindTransformFeedback(GLuint transformFeedback)
{
+ checkTransformFeedbackAllocation(transformFeedback);
+
mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback));
}
@@ -661,37 +822,68 @@ Error Context::endQuery(GLenum target)
return error;
}
-void Context::setFramebufferZero(Framebuffer *buffer)
+Error Context::queryCounter(GLuint id, GLenum target)
{
- // First, check to see if the old default framebuffer
- // was set for draw or read framebuffer, and change
- // the bindings to point to the new one before deleting it.
- if (mState.getDrawFramebuffer()->id() == 0)
- {
- mState.setDrawFramebufferBinding(buffer);
- }
+ ASSERT(target == GL_TIMESTAMP_EXT);
+
+ Query *queryObject = getQuery(id, true, target);
+ ASSERT(queryObject);
+
+ return queryObject->queryCounter();
+}
- if (mState.getReadFramebuffer()->id() == 0)
+void Context::getQueryiv(GLenum target, GLenum pname, GLint *params)
+{
+ switch (pname)
{
- mState.setReadFramebufferBinding(buffer);
+ case GL_CURRENT_QUERY_EXT:
+ params[0] = getState().getActiveQueryId(target);
+ break;
+ case GL_QUERY_COUNTER_BITS_EXT:
+ switch (target)
+ {
+ case GL_TIME_ELAPSED_EXT:
+ params[0] = getExtensions().queryCounterBitsTimeElapsed;
+ break;
+ case GL_TIMESTAMP_EXT:
+ params[0] = getExtensions().queryCounterBitsTimestamp;
+ break;
+ default:
+ UNREACHABLE();
+ params[0] = 0;
+ break;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ return;
}
+}
- delete mFramebufferMap[0];
- mFramebufferMap[0] = buffer;
+Error Context::getQueryObjectiv(GLuint id, GLenum pname, GLint *params)
+{
+ return GetQueryObjectParameter(this, id, pname, params);
}
-Framebuffer *Context::getFramebuffer(unsigned int handle) const
+Error Context::getQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
{
- FramebufferMap::const_iterator framebuffer = mFramebufferMap.find(handle);
+ return GetQueryObjectParameter(this, id, pname, params);
+}
- if (framebuffer == mFramebufferMap.end())
- {
- return NULL;
- }
- else
- {
- return framebuffer->second;
- }
+Error Context::getQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params)
+{
+ return GetQueryObjectParameter(this, id, pname, params);
+}
+
+Error Context::getQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params)
+{
+ return GetQueryObjectParameter(this, id, pname, params);
+}
+
+Framebuffer *Context::getFramebuffer(unsigned int handle) const
+{
+ auto framebufferIt = mFramebufferMap.find(handle);
+ return ((framebufferIt == mFramebufferMap.end()) ? nullptr : framebufferIt->second);
}
FenceNV *Context::getFenceNV(unsigned int handle)
@@ -727,11 +919,16 @@ Query *Context::getQuery(unsigned int handle, bool create, GLenum type)
}
}
+Query *Context::getQuery(GLuint handle) const
+{
+ auto iter = mQueryMap.find(handle);
+ return (iter != mQueryMap.end()) ? iter->second : nullptr;
+}
+
Texture *Context::getTargetTexture(GLenum target) const
{
ASSERT(ValidTextureTarget(this, target));
-
- return getSamplerTexture(mState.getActiveSampler(), target);
+ return mState.getTargetTexture(target);
}
Texture *Context::getSamplerTexture(unsigned int sampler, GLenum type) const
@@ -774,6 +971,9 @@ void Context::getFloatv(GLenum pname, GLfloat *params)
ASSERT(mExtensions.textureFilterAnisotropic);
*params = mExtensions.maxTextureAnisotropy;
break;
+ case GL_MAX_TEXTURE_LOD_BIAS:
+ *params = mCaps.maxLODBias;
+ break;
default:
mState.getFloatv(pname, params);
break;
@@ -796,7 +996,7 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxVertexTextureImageUnits; break;
case GL_MAX_TEXTURE_IMAGE_UNITS: *params = mCaps.maxTextureImageUnits; break;
case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = mCaps.maxFragmentUniformVectors; break;
- case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break;
+ case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: *params = mCaps.maxFragmentUniformComponents; break;
case GL_MAX_RENDERBUFFER_SIZE: *params = mCaps.maxRenderbufferSize; break;
case GL_MAX_COLOR_ATTACHMENTS_EXT: *params = mCaps.maxColorAttachments; break;
case GL_MAX_DRAW_BUFFERS_EXT: *params = mCaps.maxDrawBuffers; break;
@@ -811,6 +1011,10 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_VERTEX_UNIFORM_BLOCKS: *params = mCaps.maxVertexUniformBlocks; break;
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: *params = mCaps.maxFragmentUniformBlocks; break;
case GL_MAX_COMBINED_UNIFORM_BLOCKS: *params = mCaps.maxCombinedTextureImageUnits; break;
+ case GL_MAX_VERTEX_OUTPUT_COMPONENTS: *params = mCaps.maxVertexOutputComponents; break;
+ case GL_MAX_FRAGMENT_INPUT_COMPONENTS: *params = mCaps.maxFragmentInputComponents; break;
+ case GL_MIN_PROGRAM_TEXEL_OFFSET: *params = mCaps.minProgramTexelOffset; break;
+ case GL_MAX_PROGRAM_TEXEL_OFFSET: *params = mCaps.maxProgramTexelOffset; break;
case GL_MAJOR_VERSION: *params = mClientVersion; break;
case GL_MINOR_VERSION: *params = 0; break;
case GL_MAX_ELEMENTS_INDICES: *params = mCaps.maxElementsIndices; break;
@@ -818,8 +1022,10 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: *params = mCaps.maxTransformFeedbackInterleavedComponents; break;
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: *params = mCaps.maxTransformFeedbackSeparateAttributes; break;
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: *params = mCaps.maxTransformFeedbackSeparateComponents; break;
- case GL_NUM_COMPRESSED_TEXTURE_FORMATS: *params = mCaps.compressedTextureFormats.size(); break;
- case GL_MAX_SAMPLES_ANGLE: *params = mExtensions.maxSamples; break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ *params = static_cast<GLint>(mCaps.compressedTextureFormats.size());
+ break;
+ case GL_MAX_SAMPLES_ANGLE: *params = mCaps.maxSamples; break;
case GL_MAX_VIEWPORT_DIMS:
{
params[0] = mCaps.maxViewportWidth;
@@ -833,13 +1039,13 @@ void Context::getIntegerv(GLenum pname, GLint *params)
*params = mResetStrategy;
break;
case GL_NUM_SHADER_BINARY_FORMATS:
- *params = mCaps.shaderBinaryFormats.size();
+ *params = static_cast<GLint>(mCaps.shaderBinaryFormats.size());
break;
case GL_SHADER_BINARY_FORMATS:
std::copy(mCaps.shaderBinaryFormats.begin(), mCaps.shaderBinaryFormats.end(), params);
break;
case GL_NUM_PROGRAM_BINARY_FORMATS:
- *params = mCaps.programBinaryFormats.size();
+ *params = static_cast<GLint>(mCaps.programBinaryFormats.size());
break;
case GL_PROGRAM_BINARY_FORMATS:
std::copy(mCaps.programBinaryFormats.begin(), mCaps.programBinaryFormats.end(), params);
@@ -847,6 +1053,26 @@ void Context::getIntegerv(GLenum pname, GLint *params)
case GL_NUM_EXTENSIONS:
*params = static_cast<GLint>(mExtensionStrings.size());
break;
+
+ // GL_KHR_debug
+ case GL_MAX_DEBUG_MESSAGE_LENGTH:
+ *params = mExtensions.maxDebugMessageLength;
+ break;
+ case GL_MAX_DEBUG_LOGGED_MESSAGES:
+ *params = mExtensions.maxDebugLoggedMessages;
+ break;
+ case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
+ *params = mExtensions.maxDebugGroupStackDepth;
+ break;
+ case GL_MAX_LABEL_LENGTH:
+ *params = mExtensions.maxLabelLength;
+ break;
+
+ // GL_EXT_disjoint_timer_query
+ case GL_GPU_DISJOINT_EXT:
+ *params = mRenderer->getGPUDisjoint();
+ break;
+
default:
mState.getIntegerv(getData(), pname, params);
break;
@@ -874,17 +1100,27 @@ void Context::getInteger64v(GLenum pname, GLint64 *params)
case GL_MAX_SERVER_WAIT_TIMEOUT:
*params = mCaps.maxServerWaitTimeout;
break;
+
+ // GL_EXT_disjoint_timer_query
+ case GL_TIMESTAMP_EXT:
+ *params = mRenderer->getTimestamp();
+ break;
default:
UNREACHABLE();
break;
}
}
+void Context::getPointerv(GLenum pname, void **params) const
+{
+ mState.getPointerv(pname, params);
+}
+
bool Context::getIndexedIntegerv(GLenum target, GLuint index, GLint *data)
{
// Queries about context capabilities and maximums are answered by Context.
// Queries about current GL state values are answered by State.
- // Indexed integer queries all refer to current state, so this function is a
+ // Indexed integer queries all refer to current state, so this function is a
// mere passthrough.
return mState.getIndexedIntegerv(target, index, data);
}
@@ -893,7 +1129,7 @@ bool Context::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data)
{
// Queries about context capabilities and maximums are answered by Context.
// Queries about current GL state values are answered by State.
- // Indexed integer queries all refer to current state, so this function is a
+ // Indexed integer queries all refer to current state, so this function is a
// mere passthrough.
return mState.getIndexedInteger64v(target, index, data);
}
@@ -919,19 +1155,19 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_COMPRESSED_TEXTURE_FORMATS:
{
*type = GL_INT;
- *numParams = mCaps.compressedTextureFormats.size();
+ *numParams = static_cast<unsigned int>(mCaps.compressedTextureFormats.size());
}
return true;
case GL_PROGRAM_BINARY_FORMATS_OES:
{
*type = GL_INT;
- *numParams = mCaps.programBinaryFormats.size();
+ *numParams = static_cast<unsigned int>(mCaps.programBinaryFormats.size());
}
return true;
case GL_SHADER_BINARY_FORMATS:
{
*type = GL_INT;
- *numParams = mCaps.shaderBinaryFormats.size();
+ *numParams = static_cast<unsigned int>(mCaps.shaderBinaryFormats.size());
}
return true;
@@ -1019,20 +1255,6 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
}
}
return true;
- case GL_PIXEL_PACK_BUFFER_BINDING:
- case GL_PIXEL_UNPACK_BUFFER_BINDING:
- {
- if (mExtensions.pixelBufferObject)
- {
- *type = GL_INT;
- *numParams = 1;
- }
- else
- {
- return false;
- }
- }
- return true;
case GL_MAX_VIEWPORT_DIMS:
{
*type = GL_INT;
@@ -1103,6 +1325,87 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
*type = GL_FLOAT;
*numParams = 1;
return true;
+ case GL_TIMESTAMP_EXT:
+ if (!mExtensions.disjointTimerQuery)
+ {
+ return false;
+ }
+ *type = GL_INT_64_ANGLEX;
+ *numParams = 1;
+ return true;
+ case GL_GPU_DISJOINT_EXT:
+ if (!mExtensions.disjointTimerQuery)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ }
+
+ if (mExtensions.debug)
+ {
+ switch (pname)
+ {
+ case GL_DEBUG_LOGGED_MESSAGES:
+ case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH:
+ case GL_DEBUG_GROUP_STACK_DEPTH:
+ case GL_MAX_DEBUG_MESSAGE_LENGTH:
+ case GL_MAX_DEBUG_LOGGED_MESSAGES:
+ case GL_MAX_DEBUG_GROUP_STACK_DEPTH:
+ case GL_MAX_LABEL_LENGTH:
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+
+ case GL_DEBUG_OUTPUT_SYNCHRONOUS:
+ case GL_DEBUG_OUTPUT:
+ *type = GL_BOOL;
+ *numParams = 1;
+ return true;
+ }
+ }
+
+ // Check for ES3.0+ parameter names which are also exposed as ES2 extensions
+ switch (pname)
+ {
+ case GL_PACK_ROW_LENGTH:
+ case GL_PACK_SKIP_ROWS:
+ case GL_PACK_SKIP_PIXELS:
+ if ((mClientVersion < 3) && !mExtensions.packSubimage)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ case GL_UNPACK_ROW_LENGTH:
+ case GL_UNPACK_SKIP_ROWS:
+ case GL_UNPACK_SKIP_PIXELS:
+ if ((mClientVersion < 3) && !mExtensions.unpackSubimage)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ case GL_VERTEX_ARRAY_BINDING:
+ if ((mClientVersion < 3) && !mExtensions.vertexArrayObject)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
+ case GL_PIXEL_PACK_BUFFER_BINDING:
+ case GL_PIXEL_UNPACK_BUFFER_BINDING:
+ if ((mClientVersion < 3) && !mExtensions.pixelBufferObject)
+ {
+ return false;
+ }
+ *type = GL_INT;
+ *numParams = 1;
+ return true;
}
if (mClientVersion < 3)
@@ -1117,6 +1420,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
case GL_UNIFORM_BUFFER_BINDING:
case GL_TRANSFORM_FEEDBACK_BINDING:
+ case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
case GL_COPY_READ_BUFFER_BINDING:
case GL_COPY_WRITE_BUFFER_BINDING:
case GL_TEXTURE_BINDING_3D:
@@ -1126,10 +1430,13 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_MAX_VERTEX_UNIFORM_BLOCKS:
case GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
case GL_MAX_COMBINED_UNIFORM_BLOCKS:
+ case GL_MAX_VERTEX_OUTPUT_COMPONENTS:
+ case GL_MAX_FRAGMENT_INPUT_COMPONENTS:
case GL_MAX_VARYING_COMPONENTS:
- case GL_VERTEX_ARRAY_BINDING:
case GL_MAX_VERTEX_UNIFORM_COMPONENTS:
case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
+ case GL_MIN_PROGRAM_TEXEL_OFFSET:
+ case GL_MAX_PROGRAM_TEXEL_OFFSET:
case GL_NUM_EXTENSIONS:
case GL_MAJOR_VERSION:
case GL_MINOR_VERSION:
@@ -1138,6 +1445,8 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS:
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS:
+ case GL_UNPACK_IMAGE_HEIGHT:
+ case GL_UNPACK_SKIP_IMAGES:
{
*type = GL_INT;
*numParams = 1;
@@ -1157,11 +1466,20 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_TRANSFORM_FEEDBACK_ACTIVE:
case GL_TRANSFORM_FEEDBACK_PAUSED:
+ case GL_PRIMITIVE_RESTART_FIXED_INDEX:
+ case GL_RASTERIZER_DISCARD:
{
*type = GL_BOOL;
*numParams = 1;
}
return true;
+
+ case GL_MAX_TEXTURE_LOD_BIAS:
+ {
+ *type = GL_FLOAT;
+ *numParams = 1;
+ }
+ return true;
}
return false;
@@ -1196,16 +1514,67 @@ bool Context::getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned
return false;
}
-Error Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
+Error Context::drawArrays(GLenum mode, GLint first, GLsizei count)
{
- return mRenderer->drawArrays(getData(), mode, first, count, instances);
+ syncRendererState();
+ Error error = mRenderer->drawArrays(getData(), mode, first, count);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback());
+
+ return Error(GL_NO_ERROR);
}
-Error Context::drawElements(GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei instances,
- const rx::RangeUI &indexRange)
+Error Context::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
{
- return mRenderer->drawElements(getData(), mode, count, type, indices, instances, indexRange);
+ syncRendererState();
+ Error error = mRenderer->drawArraysInstanced(getData(), mode, first, count, instanceCount);
+ if (error.isError())
+ {
+ return error;
+ }
+
+ MarkTransformFeedbackBufferUsage(mState.getCurrentTransformFeedback());
+
+ return Error(GL_NO_ERROR);
+}
+
+Error Context::drawElements(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const IndexRange &indexRange)
+{
+ syncRendererState();
+ return mRenderer->drawElements(getData(), mode, count, type, indices, indexRange);
+}
+
+Error Context::drawElementsInstanced(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ GLsizei instances,
+ const IndexRange &indexRange)
+{
+ syncRendererState();
+ return mRenderer->drawElementsInstanced(getData(), mode, count, type, indices, instances,
+ indexRange);
+}
+
+Error Context::drawRangeElements(GLenum mode,
+ GLuint start,
+ GLuint end,
+ GLsizei count,
+ GLenum type,
+ const GLvoid *indices,
+ const IndexRange &indexRange)
+{
+ syncRendererState();
+ return mRenderer->drawRangeElements(getData(), mode, start, end, count, type, indices,
+ indexRange);
}
Error Context::flush()
@@ -1218,11 +1587,36 @@ Error Context::finish()
return mRenderer->finish();
}
+void Context::insertEventMarker(GLsizei length, const char *marker)
+{
+ ASSERT(mRenderer);
+ mRenderer->insertEventMarker(length, marker);
+}
+
+void Context::pushGroupMarker(GLsizei length, const char *marker)
+{
+ ASSERT(mRenderer);
+ mRenderer->pushGroupMarker(length, marker);
+}
+
+void Context::popGroupMarker()
+{
+ ASSERT(mRenderer);
+ mRenderer->popGroupMarker();
+}
+
void Context::recordError(const Error &error)
{
if (error.isError())
{
mErrors.insert(error.getCode());
+
+ if (!error.getMessage().empty())
+ {
+ auto &debug = mState.getDebug();
+ debug.insertMessage(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, error.getID(),
+ GL_DEBUG_SEVERITY_HIGH, error.getMessage());
+ }
}
}
@@ -1275,14 +1669,9 @@ bool Context::isResetNotificationEnabled()
return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
}
-int Context::getClientVersion() const
+const egl::Config *Context::getConfig() const
{
- return mClientVersion;
-}
-
-EGLint Context::getConfigID() const
-{
- return mConfigID;
+ return mConfig;
}
EGLenum Context::getClientType() const
@@ -1292,22 +1681,73 @@ EGLenum Context::getClientType() const
EGLenum Context::getRenderBuffer() const
{
- return mRenderBuffer;
+ auto framebufferIt = mFramebufferMap.find(0);
+ if (framebufferIt != mFramebufferMap.end())
+ {
+ const Framebuffer *framebuffer = framebufferIt->second;
+ const FramebufferAttachment *backAttachment = framebuffer->getAttachment(GL_BACK);
+
+ ASSERT(backAttachment != nullptr);
+ return backAttachment->getSurface()->getRenderBuffer();
+ }
+ else
+ {
+ return EGL_NONE;
+ }
+}
+
+void Context::checkVertexArrayAllocation(GLuint vertexArray)
+{
+ // Only called after a prior call to Gen.
+ if (!getVertexArray(vertexArray))
+ {
+ VertexArray *vertexArrayObject =
+ new VertexArray(mRenderer, vertexArray, MAX_VERTEX_ATTRIBS);
+ mVertexArrayMap[vertexArray] = vertexArrayObject;
+ }
+}
+
+void Context::checkTransformFeedbackAllocation(GLuint transformFeedback)
+{
+ // Only called after a prior call to Gen.
+ if (!getTransformFeedback(transformFeedback))
+ {
+ TransformFeedback *transformFeedbackObject =
+ new TransformFeedback(mRenderer->createTransformFeedback(), transformFeedback, mCaps);
+ transformFeedbackObject->addRef();
+ mTransformFeedbackMap[transformFeedback] = transformFeedbackObject;
+ }
}
-const Caps &Context::getCaps() const
+Framebuffer *Context::checkFramebufferAllocation(GLuint framebuffer)
{
- return mCaps;
+ // Can be called from Bind without a prior call to Gen.
+ auto framebufferIt = mFramebufferMap.find(framebuffer);
+ bool neverCreated = framebufferIt == mFramebufferMap.end();
+ if (neverCreated || framebufferIt->second == nullptr)
+ {
+ Framebuffer *newFBO = new Framebuffer(mCaps, mRenderer, framebuffer);
+ if (neverCreated)
+ {
+ mFramebufferHandleAllocator.reserve(framebuffer);
+ mFramebufferMap[framebuffer] = newFBO;
+ return newFBO;
+ }
+
+ framebufferIt->second = newFBO;
+ }
+
+ return framebufferIt->second;
}
-const TextureCapsMap &Context::getTextureCaps() const
+bool Context::isVertexArrayGenerated(GLuint vertexArray)
{
- return mTextureCaps;
+ return mVertexArrayMap.find(vertexArray) != mVertexArrayMap.end();
}
-const Extensions &Context::getExtensions() const
+bool Context::isTransformFeedbackGenerated(GLuint transformFeedback)
{
- return mExtensions;
+ return mTransformFeedbackMap.find(transformFeedback) != mTransformFeedbackMap.end();
}
void Context::detachTexture(GLuint texture)
@@ -1321,20 +1761,15 @@ void Context::detachTexture(GLuint texture)
void Context::detachBuffer(GLuint buffer)
{
- // Buffer detachment is handled by Context, because the buffer must also be
- // attached from any VAOs in existence, and Context holds the VAO map.
+ // Simple pass-through to State's detachBuffer method, since
+ // only buffer attachments to container objects that are bound to the current context
+ // should be detached. And all those are available in State.
- // [OpenGL ES 2.0.24] section 2.9 page 22:
- // If a buffer object is deleted while it is bound, all bindings to that object in the current context
- // (i.e. in the thread that called Delete-Buffers) are reset to zero.
-
- mState.removeArrayBufferBinding(buffer);
-
- // mark as freed among the vertex array objects
- for (auto vaoIt = mVertexArrayMap.begin(); vaoIt != mVertexArrayMap.end(); vaoIt++)
- {
- vaoIt->second->detachBuffer(buffer);
- }
+ // [OpenGL ES 3.2] section 5.1.2 page 45:
+ // Attachments to unbound container objects, such as
+ // deletion of a buffer attached to a vertex array object which is not bound to the context,
+ // are not affected and continue to act as references on the deleted object
+ mState.detachBuffer(buffer);
}
void Context::detachFramebuffer(GLuint framebuffer)
@@ -1365,8 +1800,8 @@ void Context::detachRenderbuffer(GLuint renderbuffer)
void Context::detachVertexArray(GLuint vertexArray)
{
- // Vertex array detachment is handled by Context, because 0 is a valid
- // VAO, and a pointer to it must be passed from Context to State at
+ // Vertex array detachment is handled by Context, because 0 is a valid
+ // VAO, and a pointer to it must be passed from Context to State at
// binding time.
// [OpenGL ES 3.0.2] section 2.10 page 43:
@@ -1390,7 +1825,7 @@ void Context::detachSampler(GLuint sampler)
void Context::setVertexAttribDivisor(GLuint index, GLuint divisor)
{
- mState.getVertexArray()->setVertexAttribDivisor(index, divisor);
+ mState.setVertexAttribDivisor(index, divisor);
}
void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
@@ -1400,19 +1835,22 @@ void Context::samplerParameteri(GLuint sampler, GLenum pname, GLint param)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast<GLfloat>(param)); break;
- case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast<GLfloat>(param)); break;
- case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(static_cast<GLenum>(param)); break;
- case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(static_cast<GLenum>(param)); break;
- default: UNREACHABLE(); break;
+ case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(std::min(static_cast<GLfloat>(param), getExtensions().maxTextureAnisotropy)); break;
+ case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(static_cast<GLfloat>(param)); break;
+ case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(static_cast<GLfloat>(param)); break;
+ case GL_TEXTURE_COMPARE_MODE: samplerObject->setCompareMode(static_cast<GLenum>(param)); break;
+ case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(static_cast<GLenum>(param)); break;
+ default: UNREACHABLE(); break;
}
+ // clang-format on
}
void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
@@ -1422,19 +1860,22 @@ void Context::samplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround<GLenum>(param)); break;
- case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround<GLenum>(param)); break;
- case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround<GLenum>(param)); break;
- case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break;
- case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break;
- case GL_TEXTURE_COMPARE_MODE: samplerObject->setComparisonMode(uiround<GLenum>(param)); break;
- case GL_TEXTURE_COMPARE_FUNC: samplerObject->setComparisonFunc(uiround<GLenum>(param)); break;
- default: UNREACHABLE(); break;
+ case GL_TEXTURE_MIN_FILTER: samplerObject->setMinFilter(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_MAG_FILTER: samplerObject->setMagFilter(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_S: samplerObject->setWrapS(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_T: samplerObject->setWrapT(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_WRAP_R: samplerObject->setWrapR(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: samplerObject->setMaxAnisotropy(std::min(param, getExtensions().maxTextureAnisotropy)); break;
+ case GL_TEXTURE_MIN_LOD: samplerObject->setMinLod(param); break;
+ case GL_TEXTURE_MAX_LOD: samplerObject->setMaxLod(param); break;
+ case GL_TEXTURE_COMPARE_MODE: samplerObject->setCompareMode(uiround<GLenum>(param)); break;
+ case GL_TEXTURE_COMPARE_FUNC: samplerObject->setCompareFunc(uiround<GLenum>(param)); break;
+ default: UNREACHABLE(); break;
}
+ // clang-format on
}
GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname)
@@ -1444,19 +1885,22 @@ GLint Context::getSamplerParameteri(GLuint sampler, GLenum pname)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: return static_cast<GLint>(samplerObject->getMinFilter());
- case GL_TEXTURE_MAG_FILTER: return static_cast<GLint>(samplerObject->getMagFilter());
- case GL_TEXTURE_WRAP_S: return static_cast<GLint>(samplerObject->getWrapS());
- case GL_TEXTURE_WRAP_T: return static_cast<GLint>(samplerObject->getWrapT());
- case GL_TEXTURE_WRAP_R: return static_cast<GLint>(samplerObject->getWrapR());
- case GL_TEXTURE_MIN_LOD: return uiround<GLint>(samplerObject->getMinLod());
- case GL_TEXTURE_MAX_LOD: return uiround<GLint>(samplerObject->getMaxLod());
- case GL_TEXTURE_COMPARE_MODE: return static_cast<GLint>(samplerObject->getComparisonMode());
- case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLint>(samplerObject->getComparisonFunc());
- default: UNREACHABLE(); return 0;
+ case GL_TEXTURE_MIN_FILTER: return static_cast<GLint>(samplerObject->getMinFilter());
+ case GL_TEXTURE_MAG_FILTER: return static_cast<GLint>(samplerObject->getMagFilter());
+ case GL_TEXTURE_WRAP_S: return static_cast<GLint>(samplerObject->getWrapS());
+ case GL_TEXTURE_WRAP_T: return static_cast<GLint>(samplerObject->getWrapT());
+ case GL_TEXTURE_WRAP_R: return static_cast<GLint>(samplerObject->getWrapR());
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: return static_cast<GLint>(samplerObject->getMaxAnisotropy());
+ case GL_TEXTURE_MIN_LOD: return uiround<GLint>(samplerObject->getMinLod());
+ case GL_TEXTURE_MAX_LOD: return uiround<GLint>(samplerObject->getMaxLod());
+ case GL_TEXTURE_COMPARE_MODE: return static_cast<GLint>(samplerObject->getCompareMode());
+ case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLint>(samplerObject->getCompareFunc());
+ default: UNREACHABLE(); return 0;
}
+ // clang-format on
}
GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname)
@@ -1466,19 +1910,22 @@ GLfloat Context::getSamplerParameterf(GLuint sampler, GLenum pname)
Sampler *samplerObject = getSampler(sampler);
ASSERT(samplerObject);
+ // clang-format off
switch (pname)
{
- case GL_TEXTURE_MIN_FILTER: return static_cast<GLfloat>(samplerObject->getMinFilter());
- case GL_TEXTURE_MAG_FILTER: return static_cast<GLfloat>(samplerObject->getMagFilter());
- case GL_TEXTURE_WRAP_S: return static_cast<GLfloat>(samplerObject->getWrapS());
- case GL_TEXTURE_WRAP_T: return static_cast<GLfloat>(samplerObject->getWrapT());
- case GL_TEXTURE_WRAP_R: return static_cast<GLfloat>(samplerObject->getWrapR());
- case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod();
- case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod();
- case GL_TEXTURE_COMPARE_MODE: return static_cast<GLfloat>(samplerObject->getComparisonMode());
- case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLfloat>(samplerObject->getComparisonFunc());
- default: UNREACHABLE(); return 0;
+ case GL_TEXTURE_MIN_FILTER: return static_cast<GLfloat>(samplerObject->getMinFilter());
+ case GL_TEXTURE_MAG_FILTER: return static_cast<GLfloat>(samplerObject->getMagFilter());
+ case GL_TEXTURE_WRAP_S: return static_cast<GLfloat>(samplerObject->getWrapS());
+ case GL_TEXTURE_WRAP_T: return static_cast<GLfloat>(samplerObject->getWrapT());
+ case GL_TEXTURE_WRAP_R: return static_cast<GLfloat>(samplerObject->getWrapR());
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT: return samplerObject->getMaxAnisotropy();
+ case GL_TEXTURE_MIN_LOD: return samplerObject->getMinLod();
+ case GL_TEXTURE_MAX_LOD: return samplerObject->getMaxLod();
+ case GL_TEXTURE_COMPARE_MODE: return static_cast<GLfloat>(samplerObject->getCompareMode());
+ case GL_TEXTURE_COMPARE_FUNC: return static_cast<GLfloat>(samplerObject->getCompareFunc());
+ default: UNREACHABLE(); return 0;
}
+ // clang-format on
}
void Context::initRendererString()
@@ -1526,6 +1973,8 @@ void Context::initCaps(GLuint clientVersion)
mExtensions = mRenderer->getRendererExtensions();
+ mLimitations = mRenderer->getRendererLimitations();
+
if (clientVersion < 3)
{
// Disable ES3+ extensions
@@ -1538,6 +1987,13 @@ void Context::initCaps(GLuint clientVersion)
//mExtensions.sRGB = false;
}
+ // Explicitly enable GL_KHR_debug
+ mExtensions.debug = true;
+ mExtensions.maxDebugMessageLength = 1024;
+ mExtensions.maxDebugLoggedMessages = 1024;
+ mExtensions.maxDebugGroupStackDepth = 1024;
+ mExtensions.maxLabelLength = 1024;
+
// Apply implementation limits
mCaps.maxVertexAttributes = std::min<GLuint>(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS);
mCaps.maxVertexUniformBlocks = std::min<GLuint>(mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS);
@@ -1545,7 +2001,6 @@ void Context::initCaps(GLuint clientVersion)
mCaps.maxFragmentInputComponents = std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
- GLuint maxSamples = 0;
mCaps.compressedTextureFormats.clear();
const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps();
@@ -1556,17 +2011,21 @@ void Context::initCaps(GLuint clientVersion)
const InternalFormat &formatInfo = GetInternalFormatInfo(format);
- // Update the format caps based on the client version and extensions
- formatCaps.texturable = formatInfo.textureSupport(clientVersion, mExtensions);
- formatCaps.renderable = formatInfo.renderSupport(clientVersion, mExtensions);
- formatCaps.filterable = formatInfo.filterSupport(clientVersion, mExtensions);
+ // Update the format caps based on the client version and extensions.
+ // Caps are AND'd with the renderer caps because some core formats are still unsupported in
+ // ES3.
+ formatCaps.texturable =
+ formatCaps.texturable && formatInfo.textureSupport(clientVersion, mExtensions);
+ formatCaps.renderable =
+ formatCaps.renderable && formatInfo.renderSupport(clientVersion, mExtensions);
+ formatCaps.filterable =
+ formatCaps.filterable && formatInfo.filterSupport(clientVersion, mExtensions);
// OpenGL ES does not support multisampling with integer formats
if (!formatInfo.renderSupport || formatInfo.componentType == GL_INT || formatInfo.componentType == GL_UNSIGNED_INT)
{
formatCaps.sampleCounts.clear();
}
- maxSamples = std::max(maxSamples, formatCaps.getMaxSamples());
if (formatCaps.texturable && formatInfo.compressed)
{
@@ -1575,13 +2034,391 @@ void Context::initCaps(GLuint clientVersion)
mTextureCaps.insert(format, formatCaps);
}
+}
+
+void Context::syncRendererState()
+{
+ const State::DirtyBits &dirtyBits = mState.getDirtyBits();
+ mRenderer->syncState(mState, dirtyBits);
+ mState.clearDirtyBits();
+ mState.syncDirtyObjects();
+}
+
+void Context::syncRendererState(const State::DirtyBits &bitMask)
+{
+ const State::DirtyBits &dirtyBits = (mState.getDirtyBits() & bitMask);
+ mRenderer->syncState(mState, dirtyBits);
+ mState.clearDirtyBits(dirtyBits);
+
+ // TODO(jmadill): Filter objects by bitMask somehow?
+ mState.syncDirtyObjects();
+}
+
+void Context::blitFramebuffer(GLint srcX0,
+ GLint srcY0,
+ GLint srcX1,
+ GLint srcY1,
+ GLint dstX0,
+ GLint dstY0,
+ GLint dstX1,
+ GLint dstY1,
+ GLbitfield mask,
+ GLenum filter)
+{
+ Framebuffer *readFramebuffer = mState.getReadFramebuffer();
+ ASSERT(readFramebuffer);
+
+ Framebuffer *drawFramebuffer = mState.getDrawFramebuffer();
+ ASSERT(drawFramebuffer);
+
+ Rectangle srcArea(srcX0, srcY0, srcX1 - srcX0, srcY1 - srcY0);
+ Rectangle dstArea(dstX0, dstY0, dstX1 - dstX0, dstY1 - dstY0);
+
+ syncRendererState(mState.blitStateBitMask());
+
+ Error error = drawFramebuffer->blit(mState, srcArea, dstArea, mask, filter, readFramebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ return;
+ }
+}
+
+void Context::clear(GLbitfield mask)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clear(mData, mask);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *values)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clearBufferfv(mData, buffer, drawbuffer, values);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *values)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clearBufferuiv(mData, buffer, drawbuffer, values);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *values)
+{
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = mState.getDrawFramebuffer()->clearBufferiv(mData, buffer, drawbuffer, values);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+{
+ Framebuffer *framebufferObject = mState.getDrawFramebuffer();
+ ASSERT(framebufferObject);
+
+ // If a buffer is not present, the clear has no effect
+ if (framebufferObject->getDepthbuffer() == nullptr &&
+ framebufferObject->getStencilbuffer() == nullptr)
+ {
+ return;
+ }
+
+ // Sync the clear state
+ syncRendererState(mState.clearStateBitMask());
+
+ Error error = framebufferObject->clearBufferfi(mData, buffer, drawbuffer, depth, stencil);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::readPixels(GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels)
+{
+ // Sync pack state
+ syncRendererState(mState.packStateBitMask());
+
+ Framebuffer *framebufferObject = mState.getReadFramebuffer();
+ ASSERT(framebufferObject);
+
+ Rectangle area(x, y, width, height);
+ Error error = framebufferObject->readPixels(mState, area, format, type, pixels);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::copyTexImage2D(GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border)
+{
+ // Only sync the read FBO
+ mState.syncDirtyObject(GL_READ_FRAMEBUFFER);
+
+ Rectangle sourceArea(x, y, width, height);
+
+ const Framebuffer *framebuffer = mState.getReadFramebuffer();
+ Texture *texture =
+ getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
+ Error error = texture->copyImage(target, level, sourceArea, internalformat, framebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::copyTexSubImage2D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ // Only sync the read FBO
+ mState.syncDirtyObject(GL_READ_FRAMEBUFFER);
+
+ Offset destOffset(xoffset, yoffset, 0);
+ Rectangle sourceArea(x, y, width, height);
+
+ const Framebuffer *framebuffer = mState.getReadFramebuffer();
+ Texture *texture =
+ getTargetTexture(IsCubeMapTextureTarget(target) ? GL_TEXTURE_CUBE_MAP : target);
+ Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::copyTexSubImage3D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint zoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ // Only sync the read FBO
+ mState.syncDirtyObject(GL_READ_FRAMEBUFFER);
+
+ Offset destOffset(xoffset, yoffset, zoffset);
+ Rectangle sourceArea(x, y, width, height);
+
+ const Framebuffer *framebuffer = mState.getReadFramebuffer();
+ Texture *texture = getTargetTexture(target);
+ Error error = texture->copySubImage(target, level, destOffset, sourceArea, framebuffer);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::framebufferTexture2D(GLenum target,
+ GLenum attachment,
+ GLenum textarget,
+ GLuint texture,
+ GLint level)
+{
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (texture != 0)
+ {
+ Texture *textureObj = getTexture(texture);
+
+ ImageIndex index = ImageIndex::MakeInvalid();
+
+ if (textarget == GL_TEXTURE_2D)
+ {
+ index = ImageIndex::Make2D(level);
+ }
+ else
+ {
+ ASSERT(IsCubeMapTextureTarget(textarget));
+ index = ImageIndex::MakeCube(textarget, level);
+ }
+
+ framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObj);
+ }
+ else
+ {
+ framebuffer->resetAttachment(attachment);
+ }
+
+ mState.setObjectDirty(target);
+}
+
+void Context::framebufferRenderbuffer(GLenum target,
+ GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer)
+{
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (renderbuffer != 0)
+ {
+ Renderbuffer *renderbufferObject = getRenderbuffer(renderbuffer);
+ framebuffer->setAttachment(GL_RENDERBUFFER, attachment, gl::ImageIndex::MakeInvalid(),
+ renderbufferObject);
+ }
+ else
+ {
+ framebuffer->resetAttachment(attachment);
+ }
- mExtensions.maxSamples = maxSamples;
+ mState.setObjectDirty(target);
}
-Data Context::getData() const
+void Context::framebufferTextureLayer(GLenum target,
+ GLenum attachment,
+ GLuint texture,
+ GLint level,
+ GLint layer)
{
- return Data(mClientVersion, mState, mCaps, mTextureCaps, mExtensions, mResourceManager);
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (texture != 0)
+ {
+ Texture *textureObject = getTexture(texture);
+
+ ImageIndex index = ImageIndex::MakeInvalid();
+
+ if (textureObject->getTarget() == GL_TEXTURE_3D)
+ {
+ index = ImageIndex::Make3D(level, layer);
+ }
+ else
+ {
+ ASSERT(textureObject->getTarget() == GL_TEXTURE_2D_ARRAY);
+ index = ImageIndex::Make2DArray(level, layer);
+ }
+
+ framebuffer->setAttachment(GL_TEXTURE, attachment, index, textureObject);
+ }
+ else
+ {
+ framebuffer->resetAttachment(attachment);
+ }
+
+ mState.setObjectDirty(target);
+}
+
+void Context::drawBuffers(GLsizei n, const GLenum *bufs)
+{
+ Framebuffer *framebuffer = mState.getDrawFramebuffer();
+ ASSERT(framebuffer);
+ framebuffer->setDrawBuffers(n, bufs);
+ mState.setObjectDirty(GL_DRAW_FRAMEBUFFER);
}
+void Context::readBuffer(GLenum mode)
+{
+ Framebuffer *readFBO = mState.getReadFramebuffer();
+ readFBO->setReadBuffer(mode);
+ mState.setObjectDirty(GL_READ_FRAMEBUFFER);
}
+
+void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+ // Only sync the FBO
+ mState.syncDirtyObject(target);
+
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ // The specification isn't clear what should be done when the framebuffer isn't complete.
+ // We leave it up to the framebuffer implementation to decide what to do.
+ Error error = framebuffer->discard(numAttachments, attachments);
+ if (error.isError())
+ {
+ recordError(error);
+ }
+}
+
+void Context::invalidateFramebuffer(GLenum target,
+ GLsizei numAttachments,
+ const GLenum *attachments)
+{
+ // Only sync the FBO
+ mState.syncDirtyObject(target);
+
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE)
+ {
+ Error error = framebuffer->invalidate(numAttachments, attachments);
+ if (error.isError())
+ {
+ recordError(error);
+ return;
+ }
+ }
+}
+
+void Context::invalidateSubFramebuffer(GLenum target,
+ GLsizei numAttachments,
+ const GLenum *attachments,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height)
+{
+ // Only sync the FBO
+ mState.syncDirtyObject(target);
+
+ Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
+ ASSERT(framebuffer);
+
+ if (framebuffer->checkStatus(mData) == GL_FRAMEBUFFER_COMPLETE)
+ {
+ Rectangle area(x, y, width, height);
+ Error error = framebuffer->invalidateSub(numAttachments, attachments, area);
+ if (error.isError())
+ {
+ recordError(error);
+ return;
+ }
+ }
+}
+
+} // namespace gl