| // |
| // Copyright 2018 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // Context.inl.h: Defines inline functions of gl::Context class |
| // Has to be included after libANGLE/Context.h when using one |
| // of the defined functions |
| |
| #ifndef LIBANGLE_CONTEXT_INL_H_ |
| #define LIBANGLE_CONTEXT_INL_H_ |
| |
| #include "libANGLE/Context.h" |
| #include "libANGLE/GLES1Renderer.h" |
| #include "libANGLE/renderer/ContextImpl.h" |
| |
| #define ANGLE_HANDLE_ERR(X) \ |
| (void)(X); \ |
| return; |
| #define ANGLE_CONTEXT_TRY(EXPR) ANGLE_TRY_TEMPLATE(EXPR, static_cast<void>(0), ANGLE_HANDLE_ERR) |
| |
| namespace gl |
| { |
| constexpr angle::PackedEnumMap<PrimitiveMode, GLsizei> kMinimumPrimitiveCounts = {{ |
| {PrimitiveMode::Points, 1}, |
| {PrimitiveMode::Lines, 2}, |
| {PrimitiveMode::LineLoop, 2}, |
| {PrimitiveMode::LineStrip, 2}, |
| {PrimitiveMode::Triangles, 3}, |
| {PrimitiveMode::TriangleStrip, 3}, |
| {PrimitiveMode::TriangleFan, 3}, |
| {PrimitiveMode::LinesAdjacency, 2}, |
| {PrimitiveMode::LineStripAdjacency, 2}, |
| {PrimitiveMode::TrianglesAdjacency, 3}, |
| {PrimitiveMode::TriangleStripAdjacency, 3}, |
| }}; |
| |
| // All bits except |DIRTY_BIT_READ_FRAMEBUFFER_BINDING| because |mDrawDirtyObjects| does not contain |
| // |DIRTY_OBJECT_READ_FRAMEBUFFER|, to avoid synchronizing with invalid read framebuffer state. |
| constexpr state::DirtyBits kDrawDirtyBits = |
| ~state::DirtyBits{state::DIRTY_BIT_READ_FRAMEBUFFER_BINDING}; |
| constexpr state::ExtendedDirtyBits kDrawExtendedDirtyBits = state::ExtendedDirtyBits().set(); |
| |
| ANGLE_INLINE void MarkTransformFeedbackBufferUsage(const Context *context, |
| GLsizei count, |
| GLsizei instanceCount) |
| { |
| if (context->getStateCache().isTransformFeedbackActiveUnpaused()) |
| { |
| TransformFeedback *transformFeedback = context->getState().getCurrentTransformFeedback(); |
| transformFeedback->onVerticesDrawn(context, count, instanceCount); |
| } |
| } |
| |
| ANGLE_INLINE void MarkShaderStorageUsage(const Context *context) |
| { |
| for (size_t index : context->getStateCache().getActiveShaderStorageBufferIndices()) |
| { |
| Buffer *buffer = context->getState().getIndexedShaderStorageBuffer(index).get(); |
| if (buffer) |
| { |
| buffer->onDataChanged(context); |
| } |
| } |
| |
| for (size_t index : context->getStateCache().getActiveImageUnitIndices()) |
| { |
| const ImageUnit &imageUnit = context->getState().getImageUnit(index); |
| const Texture *texture = imageUnit.texture.get(); |
| if (texture) |
| { |
| texture->onStateChange(angle::SubjectMessage::ContentsChanged); |
| } |
| } |
| } |
| |
| // Return true if the draw is a no-op, else return false. |
| // If there is no active program for the vertex or fragment shader stages, the results of vertex |
| // and fragment shader execution will respectively be undefined. However, this is not |
| // an error. ANGLE will treat this as a no-op. |
| // A no-op draw occurs if the count of vertices is less than the minimum required to |
| // have a valid primitive for this mode (0 for points, 0-1 for lines, 0-2 for tris). |
| ANGLE_INLINE bool Context::noopDrawProgram() const |
| { |
| // Make sure any pending link is done before checking whether draw is allowed. |
| mState.ensureNoPendingLink(this); |
| |
| // No-op when there is no active vertex shader |
| return !mStateCache.getCanDraw(); |
| } |
| |
| ANGLE_INLINE bool Context::noopDraw(PrimitiveMode mode, GLsizei count) const |
| { |
| if (ANGLE_UNLIKELY(count < kMinimumPrimitiveCounts[mode])) |
| { |
| return true; |
| } |
| |
| return noopDrawProgram(); |
| } |
| |
| ANGLE_INLINE bool Context::noopDrawInstanced(PrimitiveMode mode, |
| GLsizei count, |
| GLsizei instanceCount) const |
| { |
| if (ANGLE_UNLIKELY(instanceCount < 1)) |
| { |
| return true; |
| } |
| |
| return noopDraw(mode, count); |
| } |
| |
| ANGLE_INLINE bool Context::noopMultiDraw(GLsizei drawcount) const |
| { |
| if (ANGLE_UNLIKELY(drawcount < 1)) |
| { |
| return true; |
| } |
| |
| return noopDrawProgram(); |
| } |
| |
| ANGLE_INLINE angle::Result Context::syncDirtyBits(const state::DirtyBits bitMask, |
| const state::ExtendedDirtyBits extendedBitMask, |
| Command command) |
| { |
| const state::DirtyBits dirtyBits = (mState.getDirtyBits() & bitMask); |
| const state::ExtendedDirtyBits extendedDirtyBits = |
| (mState.getExtendedDirtyBits() & extendedBitMask); |
| ANGLE_TRY(mImplementation->syncState(this, dirtyBits, bitMask, extendedDirtyBits, |
| extendedBitMask, command)); |
| mState.clearDirtyBits(dirtyBits); |
| mState.clearExtendedDirtyBits(extendedDirtyBits); |
| return angle::Result::Continue; |
| } |
| |
| ANGLE_INLINE angle::Result Context::syncDirtyObjects(const state::DirtyObjects &objectMask, |
| Command command) |
| { |
| return mState.syncDirtyObjects(this, objectMask, command); |
| } |
| |
| ANGLE_INLINE angle::Result Context::prepareForDraw(PrimitiveMode mode) |
| { |
| if (mGLES1Renderer) |
| { |
| ANGLE_TRY(mGLES1Renderer->prepareForDraw(mode, this, &mState, getMutableGLES1State())); |
| } |
| |
| ANGLE_TRY(syncDirtyObjects(mDrawDirtyObjects, Command::Draw)); |
| ASSERT(!isRobustResourceInitEnabled() || |
| !mState.getDrawFramebuffer()->hasResourceThatNeedsInit()); |
| return syncDirtyBits(kDrawDirtyBits, kDrawExtendedDirtyBits, Command::Draw); |
| } |
| |
| ANGLE_INLINE void Context::drawArrays(PrimitiveMode mode, GLint first, GLsizei count) |
| { |
| // No-op if count draws no primitives for given mode |
| if (noopDraw(mode, count)) |
| { |
| ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent()); |
| return; |
| } |
| |
| ANGLE_CONTEXT_TRY(prepareForDraw(mode)); |
| ANGLE_CONTEXT_TRY(mImplementation->drawArrays(this, mode, first, count)); |
| MarkTransformFeedbackBufferUsage(this, count, 1); |
| } |
| |
| ANGLE_INLINE void Context::drawElements(PrimitiveMode mode, |
| GLsizei count, |
| DrawElementsType type, |
| const void *indices) |
| { |
| // No-op if count draws no primitives for given mode |
| if (noopDraw(mode, count)) |
| { |
| ANGLE_CONTEXT_TRY(mImplementation->handleNoopDrawEvent()); |
| return; |
| } |
| |
| ANGLE_CONTEXT_TRY(prepareForDraw(mode)); |
| ANGLE_CONTEXT_TRY(mImplementation->drawElements(this, mode, count, type, indices)); |
| } |
| |
| ANGLE_INLINE void Context::bindBuffer(BufferBinding target, BufferID buffer) |
| { |
| Buffer *bufferObject = |
| mState.mBufferManager->checkBufferAllocation(mImplementation.get(), buffer); |
| |
| // If there is a shared context, buffer may have been modified by other context. bindBuffer |
| // supposedly should pick up the changes other contexts have made and update current vertex |
| // array. |
| if (bufferObject != nullptr && isSharedContext()) |
| { |
| VertexArrayBufferBindingMask bindingMask = bufferObject->getVertexArrayBinding(this); |
| if (bindingMask.any()) |
| { |
| ASSERT(mState.mVertexArray != nullptr); |
| // Update vertex array only if buffer is attached to current vertex array. |
| mState.mVertexArray->onSharedBufferBind(this, bufferObject, bindingMask); |
| mState.setObjectDirty(GL_VERTEX_ARRAY); |
| mPrivateStateCache.onVertexArrayBufferContentsChange(); |
| } |
| } |
| |
| // Early return if rebinding the same buffer |
| if (bufferObject == mState.getTargetBuffer(target)) |
| { |
| return; |
| } |
| |
| mState.setBufferBinding(this, target, bufferObject); |
| mPrivateStateCache.onBufferBindingChange(); |
| |
| if (bufferObject && isWebGL()) |
| { |
| bufferObject->onBind(this, target); |
| } |
| } |
| |
| ANGLE_INLINE void Context::uniform1f(UniformLocation location, GLfloat x) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform1fv(location, 1, &x); |
| } |
| |
| ANGLE_INLINE void Context::uniform1fv(UniformLocation location, GLsizei count, const GLfloat *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform1fv(location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::setUniform1iImpl(Program *program, |
| UniformLocation location, |
| GLsizei count, |
| const GLint *v) |
| { |
| program->getExecutable().setUniform1iv(this, location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform1i(UniformLocation location, GLint x) |
| { |
| Program *program = getActiveLinkedProgram(); |
| setUniform1iImpl(program, location, 1, &x); |
| } |
| |
| ANGLE_INLINE void Context::uniform1iv(UniformLocation location, GLsizei count, const GLint *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| setUniform1iImpl(program, location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform2f(UniformLocation location, GLfloat x, GLfloat y) |
| { |
| GLfloat xy[2] = {x, y}; |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform2fv(location, 1, xy); |
| } |
| |
| ANGLE_INLINE void Context::uniform2fv(UniformLocation location, GLsizei count, const GLfloat *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform2fv(location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform2i(UniformLocation location, GLint x, GLint y) |
| { |
| GLint xy[2] = {x, y}; |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform2iv(location, 1, xy); |
| } |
| |
| ANGLE_INLINE void Context::uniform2iv(UniformLocation location, GLsizei count, const GLint *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform2iv(location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform3f(UniformLocation location, GLfloat x, GLfloat y, GLfloat z) |
| { |
| GLfloat xyz[3] = {x, y, z}; |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform3fv(location, 1, xyz); |
| } |
| |
| ANGLE_INLINE void Context::uniform3fv(UniformLocation location, GLsizei count, const GLfloat *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform3fv(location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform3i(UniformLocation location, GLint x, GLint y, GLint z) |
| { |
| GLint xyz[3] = {x, y, z}; |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform3iv(location, 1, xyz); |
| } |
| |
| ANGLE_INLINE void Context::uniform3iv(UniformLocation location, GLsizei count, const GLint *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform3iv(location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform4f(UniformLocation location, |
| GLfloat x, |
| GLfloat y, |
| GLfloat z, |
| GLfloat w) |
| { |
| GLfloat xyzw[4] = {x, y, z, w}; |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform4fv(location, 1, xyzw); |
| } |
| |
| ANGLE_INLINE void Context::uniform4fv(UniformLocation location, GLsizei count, const GLfloat *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform4fv(location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform4i(UniformLocation location, GLint x, GLint y, GLint z, GLint w) |
| { |
| GLint xyzw[4] = {x, y, z, w}; |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform4iv(location, 1, xyzw); |
| } |
| |
| ANGLE_INLINE void Context::uniform4iv(UniformLocation location, GLsizei count, const GLint *v) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform4iv(location, count, v); |
| } |
| |
| ANGLE_INLINE void Context::uniform1ui(UniformLocation location, GLuint v0) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform1uiv(location, 1, &v0); |
| } |
| |
| ANGLE_INLINE void Context::uniform2ui(UniformLocation location, GLuint v0, GLuint v1) |
| { |
| Program *program = getActiveLinkedProgram(); |
| const GLuint xy[] = {v0, v1}; |
| program->getExecutable().setUniform2uiv(location, 1, xy); |
| } |
| |
| ANGLE_INLINE void Context::uniform3ui(UniformLocation location, GLuint v0, GLuint v1, GLuint v2) |
| { |
| Program *program = getActiveLinkedProgram(); |
| const GLuint xyz[] = {v0, v1, v2}; |
| program->getExecutable().setUniform3uiv(location, 1, xyz); |
| } |
| |
| ANGLE_INLINE void Context::uniform4ui(UniformLocation location, |
| GLuint v0, |
| GLuint v1, |
| GLuint v2, |
| GLuint v3) |
| { |
| Program *program = getActiveLinkedProgram(); |
| const GLuint xyzw[] = {v0, v1, v2, v3}; |
| program->getExecutable().setUniform4uiv(location, 1, xyzw); |
| } |
| |
| ANGLE_INLINE void Context::uniform1uiv(UniformLocation location, GLsizei count, const GLuint *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform1uiv(location, count, value); |
| } |
| |
| ANGLE_INLINE void Context::uniform2uiv(UniformLocation location, GLsizei count, const GLuint *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform2uiv(location, count, value); |
| } |
| |
| ANGLE_INLINE void Context::uniform3uiv(UniformLocation location, GLsizei count, const GLuint *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform3uiv(location, count, value); |
| } |
| |
| ANGLE_INLINE void Context::uniform4uiv(UniformLocation location, GLsizei count, const GLuint *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniform4uiv(location, count, value); |
| } |
| |
| ANGLE_INLINE void Context::uniformMatrix2x3fv(UniformLocation location, |
| GLsizei count, |
| GLboolean transpose, |
| const GLfloat *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniformMatrix2x3fv(location, count, transpose, value); |
| } |
| |
| ANGLE_INLINE void Context::uniformMatrix3x2fv(UniformLocation location, |
| GLsizei count, |
| GLboolean transpose, |
| const GLfloat *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniformMatrix3x2fv(location, count, transpose, value); |
| } |
| |
| ANGLE_INLINE void Context::uniformMatrix2x4fv(UniformLocation location, |
| GLsizei count, |
| GLboolean transpose, |
| const GLfloat *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniformMatrix2x4fv(location, count, transpose, value); |
| } |
| |
| ANGLE_INLINE void Context::uniformMatrix4x2fv(UniformLocation location, |
| GLsizei count, |
| GLboolean transpose, |
| const GLfloat *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniformMatrix4x2fv(location, count, transpose, value); |
| } |
| |
| ANGLE_INLINE void Context::uniformMatrix3x4fv(UniformLocation location, |
| GLsizei count, |
| GLboolean transpose, |
| const GLfloat *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniformMatrix3x4fv(location, count, transpose, value); |
| } |
| |
| ANGLE_INLINE void Context::uniformMatrix4x3fv(UniformLocation location, |
| GLsizei count, |
| GLboolean transpose, |
| const GLfloat *value) |
| { |
| Program *program = getActiveLinkedProgram(); |
| program->getExecutable().setUniformMatrix4x3fv(location, count, transpose, value); |
| } |
| |
| ANGLE_INLINE void Context::vertexAttribPointer(GLuint index, |
| GLint size, |
| VertexAttribType type, |
| GLboolean normalized, |
| GLsizei stride, |
| const void *ptr) |
| { |
| bool vertexAttribDirty = false; |
| mState.setVertexAttribPointer(this, index, mState.getTargetBuffer(BufferBinding::Array), size, |
| type, normalized != GL_FALSE, stride, ptr, &vertexAttribDirty); |
| if (vertexAttribDirty) |
| { |
| mPrivateStateCache.onVertexArrayStateChange(); |
| } |
| } |
| |
| } // namespace gl |
| |
| #endif // LIBANGLE_CONTEXT_INL_H_ |