// // 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/OverlayImpl.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/MemoryObjectGL.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/SemaphoreGL.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::State &state, gl::ErrorSet *errorSet, const std::shared_ptr &renderer) : ContextImpl(state, errorSet), 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(), mRenderer); } ProgramImpl *ContextGL::createProgram(const gl::ProgramState &data) { return new ProgramGL(data, getFunctions(), getFeaturesGL(), getStateManager(), mRenderer); } FramebufferImpl *ContextGL::createFramebuffer(const gl::FramebufferState &data) { const FunctionsGL *funcs = getFunctions(); GLuint fbo = 0; funcs->genFramebuffers(1, &fbo); return new FramebufferGL(data, fbo, false, 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) { const FunctionsGL *functions = getFunctions(); StateManagerGL *stateManager = getStateManager(); GLuint renderbuffer = 0; functions->genRenderbuffers(1, &renderbuffer); stateManager->bindRenderbuffer(GL_RENDERBUFFER, renderbuffer); return new RenderbufferGL(state, renderbuffer); } 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()); } MemoryObjectImpl *ContextGL::createMemoryObject() { const FunctionsGL *functions = getFunctions(); GLuint memoryObject = 0; functions->createMemoryObjectsEXT(1, &memoryObject); return new MemoryObjectGL(memoryObject); } SemaphoreImpl *ContextGL::createSemaphore() { const FunctionsGL *functions = getFunctions(); GLuint semaphore = 0; functions->genSemaphoresEXT(1, &semaphore); return new SemaphoreGL(semaphore); } OverlayImpl *ContextGL::createOverlay(const gl::OverlayState &state) { // Not implemented. return new OverlayImpl(state); } 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->getState(); const gl::ProgramExecutable *executable = getState().getProgramExecutable(); const gl::VertexArray *vao = glState.getVertexArray(); const VertexArrayGL *vaoGL = GetImplAs(vao); ANGLE_TRY(vaoGL->syncClientSideData(context, executable->getActiveAttribLocationsMask(), first, count, instanceCount)); #if defined(ANGLE_STATE_VALIDATION_ENABLED) vaoGL->validateState(); #endif // ANGLE_STATE_VALIDATION_ENABLED } const angle::FeaturesGL &features = getFeaturesGL(); if (features.setPrimitiveRestartFixedIndexForDrawArrays.enabled) { StateManagerGL *stateManager = getStateManager(); constexpr GLuint primitiveRestartIndex = gl::GetPrimitiveRestartIndexFromType(); ANGLE_TRY(stateManager->setPrimitiveRestartIndex(context, primitiveRestartIndex)); } return angle::Result::Continue; } ANGLE_INLINE angle::Result ContextGL::setDrawElementsState(const gl::Context *context, GLsizei count, gl::DrawElementsType type, const void *indices, GLsizei instanceCount, const void **outIndices) { const gl::State &glState = context->getState(); const gl::ProgramExecutable *executable = getState().getProgramExecutable(); const gl::VertexArray *vao = glState.getVertexArray(); const gl::StateCache &stateCache = context->getStateCache(); if (stateCache.hasAnyActiveClientAttrib() || vao->getElementArrayBuffer() == nullptr) { const VertexArrayGL *vaoGL = GetImplAs(vao); ANGLE_TRY(vaoGL->syncDrawElementsState(context, executable->getActiveAttribLocationsMask(), count, type, indices, instanceCount, glState.isPrimitiveRestartEnabled(), outIndices)); } else { *outIndices = indices; } const angle::FeaturesGL &features = getFeaturesGL(); if (glState.isPrimitiveRestartEnabled() && features.emulatePrimitiveRestartFixedIndex.enabled) { StateManagerGL *stateManager = getStateManager(); GLuint primitiveRestartIndex = gl::GetPrimitiveRestartIndex(type); ANGLE_TRY(stateManager->setPrimitiveRestartIndex(context, primitiveRestartIndex)); } #if defined(ANGLE_STATE_VALIDATION_ENABLED) const VertexArrayGL *vaoGL = GetImplAs(vao); vaoGL->validateState(); #endif // ANGLE_STATE_VALIDATION_ENABLED return angle::Result::Continue; } angle::Result ContextGL::drawArrays(const gl::Context *context, gl::PrimitiveMode mode, GLint first, GLsizei count) { const gl::Program *program = context->getState().getProgram(); const bool usesMultiview = program->usesMultiview(); const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0; #if defined(ANGLE_STATE_VALIDATION_ENABLED) validateState(); #endif 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->getState().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; } gl::AttributesMask ContextGL::updateAttributesForBaseInstance(const gl::Program *program, GLuint baseInstance) { const gl::ProgramExecutable *executable = getState().getProgramExecutable(); gl::AttributesMask attribToUpdateMask; if (baseInstance != 0) { const FunctionsGL *functions = getFunctions(); const auto &attribs = mState.getVertexArray()->getVertexAttributes(); const auto &bindings = mState.getVertexArray()->getVertexBindings(); for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; attribIndex++) { const gl::VertexAttribute &attrib = attribs[attribIndex]; const gl::VertexBinding &binding = bindings[attrib.bindingIndex]; if (executable->isAttribLocationActive(attribIndex) && binding.getDivisor() != 0) { attribToUpdateMask.set(attribIndex); const char *p = static_cast(attrib.pointer); const size_t sourceStride = gl::ComputeVertexAttributeStride(attrib, binding); const void *newPointer = p + sourceStride * baseInstance; const BufferGL *buffer = GetImplAs(binding.getBuffer().get()); // We often stream data from scratch buffers when client side data is being used // and that information is in VertexArrayGL. // Assert that the buffer is non-null because this case isn't handled. ASSERT(buffer); getStateManager()->bindBuffer(gl::BufferBinding::Array, buffer->getBufferID()); if (attrib.format->isPureInt()) { functions->vertexAttribIPointer(attribIndex, attrib.format->channelCount, gl::ToGLenum(attrib.format->vertexAttribType), attrib.vertexAttribArrayStride, newPointer); } else { functions->vertexAttribPointer(attribIndex, attrib.format->channelCount, gl::ToGLenum(attrib.format->vertexAttribType), attrib.format->isNorm(), attrib.vertexAttribArrayStride, newPointer); } } } } return attribToUpdateMask; } void ContextGL::resetUpdatedAttributes(gl::AttributesMask attribMask) { const FunctionsGL *functions = getFunctions(); for (size_t attribIndex : attribMask) { const gl::VertexAttribute &attrib = mState.getVertexArray()->getVertexAttributes()[attribIndex]; const gl::VertexBinding &binding = (mState.getVertexArray()->getVertexBindings())[attrib.bindingIndex]; getStateManager()->bindBuffer( gl::BufferBinding::Array, GetImplAs(binding.getBuffer().get())->getBufferID()); if (attrib.format->isPureInt()) { functions->vertexAttribIPointer(static_cast(attribIndex), attrib.format->channelCount, gl::ToGLenum(attrib.format->vertexAttribType), attrib.vertexAttribArrayStride, attrib.pointer); } else { functions->vertexAttribPointer( static_cast(attribIndex), attrib.format->channelCount, gl::ToGLenum(attrib.format->vertexAttribType), attrib.format->isNorm(), attrib.vertexAttribArrayStride, attrib.pointer); } } } angle::Result ContextGL::drawArraysInstancedBaseInstance(const gl::Context *context, gl::PrimitiveMode mode, GLint first, GLsizei count, GLsizei instanceCount, GLuint baseInstance) { GLsizei adjustedInstanceCount = instanceCount; const gl::Program *program = context->getState().getProgram(); if (program->usesMultiview()) { adjustedInstanceCount *= program->getNumViews(); } ANGLE_TRY(setDrawArraysState(context, first, count, adjustedInstanceCount)); const FunctionsGL *functions = getFunctions(); if (functions->drawArraysInstancedBaseInstance) { // GL 4.2+ or GL_EXT_base_instance functions->drawArraysInstancedBaseInstance(ToGLenum(mode), first, count, adjustedInstanceCount, baseInstance); } else { // GL 3.3+ or GLES 3.2+ // TODO(http://anglebug.com/3910): This is a temporary solution by setting and resetting // pointer offset calling vertexAttribPointer Will refactor stateCache and pass baseInstance // to setDrawArraysState to set pointer offset gl::AttributesMask attribToResetMask = updateAttributesForBaseInstance(program, baseInstance); functions->drawArraysInstanced(ToGLenum(mode), first, count, adjustedInstanceCount); resetUpdatedAttributes(attribToResetMask); } return angle::Result::Continue; } angle::Result ContextGL::drawElements(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices) { const gl::State &glState = context->getState(); const gl::Program *program = glState.getProgram(); const bool usesMultiview = program->usesMultiview(); const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0; const void *drawIndexPtr = nullptr; #if defined(ANGLE_STATE_VALIDATION_ENABLED) validateState(); #endif // ANGLE_STATE_VALIDATION_ENABLED ANGLE_TRY(setDrawElementsState(context, count, type, indices, instanceCount, &drawIndexPtr)); if (!usesMultiview) { getFunctions()->drawElements(ToGLenum(mode), count, ToGLenum(type), drawIndexPtr); } else { getFunctions()->drawElementsInstanced(ToGLenum(mode), count, ToGLenum(type), drawIndexPtr, instanceCount); } return angle::Result::Continue; } angle::Result ContextGL::drawElementsBaseVertex(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLint baseVertex) { const gl::State &glState = context->getState(); const gl::Program *program = glState.getProgram(); const bool usesMultiview = program->usesMultiview(); const GLsizei instanceCount = usesMultiview ? program->getNumViews() : 0; const void *drawIndexPtr = nullptr; #if defined(ANGLE_STATE_VALIDATION_ENABLED) validateState(); #endif // ANGLE_STATE_VALIDATION_ENABLED ANGLE_TRY(setDrawElementsState(context, count, type, indices, instanceCount, &drawIndexPtr)); if (!usesMultiview) { getFunctions()->drawElementsBaseVertex(ToGLenum(mode), count, ToGLenum(type), drawIndexPtr, baseVertex); } else { getFunctions()->drawElementsInstancedBaseVertex(ToGLenum(mode), count, ToGLenum(type), drawIndexPtr, instanceCount, baseVertex); } return angle::Result::Continue; } angle::Result ContextGL::drawElementsInstanced(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLsizei instances) { GLsizei adjustedInstanceCount = instances; const gl::Program *program = context->getState().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, ToGLenum(type), drawIndexPointer, adjustedInstanceCount); return angle::Result::Continue; } angle::Result ContextGL::drawElementsInstancedBaseVertex(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLsizei instances, GLint baseVertex) { GLsizei adjustedInstanceCount = instances; const gl::Program *program = context->getState().getProgram(); if (program->usesMultiview()) { adjustedInstanceCount *= program->getNumViews(); } const void *drawIndexPointer = nullptr; ANGLE_TRY(setDrawElementsState(context, count, type, indices, adjustedInstanceCount, &drawIndexPointer)); getFunctions()->drawElementsInstancedBaseVertex( ToGLenum(mode), count, ToGLenum(type), drawIndexPointer, adjustedInstanceCount, baseVertex); return angle::Result::Continue; } angle::Result ContextGL::drawElementsInstancedBaseVertexBaseInstance(const gl::Context *context, gl::PrimitiveMode mode, GLsizei count, gl::DrawElementsType type, const void *indices, GLsizei instances, GLint baseVertex, GLuint baseInstance) { GLsizei adjustedInstanceCount = instances; const gl::Program *program = context->getState().getProgram(); if (program->usesMultiview()) { adjustedInstanceCount *= program->getNumViews(); } const void *drawIndexPointer = nullptr; ANGLE_TRY(setDrawElementsState(context, count, type, indices, adjustedInstanceCount, &drawIndexPointer)); const FunctionsGL *functions = getFunctions(); if (functions->drawElementsInstancedBaseVertexBaseInstance) { // GL 4.2+ or GL_EXT_base_instance functions->drawElementsInstancedBaseVertexBaseInstance( ToGLenum(mode), count, ToGLenum(type), drawIndexPointer, adjustedInstanceCount, baseVertex, baseInstance); } else { // GL 3.3+ or GLES 3.2+ // TODO(http://anglebug.com/3910): same as above gl::AttributesMask attribToResetMask = updateAttributesForBaseInstance(program, baseInstance); functions->drawElementsInstancedBaseVertex(ToGLenum(mode), count, ToGLenum(type), drawIndexPointer, adjustedInstanceCount, baseVertex); resetUpdatedAttributes(attribToResetMask); } return angle::Result::Continue; } angle::Result ContextGL::drawRangeElements(const gl::Context *context, gl::PrimitiveMode mode, GLuint start, GLuint end, GLsizei count, gl::DrawElementsType type, const void *indices) { const gl::Program *program = context->getState().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, ToGLenum(type), drawIndexPointer); } else { getFunctions()->drawElementsInstanced(ToGLenum(mode), count, ToGLenum(type), drawIndexPointer, instanceCount); } return angle::Result::Continue; } angle::Result ContextGL::drawRangeElementsBaseVertex(const gl::Context *context, gl::PrimitiveMode mode, GLuint start, GLuint end, GLsizei count, gl::DrawElementsType type, const void *indices, GLint baseVertex) { const gl::Program *program = context->getState().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()->drawRangeElementsBaseVertex(ToGLenum(mode), start, end, count, ToGLenum(type), drawIndexPointer, baseVertex); } else { getFunctions()->drawElementsInstancedBaseVertex( ToGLenum(mode), count, ToGLenum(type), drawIndexPointer, instanceCount, baseVertex); } return angle::Result::Continue; } angle::Result ContextGL::drawArraysIndirect(const gl::Context *context, gl::PrimitiveMode mode, const void *indirect) { getFunctions()->drawArraysIndirect(ToGLenum(mode), indirect); return angle::Result::Continue; } angle::Result ContextGL::drawElementsIndirect(const gl::Context *context, gl::PrimitiveMode mode, gl::DrawElementsType type, const void *indirect) { getFunctions()->drawElementsIndirect(ToGLenum(mode), ToGLenum(type), indirect); return angle::Result::Continue; } gl::GraphicsResetStatus ContextGL::getResetStatus() { return mRenderer->getResetStatus(); } std::string ContextGL::getVendorString() const { return mRenderer->getVendorString(); } std::string ContextGL::getRendererDescription() const { return mRenderer->getRendererDescription(); } angle::Result ContextGL::insertEventMarker(GLsizei length, const char *marker) { mRenderer->insertEventMarker(length, marker); return angle::Result::Continue; } angle::Result ContextGL::pushGroupMarker(GLsizei length, const char *marker) { mRenderer->pushGroupMarker(length, marker); return angle::Result::Continue; } angle::Result ContextGL::popGroupMarker() { mRenderer->popGroupMarker(); return angle::Result::Continue; } angle::Result ContextGL::pushDebugGroup(const gl::Context *context, GLenum source, GLuint id, const std::string &message) { mRenderer->pushDebugGroup(source, id, message); return angle::Result::Continue; } angle::Result ContextGL::popDebugGroup(const gl::Context *context) { mRenderer->popDebugGroup(); return angle::Result::Continue; } angle::Result ContextGL::syncState(const gl::Context *context, const gl::State::DirtyBits &dirtyBits, const gl::State::DirtyBits &bitMask) { return mRenderer->getStateManager()->syncState(context, dirtyBits, bitMask); } 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(); } StateManagerGL *ContextGL::getStateManager() { return mRenderer->getStateManager(); } const angle::FeaturesGL &ContextGL::getFeaturesGL() const { return mRenderer->getFeatures(); } 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); } void ContextGL::setMaxShaderCompilerThreads(GLuint count) { mRenderer->setMaxShaderCompilerThreads(count); } void ContextGL::invalidateTexture(gl::TextureType target) { mRenderer->getStateManager()->invalidateTexture(target); } void ContextGL::validateState() const { const StateManagerGL *stateManager = mRenderer->getStateManager(); stateManager->validateState(); } void ContextGL::setNeedsFlushBeforeDeleteTextures() { mRenderer->setNeedsFlushBeforeDeleteTextures(); } void ContextGL::flushIfNecessaryBeforeDeleteTextures() { mRenderer->flushIfNecessaryBeforeDeleteTextures(); } } // namespace rx