// // Copyright (c) 2014 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. // // Compiler.cpp: implements the gl::Compiler class. #include "libANGLE/Compiler.h" #include "common/debug.h" #include "libANGLE/State.h" #include "libANGLE/renderer/CompilerImpl.h" #include "libANGLE/renderer/GLImplFactory.h" namespace gl { namespace { // To know when to call sh::Initialize and sh::Finalize. size_t gActiveCompilers = 0; ShShaderSpec SelectShaderSpec(GLint majorVersion, GLint minorVersion, bool isWebGL, EGLenum clientType) { // For Desktop GL if (clientType == EGL_OPENGL_API) { ASSERT(majorVersion == 3 && minorVersion == 3); return SH_GL3_3_SPEC; } if (majorVersion >= 3) { if (minorVersion == 1) { return isWebGL ? SH_WEBGL3_SPEC : SH_GLES3_1_SPEC; } else { return isWebGL ? SH_WEBGL2_SPEC : SH_GLES3_SPEC; } } // GLES1 emulation: Use GLES3 shader spec. if (!isWebGL && majorVersion == 1) { return SH_GLES3_SPEC; } return isWebGL ? SH_WEBGL_SPEC : SH_GLES2_SPEC; } } // anonymous namespace Compiler::Compiler(rx::GLImplFactory *implFactory, const State &state) : mImplementation(implFactory->createCompiler()), mSpec(SelectShaderSpec(state.getClientMajorVersion(), state.getClientMinorVersion(), state.getExtensions().webglCompatibility, state.getClientType())), mOutputType(mImplementation->getTranslatorOutputType()), mResources() { ASSERT(state.getClientMajorVersion() == 1 || state.getClientMajorVersion() == 2 || state.getClientMajorVersion() == 3); const gl::Caps &caps = state.getCaps(); const gl::Extensions &extensions = state.getExtensions(); if (gActiveCompilers == 0) { sh::Initialize(); } ++gActiveCompilers; sh::InitBuiltInResources(&mResources); mResources.MaxVertexAttribs = caps.maxVertexAttributes; mResources.MaxVertexUniformVectors = caps.maxVertexUniformVectors; mResources.MaxVaryingVectors = caps.maxVaryingVectors; mResources.MaxVertexTextureImageUnits = caps.maxShaderTextureImageUnits[ShaderType::Vertex]; mResources.MaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits; mResources.MaxTextureImageUnits = caps.maxShaderTextureImageUnits[ShaderType::Fragment]; mResources.MaxFragmentUniformVectors = caps.maxFragmentUniformVectors; mResources.MaxDrawBuffers = caps.maxDrawBuffers; mResources.OES_standard_derivatives = extensions.standardDerivatives; mResources.EXT_draw_buffers = extensions.drawBuffers; mResources.EXT_shader_texture_lod = extensions.shaderTextureLOD; mResources.OES_EGL_image_external = extensions.eglImageExternal; mResources.OES_EGL_image_external_essl3 = extensions.eglImageExternalEssl3; mResources.NV_EGL_stream_consumer_external = extensions.eglStreamConsumerExternal; mResources.ARB_texture_rectangle = extensions.textureRectangle; mResources.OES_texture_storage_multisample_2d_array = extensions.textureStorageMultisample2DArray; mResources.OES_texture_3D = extensions.texture3DOES; mResources.ANGLE_texture_multisample = extensions.textureMultisample; mResources.ANGLE_multi_draw = extensions.multiDraw; mResources.ANGLE_base_vertex_base_instance = extensions.baseVertexBaseInstance; // TODO: use shader precision caps to determine if high precision is supported? mResources.FragmentPrecisionHigh = 1; mResources.EXT_frag_depth = extensions.fragDepth; // OVR_multiview state mResources.OVR_multiview = extensions.multiview; // OVR_multiview2 state mResources.OVR_multiview2 = extensions.multiview2; mResources.MaxViewsOVR = extensions.maxViews; // GLSL ES 3.0 constants mResources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4; mResources.MaxFragmentInputVectors = caps.maxFragmentInputComponents / 4; mResources.MinProgramTexelOffset = caps.minProgramTexelOffset; mResources.MaxProgramTexelOffset = caps.maxProgramTexelOffset; // EXT_blend_func_extended mResources.EXT_blend_func_extended = extensions.blendFuncExtended; mResources.MaxDualSourceDrawBuffers = extensions.maxDualSourceDrawBuffers; // GLSL ES 3.1 constants mResources.MaxProgramTextureGatherOffset = caps.maxProgramTextureGatherOffset; mResources.MinProgramTextureGatherOffset = caps.minProgramTextureGatherOffset; mResources.MaxImageUnits = caps.maxImageUnits; mResources.MaxVertexImageUniforms = caps.maxShaderImageUniforms[ShaderType::Vertex]; mResources.MaxFragmentImageUniforms = caps.maxShaderImageUniforms[ShaderType::Fragment]; mResources.MaxComputeImageUniforms = caps.maxShaderImageUniforms[ShaderType::Compute]; mResources.MaxCombinedImageUniforms = caps.maxCombinedImageUniforms; mResources.MaxCombinedShaderOutputResources = caps.maxCombinedShaderOutputResources; mResources.MaxUniformLocations = caps.maxUniformLocations; for (size_t index = 0u; index < 3u; ++index) { mResources.MaxComputeWorkGroupCount[index] = caps.maxComputeWorkGroupCount[index]; mResources.MaxComputeWorkGroupSize[index] = caps.maxComputeWorkGroupSize[index]; } mResources.MaxComputeUniformComponents = caps.maxShaderUniformComponents[ShaderType::Compute]; mResources.MaxComputeTextureImageUnits = caps.maxShaderTextureImageUnits[ShaderType::Compute]; mResources.MaxComputeAtomicCounters = caps.maxShaderAtomicCounters[ShaderType::Compute]; mResources.MaxComputeAtomicCounterBuffers = caps.maxShaderAtomicCounterBuffers[ShaderType::Compute]; mResources.MaxVertexAtomicCounters = caps.maxShaderAtomicCounters[ShaderType::Vertex]; mResources.MaxFragmentAtomicCounters = caps.maxShaderAtomicCounters[ShaderType::Fragment]; mResources.MaxCombinedAtomicCounters = caps.maxCombinedAtomicCounters; mResources.MaxAtomicCounterBindings = caps.maxAtomicCounterBufferBindings; mResources.MaxVertexAtomicCounterBuffers = caps.maxShaderAtomicCounterBuffers[ShaderType::Vertex]; mResources.MaxFragmentAtomicCounterBuffers = caps.maxShaderAtomicCounterBuffers[ShaderType::Fragment]; mResources.MaxCombinedAtomicCounterBuffers = caps.maxCombinedAtomicCounterBuffers; mResources.MaxAtomicCounterBufferSize = caps.maxAtomicCounterBufferSize; mResources.MaxUniformBufferBindings = caps.maxUniformBufferBindings; mResources.MaxShaderStorageBufferBindings = caps.maxShaderStorageBufferBindings; // Needed by point size clamping workaround mResources.MaxPointSize = caps.maxAliasedPointSize; if (state.getClientMajorVersion() == 2 && !extensions.drawBuffers) { mResources.MaxDrawBuffers = 1; } // Geometry Shader constants mResources.EXT_geometry_shader = extensions.geometryShader; mResources.MaxGeometryUniformComponents = caps.maxShaderUniformComponents[ShaderType::Geometry]; mResources.MaxGeometryUniformBlocks = caps.maxShaderUniformBlocks[ShaderType::Geometry]; mResources.MaxGeometryInputComponents = caps.maxGeometryInputComponents; mResources.MaxGeometryOutputComponents = caps.maxGeometryOutputComponents; mResources.MaxGeometryOutputVertices = caps.maxGeometryOutputVertices; mResources.MaxGeometryTotalOutputComponents = caps.maxGeometryTotalOutputComponents; mResources.MaxGeometryTextureImageUnits = caps.maxShaderTextureImageUnits[ShaderType::Geometry]; mResources.MaxGeometryAtomicCounterBuffers = caps.maxShaderAtomicCounterBuffers[ShaderType::Geometry]; mResources.MaxGeometryAtomicCounters = caps.maxShaderAtomicCounters[ShaderType::Geometry]; mResources.MaxGeometryShaderStorageBlocks = caps.maxShaderStorageBlocks[ShaderType::Geometry]; mResources.MaxGeometryShaderInvocations = caps.maxGeometryShaderInvocations; mResources.MaxGeometryImageUniforms = caps.maxShaderImageUniforms[ShaderType::Geometry]; } Compiler::~Compiler() { for (auto &pool : mPools) { for (ShCompilerInstance &instance : pool) { instance.destroy(); } } --gActiveCompilers; if (gActiveCompilers == 0) { sh::Finalize(); } } ShCompilerInstance Compiler::getInstance(ShaderType type) { ASSERT(type != ShaderType::InvalidEnum); auto &pool = mPools[type]; if (pool.empty()) { ShHandle handle = sh::ConstructCompiler(ToGLenum(type), mSpec, mOutputType, &mResources); ASSERT(handle); return ShCompilerInstance(handle, mOutputType, type); } else { ShCompilerInstance instance = std::move(pool.back()); pool.pop_back(); return instance; } } void Compiler::putInstance(ShCompilerInstance &&instance) { static constexpr size_t kMaxPoolSize = 32; auto &pool = mPools[instance.getShaderType()]; if (pool.size() < kMaxPoolSize) { pool.push_back(std::move(instance)); } else { instance.destroy(); } } ShCompilerInstance::ShCompilerInstance() : mHandle(nullptr) {} ShCompilerInstance::ShCompilerInstance(ShHandle handle, ShShaderOutput outputType, ShaderType shaderType) : mHandle(handle), mOutputType(outputType), mShaderType(shaderType) {} ShCompilerInstance::~ShCompilerInstance() { ASSERT(mHandle == nullptr); } void ShCompilerInstance::destroy() { if (mHandle != nullptr) { sh::Destruct(mHandle); mHandle = nullptr; } } ShCompilerInstance::ShCompilerInstance(ShCompilerInstance &&other) : mHandle(other.mHandle), mOutputType(other.mOutputType), mShaderType(other.mShaderType) { other.mHandle = nullptr; } ShCompilerInstance &ShCompilerInstance::operator=(ShCompilerInstance &&other) { mHandle = other.mHandle; mOutputType = other.mOutputType; mShaderType = other.mShaderType; other.mHandle = nullptr; return *this; } ShHandle ShCompilerInstance::getHandle() { return mHandle; } ShaderType ShCompilerInstance::getShaderType() const { return mShaderType; } const std::string &ShCompilerInstance::getBuiltinResourcesString() { return sh::GetBuiltInResourcesString(mHandle); } ShShaderOutput ShCompilerInstance::getShaderOutputType() const { return mOutputType; } } // namespace gl