blob: 6732f8918c67b6763403d7d6ede32658e428c4eb [file] [log] [blame]
//
// 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, 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},
}};
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();
}
}
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::noopDraw(PrimitiveMode mode, GLsizei count) const
{
// Make sure any pending link is done before checking whether draw is allowed.
mState.ensureNoPendingLink(this);
if (!mStateCache.getCanDraw())
{
return true;
}
return count < kMinimumPrimitiveCounts[mode];
}
ANGLE_INLINE bool Context::noopMultiDraw(GLsizei drawcount) const
{
return drawcount == 0 || !mStateCache.getCanDraw();
}
ANGLE_INLINE angle::Result Context::syncAllDirtyBits(Command command)
{
constexpr state::DirtyBits kAllDirtyBits = state::DirtyBits().set();
constexpr state::ExtendedDirtyBits kAllExtendedDirtyBits = state::ExtendedDirtyBits().set();
const state::DirtyBits dirtyBits = mState.getDirtyBits();
const state::ExtendedDirtyBits extendedDirtyBits = mState.getExtendedDirtyBits();
ANGLE_TRY(mImplementation->syncState(this, dirtyBits, kAllDirtyBits, extendedDirtyBits,
kAllExtendedDirtyBits, command));
mState.clearDirtyBits();
mState.clearExtendedDirtyBits();
return angle::Result::Continue;
}
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 syncAllDirtyBits(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 StateCache::onBufferBindingChange(Context *context)
{
updateBasicDrawStatesError();
updateBasicDrawElementsError();
}
ANGLE_INLINE void Context::bindBuffer(BufferBinding target, BufferID buffer)
{
Buffer *bufferObject =
mState.mBufferManager->checkBufferAllocation(mImplementation.get(), buffer);
// Early return if rebinding the same buffer
if (bufferObject == mState.getTargetBuffer(target))
{
return;
}
mState.setBufferBinding(this, target, bufferObject);
mStateCache.onBufferBindingChange(this);
if (bufferObject)
{
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);
}
} // namespace gl
#endif // LIBANGLE_CONTEXT_INL_H_