blob: 39973cbc2c3b05c48851951e01f0841f0649edd5 [file] [log] [blame]
//
// Copyright 2016 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.
//
// ContextGL:
// OpenGL-specific functionality associated with a GL Context.
//
#include "libANGLE/renderer/gl/ContextGL.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/gl/BufferGL.h"
#include "libANGLE/renderer/gl/CompilerGL.h"
#include "libANGLE/renderer/gl/FenceNVGL.h"
#include "libANGLE/renderer/gl/FramebufferGL.h"
#include "libANGLE/renderer/gl/FunctionsGL.h"
#include "libANGLE/renderer/gl/PathGL.h"
#include "libANGLE/renderer/gl/ProgramGL.h"
#include "libANGLE/renderer/gl/ProgramPipelineGL.h"
#include "libANGLE/renderer/gl/QueryGL.h"
#include "libANGLE/renderer/gl/RenderbufferGL.h"
#include "libANGLE/renderer/gl/RendererGL.h"
#include "libANGLE/renderer/gl/SamplerGL.h"
#include "libANGLE/renderer/gl/ShaderGL.h"
#include "libANGLE/renderer/gl/StateManagerGL.h"
#include "libANGLE/renderer/gl/SyncGL.h"
#include "libANGLE/renderer/gl/TextureGL.h"
#include "libANGLE/renderer/gl/TransformFeedbackGL.h"
#include "libANGLE/renderer/gl/VertexArrayGL.h"
namespace rx
{
ContextGL::ContextGL(const gl::ContextState &state, const std::shared_ptr<RendererGL> &renderer)
: ContextImpl(state), mRenderer(renderer)
{
}
ContextGL::~ContextGL()
{
}
angle::Result ContextGL::initialize()
{
return angle::Result::Continue();
}
CompilerImpl *ContextGL::createCompiler()
{
return new CompilerGL(getFunctions());
}
ShaderImpl *ContextGL::createShader(const gl::ShaderState &data)
{
const FunctionsGL *functions = getFunctions();
GLuint shader = functions->createShader(ToGLenum(data.getShaderType()));
return new ShaderGL(data, shader, mRenderer->getMultiviewImplementationType(), functions);
}
ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data)
{
return new ProgramGL(data, getFunctions(), getWorkaroundsGL(), getStateManager(),
getExtensions().pathRendering);
}
FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data)
{
const FunctionsGL *funcs = getFunctions();
GLuint fbo = 0;
funcs->genFramebuffers(1, &fbo);
return new FramebufferGL(data, fbo, false);
}
TextureImpl *ContextGL::createTexture(const gl::TextureState &state)
{
const FunctionsGL *functions = getFunctions();
StateManagerGL *stateManager = getStateManager();
GLuint texture = 0;
functions->genTextures(1, &texture);
stateManager->bindTexture(state.getType(), texture);
return new TextureGL(state, texture);
}
RenderbufferImpl *ContextGL::createRenderbuffer(const gl::RenderbufferState &state)
{
return new RenderbufferGL(state, getFunctions(), getWorkaroundsGL(), getStateManager(),
mRenderer->getBlitter(), getNativeTextureCaps());
}
BufferImpl *ContextGL::createBuffer(const gl::BufferState &state)
{
return new BufferGL(state, getFunctions(), getStateManager());
}
VertexArrayImpl *ContextGL::createVertexArray(const gl::VertexArrayState &data)
{
return new VertexArrayGL(data, getFunctions(), getStateManager());
}
QueryImpl *ContextGL::createQuery(gl::QueryType type)
{
switch (type)
{
case gl::QueryType::CommandsCompleted:
return new SyncQueryGL(type, getFunctions());
default:
return new StandardQueryGL(type, getFunctions(), getStateManager());
}
}
FenceNVImpl *ContextGL::createFenceNV()
{
const FunctionsGL *functions = getFunctions();
if (FenceNVGL::Supported(functions))
{
return new FenceNVGL(functions);
}
else
{
ASSERT(FenceNVSyncGL::Supported(functions));
return new FenceNVSyncGL(functions);
}
}
SyncImpl *ContextGL::createSync()
{
return new SyncGL(getFunctions());
}
TransformFeedbackImpl *ContextGL::createTransformFeedback(const gl::TransformFeedbackState &state)
{
return new TransformFeedbackGL(state, getFunctions(), getStateManager());
}
SamplerImpl *ContextGL::createSampler(const gl::SamplerState &state)
{
return new SamplerGL(state, getFunctions(), getStateManager());
}
ProgramPipelineImpl *ContextGL::createProgramPipeline(const gl::ProgramPipelineState &data)
{
return new ProgramPipelineGL(data, getFunctions());
}
std::vector<PathImpl *> ContextGL::createPaths(GLsizei range)
{
const FunctionsGL *funcs = getFunctions();
std::vector<PathImpl *> ret;
ret.reserve(range);
const GLuint first = funcs->genPathsNV(range);
if (first == 0)
return ret;
for (GLsizei i = 0; i < range; ++i)
{
const auto id = first + i;
ret.push_back(new PathGL(funcs, id));
}
return ret;
}
angle::Result ContextGL::flush(const gl::Context *context)
{
return mRenderer->flush();
}
angle::Result ContextGL::finish(const gl::Context *context)
{
return mRenderer->finish();
}
ANGLE_INLINE angle::Result ContextGL::setDrawArraysState(const gl::Context *context,
GLint first,
GLsizei count,
GLsizei instanceCount)
{
if (context->getStateCache().hasAnyActiveClientAttrib())
{
const gl::State &glState = context->getGLState();
const gl::Program *program = glState.getProgram();
const gl::VertexArray *vao = glState.getVertexArray();
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(vao);
ANGLE_TRY(vaoGL->syncClientSideData(context, program->getActiveAttribLocationsMask(), first,
count, instanceCount));
}
if (context->getExtensions().webglCompatibility)
{
const gl::State &glState = context->getGLState();
FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(glState.getDrawFramebuffer());
framebufferGL->maskOutInactiveOutputDrawBuffers(context);
}
return angle::Result::Continue();
}
ANGLE_INLINE angle::Result ContextGL::setDrawElementsState(const gl::Context *context,
GLsizei count,
GLenum type,
const void *indices,
GLsizei instanceCount,
const void **outIndices)
{
const gl::State &glState = context->getGLState();
const gl::Program *program = glState.getProgram();
const gl::VertexArray *vao = glState.getVertexArray();
const VertexArrayGL *vaoGL = GetImplAs<VertexArrayGL>(vao);
ANGLE_TRY(vaoGL->syncDrawElementsState(context, program->getActiveAttribLocationsMask(), count,
type, indices, instanceCount,
glState.isPrimitiveRestartEnabled(), outIndices));
if (context->getExtensions().webglCompatibility)
{
FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(glState.getDrawFramebuffer());
framebufferGL->maskOutInactiveOutputDrawBuffers(context);
}
return angle::Result::Continue();
}
ANGLE_INLINE angle::Result ContextGL::setDrawIndirectState(const gl::Context *context)
{
if (context->getExtensions().webglCompatibility)
{
const gl::State &glState = context->getGLState();
FramebufferGL *framebufferGL = GetImplAs<FramebufferGL>(glState.getDrawFramebuffer());
framebufferGL->maskOutInactiveOutputDrawBuffers(context);
}
return angle::Result::Continue();
}
angle::Result ContextGL::drawArrays(const gl::Context *context,
gl::PrimitiveMode mode,
GLint first,
GLsizei count)
{
const gl::Program *program = context->getGLState().getProgram();
const bool usesMultiview = program->usesMultiview();
const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0;
ANGLE_TRY(setDrawArraysState(context, first, count, instanceCount));
if (!usesMultiview)
{
getFunctions()->drawArrays(ToGLenum(mode), first, count);
}
else
{
getFunctions()->drawArraysInstanced(ToGLenum(mode), first, count, instanceCount);
}
return angle::Result::Continue();
}
angle::Result ContextGL::drawArraysInstanced(const gl::Context *context,
gl::PrimitiveMode mode,
GLint first,
GLsizei count,
GLsizei instanceCount)
{
GLsizei adjustedInstanceCount = instanceCount;
const gl::Program *program = context->getGLState().getProgram();
if (program->usesMultiview())
{
adjustedInstanceCount *= program->getNumViews();
}
ANGLE_TRY(setDrawArraysState(context, first, count, adjustedInstanceCount));
getFunctions()->drawArraysInstanced(ToGLenum(mode), first, count, adjustedInstanceCount);
return angle::Result::Continue();
}
angle::Result ContextGL::drawElements(const gl::Context *context,
gl::PrimitiveMode mode,
GLsizei count,
GLenum type,
const void *indices)
{
const gl::Program *program = context->getGLState().getProgram();
const bool usesMultiview = program->usesMultiview();
const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0;
const void *drawIndexPtr = nullptr;
ANGLE_TRY(setDrawElementsState(context, count, type, indices, instanceCount, &drawIndexPtr));
if (!usesMultiview)
{
getFunctions()->drawElements(ToGLenum(mode), count, type, drawIndexPtr);
}
else
{
getFunctions()->drawElementsInstanced(ToGLenum(mode), count, type, drawIndexPtr,
instanceCount);
}
return angle::Result::Continue();
}
angle::Result ContextGL::drawElementsInstanced(const gl::Context *context,
gl::PrimitiveMode mode,
GLsizei count,
GLenum type,
const void *indices,
GLsizei instances)
{
GLsizei adjustedInstanceCount = instances;
const gl::Program *program = context->getGLState().getProgram();
if (program->usesMultiview())
{
adjustedInstanceCount *= program->getNumViews();
}
const void *drawIndexPointer = nullptr;
ANGLE_TRY(setDrawElementsState(context, count, type, indices, adjustedInstanceCount,
&drawIndexPointer));
getFunctions()->drawElementsInstanced(ToGLenum(mode), count, type, drawIndexPointer,
adjustedInstanceCount);
return angle::Result::Continue();
}
angle::Result ContextGL::drawRangeElements(const gl::Context *context,
gl::PrimitiveMode mode,
GLuint start,
GLuint end,
GLsizei count,
GLenum type,
const void *indices)
{
const gl::Program *program = context->getGLState().getProgram();
const bool usesMultiview = program->usesMultiview();
const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0;
const void *drawIndexPointer = nullptr;
ANGLE_TRY(
setDrawElementsState(context, count, type, indices, instanceCount, &drawIndexPointer));
if (!usesMultiview)
{
getFunctions()->drawRangeElements(ToGLenum(mode), start, end, count, type,
drawIndexPointer);
}
else
{
getFunctions()->drawElementsInstanced(ToGLenum(mode), count, type, drawIndexPointer,
instanceCount);
}
return angle::Result::Continue();
}
angle::Result ContextGL::drawArraysIndirect(const gl::Context *context,
gl::PrimitiveMode mode,
const void *indirect)
{
ANGLE_TRY(setDrawIndirectState(context));
getFunctions()->drawArraysIndirect(ToGLenum(mode), indirect);
return angle::Result::Continue();
}
angle::Result ContextGL::drawElementsIndirect(const gl::Context *context,
gl::PrimitiveMode mode,
GLenum type,
const void *indirect)
{
ANGLE_TRY(setDrawIndirectState(context));
getFunctions()->drawElementsIndirect(ToGLenum(mode), type, indirect);
return angle::Result::Continue();
}
void ContextGL::stencilFillPath(const gl::Path *path, GLenum fillMode, GLuint mask)
{
mRenderer->stencilFillPath(mState, path, fillMode, mask);
}
void ContextGL::stencilStrokePath(const gl::Path *path, GLint reference, GLuint mask)
{
mRenderer->stencilStrokePath(mState, path, reference, mask);
}
void ContextGL::coverFillPath(const gl::Path *path, GLenum coverMode)
{
mRenderer->coverFillPath(mState, path, coverMode);
}
void ContextGL::coverStrokePath(const gl::Path *path, GLenum coverMode)
{
mRenderer->coverStrokePath(mState, path, coverMode);
}
void ContextGL::stencilThenCoverFillPath(const gl::Path *path,
GLenum fillMode,
GLuint mask,
GLenum coverMode)
{
mRenderer->stencilThenCoverFillPath(mState, path, fillMode, mask, coverMode);
}
void ContextGL::stencilThenCoverStrokePath(const gl::Path *path,
GLint reference,
GLuint mask,
GLenum coverMode)
{
mRenderer->stencilThenCoverStrokePath(mState, path, reference, mask, coverMode);
}
void ContextGL::coverFillPathInstanced(const std::vector<gl::Path *> &paths,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues)
{
mRenderer->coverFillPathInstanced(mState, paths, coverMode, transformType, transformValues);
}
void ContextGL::coverStrokePathInstanced(const std::vector<gl::Path *> &paths,
GLenum coverMode,
GLenum transformType,
const GLfloat *transformValues)
{
mRenderer->coverStrokePathInstanced(mState, paths, coverMode, transformType, transformValues);
}
void ContextGL::stencilFillPathInstanced(const std::vector<gl::Path *> &paths,
GLenum fillMode,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues)
{
mRenderer->stencilFillPathInstanced(mState, paths, fillMode, mask, transformType,
transformValues);
}
void ContextGL::stencilStrokePathInstanced(const std::vector<gl::Path *> &paths,
GLint reference,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues)
{
mRenderer->stencilStrokePathInstanced(mState, paths, reference, mask, transformType,
transformValues);
}
void ContextGL::stencilThenCoverFillPathInstanced(const std::vector<gl::Path *> &paths,
GLenum coverMode,
GLenum fillMode,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues)
{
mRenderer->stencilThenCoverFillPathInstanced(mState, paths, coverMode, fillMode, mask,
transformType, transformValues);
}
void ContextGL::stencilThenCoverStrokePathInstanced(const std::vector<gl::Path *> &paths,
GLenum coverMode,
GLint reference,
GLuint mask,
GLenum transformType,
const GLfloat *transformValues)
{
mRenderer->stencilThenCoverStrokePathInstanced(mState, paths, coverMode, reference, mask,
transformType, transformValues);
}
GLenum ContextGL::getResetStatus()
{
return mRenderer->getResetStatus();
}
std::string ContextGL::getVendorString() const
{
return mRenderer->getVendorString();
}
std::string ContextGL::getRendererDescription() const
{
return mRenderer->getRendererDescription();
}
void ContextGL::insertEventMarker(GLsizei length, const char *marker)
{
mRenderer->insertEventMarker(length, marker);
}
void ContextGL::pushGroupMarker(GLsizei length, const char *marker)
{
mRenderer->pushGroupMarker(length, marker);
}
void ContextGL::popGroupMarker()
{
mRenderer->popGroupMarker();
}
void ContextGL::pushDebugGroup(GLenum source, GLuint id, GLsizei length, const char *message)
{
mRenderer->pushDebugGroup(source, id, length, message);
}
void ContextGL::popDebugGroup()
{
mRenderer->popDebugGroup();
}
angle::Result ContextGL::syncState(const gl::Context *context,
const gl::State::DirtyBits &dirtyBits,
const gl::State::DirtyBits &bitMask)
{
mRenderer->getStateManager()->syncState(context, dirtyBits, bitMask);
return angle::Result::Continue();
}
GLint ContextGL::getGPUDisjoint()
{
return mRenderer->getGPUDisjoint();
}
GLint64 ContextGL::getTimestamp()
{
return mRenderer->getTimestamp();
}
angle::Result ContextGL::onMakeCurrent(const gl::Context *context)
{
// Queries need to be paused/resumed on context switches
return mRenderer->getStateManager()->onMakeCurrent(context);
}
gl::Caps ContextGL::getNativeCaps() const
{
return mRenderer->getNativeCaps();
}
const gl::TextureCapsMap &ContextGL::getNativeTextureCaps() const
{
return mRenderer->getNativeTextureCaps();
}
const gl::Extensions &ContextGL::getNativeExtensions() const
{
return mRenderer->getNativeExtensions();
}
const gl::Limitations &ContextGL::getNativeLimitations() const
{
return mRenderer->getNativeLimitations();
}
void ContextGL::applyNativeWorkarounds(gl::Workarounds *workarounds) const
{
return mRenderer->applyNativeWorkarounds(workarounds);
}
StateManagerGL *ContextGL::getStateManager()
{
return mRenderer->getStateManager();
}
const WorkaroundsGL &ContextGL::getWorkaroundsGL() const
{
return mRenderer->getWorkarounds();
}
BlitGL *ContextGL::getBlitter() const
{
return mRenderer->getBlitter();
}
ClearMultiviewGL *ContextGL::getMultiviewClearer() const
{
return mRenderer->getMultiviewClearer();
}
angle::Result ContextGL::dispatchCompute(const gl::Context *context,
GLuint numGroupsX,
GLuint numGroupsY,
GLuint numGroupsZ)
{
return mRenderer->dispatchCompute(context, numGroupsX, numGroupsY, numGroupsZ);
}
angle::Result ContextGL::dispatchComputeIndirect(const gl::Context *context, GLintptr indirect)
{
return mRenderer->dispatchComputeIndirect(context, indirect);
}
angle::Result ContextGL::memoryBarrier(const gl::Context *context, GLbitfield barriers)
{
return mRenderer->memoryBarrier(barriers);
}
angle::Result ContextGL::memoryBarrierByRegion(const gl::Context *context, GLbitfield barriers)
{
return mRenderer->memoryBarrierByRegion(barriers);
}
} // namespace rx