blob: 4a7f1a8fc6a47f82f93dfa5dd693a3d4404db174 [file] [log] [blame]
//
// Copyright 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/Context.h"
#include "libANGLE/Display.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)
{
return SH_GL_COMPATIBILITY_SPEC;
}
if (majorVersion >= 3)
{
switch (minorVersion)
{
case 2:
ASSERT(!isWebGL);
return SH_GLES3_2_SPEC;
case 1:
return isWebGL ? SH_WEBGL3_SPEC : SH_GLES3_1_SPEC;
case 0:
return isWebGL ? SH_WEBGL2_SPEC : SH_GLES3_SPEC;
default:
UNREACHABLE();
}
}
// 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, egl::Display *display)
: mImplementation(implFactory->createCompiler()),
mSpec(SelectShaderSpec(state.getClientMajorVersion(),
state.getClientMinorVersion(),
state.isWebGL(),
state.getClientType())),
mOutputType(mImplementation->getTranslatorOutputType()),
mResources()
{
// TODO(http://anglebug.com/3819): Update for GL version specific validation
ASSERT(state.getClientMajorVersion() == 1 || state.getClientMajorVersion() == 2 ||
state.getClientMajorVersion() == 3 || state.getClientMajorVersion() == 4);
const gl::Caps &caps = state.getCaps();
const gl::Extensions &extensions = state.getExtensions();
{
std::lock_guard<std::mutex> lock(display->getDisplayGlobalMutex());
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.standardDerivativesOES;
mResources.EXT_draw_buffers = extensions.drawBuffersEXT;
mResources.EXT_shader_texture_lod = extensions.shaderTextureLodEXT;
mResources.EXT_shader_non_constant_global_initializers =
extensions.shaderNonConstantGlobalInitializersEXT;
mResources.OES_EGL_image_external = extensions.EGLImageExternalOES;
mResources.OES_EGL_image_external_essl3 = extensions.EGLImageExternalEssl3OES;
mResources.NV_EGL_stream_consumer_external = extensions.EGLStreamConsumerExternalNV;
mResources.NV_shader_noperspective_interpolation =
extensions.shaderNoperspectiveInterpolationNV;
mResources.ARB_texture_rectangle = extensions.textureRectangleANGLE;
mResources.EXT_gpu_shader5 = extensions.gpuShader5EXT;
mResources.OES_shader_io_blocks = extensions.shaderIoBlocksOES;
mResources.EXT_shader_io_blocks = extensions.shaderIoBlocksEXT;
mResources.OES_texture_storage_multisample_2d_array =
extensions.textureStorageMultisample2dArrayOES;
mResources.OES_texture_3D = extensions.texture3DOES;
mResources.ANGLE_texture_multisample = extensions.textureMultisampleANGLE;
mResources.ANGLE_multi_draw = extensions.multiDrawANGLE;
mResources.ANGLE_base_vertex_base_instance_shader_builtin =
extensions.baseVertexBaseInstanceShaderBuiltinANGLE;
mResources.APPLE_clip_distance = extensions.clipDistanceAPPLE;
// OES_shader_multisample_interpolation
mResources.OES_shader_multisample_interpolation = extensions.shaderMultisampleInterpolationOES;
mResources.OES_shader_image_atomic = extensions.shaderImageAtomicOES;
// TODO: use shader precision caps to determine if high precision is supported?
mResources.FragmentPrecisionHigh = 1;
mResources.EXT_frag_depth = extensions.fragDepthEXT;
// OVR_multiview state
mResources.OVR_multiview = extensions.multiviewOVR;
// OVR_multiview2 state
mResources.OVR_multiview2 = extensions.multiview2OVR;
mResources.MaxViewsOVR = caps.maxViews;
// EXT_multisampled_render_to_texture and EXT_multisampled_render_to_texture2
mResources.EXT_multisampled_render_to_texture = extensions.multisampledRenderToTextureEXT;
mResources.EXT_multisampled_render_to_texture2 = extensions.multisampledRenderToTexture2EXT;
// WEBGL_video_texture
mResources.WEBGL_video_texture = extensions.videoTextureWEBGL;
// OES_texture_cube_map_array
mResources.OES_texture_cube_map_array = extensions.textureCubeMapArrayOES;
mResources.EXT_texture_cube_map_array = extensions.textureCubeMapArrayEXT;
// EXT_shadow_samplers
mResources.EXT_shadow_samplers = extensions.shadowSamplersEXT;
// OES_texture_buffer
mResources.OES_texture_buffer = extensions.textureBufferOES;
mResources.EXT_texture_buffer = extensions.textureBufferEXT;
// GL_EXT_YUV_target
mResources.EXT_YUV_target = extensions.YUVTargetEXT;
mResources.EXT_shader_framebuffer_fetch_non_coherent =
extensions.shaderFramebufferFetchNonCoherentEXT;
// GL_EXT_clip_cull_distance
mResources.EXT_clip_cull_distance = extensions.clipCullDistanceEXT;
// GL_EXT_primitive_bounding_box
mResources.EXT_primitive_bounding_box = extensions.primitiveBoundingBoxEXT;
// 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.blendFuncExtendedEXT;
mResources.MaxDualSourceDrawBuffers = caps.maxDualSourceDrawBuffers;
// APPLE_clip_distance/EXT_clip_cull_distance
mResources.MaxClipDistances = caps.maxClipDistances;
mResources.MaxCullDistances = caps.maxCullDistances;
mResources.MaxCombinedClipAndCullDistances = caps.maxCombinedClipAndCullDistances;
// OES_sample_variables
mResources.OES_sample_variables = extensions.sampleVariablesOES;
mResources.MaxSamples = caps.maxSamples;
// 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.drawBuffersEXT)
{
mResources.MaxDrawBuffers = 1;
}
// Geometry Shader constants
mResources.EXT_geometry_shader = extensions.geometryShaderEXT;
mResources.OES_geometry_shader = extensions.geometryShaderOES;
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];
// Tessellation Shader constants
mResources.EXT_tessellation_shader = extensions.tessellationShaderEXT;
mResources.MaxTessControlInputComponents = caps.maxTessControlInputComponents;
mResources.MaxTessControlOutputComponents = caps.maxTessControlOutputComponents;
mResources.MaxTessControlTextureImageUnits =
caps.maxShaderTextureImageUnits[ShaderType::TessControl];
mResources.MaxTessControlUniformComponents =
caps.maxShaderUniformComponents[ShaderType::TessControl];
mResources.MaxTessControlTotalOutputComponents = caps.maxTessControlTotalOutputComponents;
mResources.MaxTessControlImageUniforms = caps.maxShaderImageUniforms[ShaderType::TessControl];
mResources.MaxTessControlAtomicCounters = caps.maxShaderAtomicCounters[ShaderType::TessControl];
mResources.MaxTessControlAtomicCounterBuffers =
caps.maxShaderAtomicCounterBuffers[ShaderType::TessControl];
mResources.MaxTessPatchComponents = caps.maxTessPatchComponents;
mResources.MaxPatchVertices = caps.maxPatchVertices;
mResources.MaxTessGenLevel = caps.maxTessGenLevel;
mResources.MaxTessEvaluationInputComponents = caps.maxTessEvaluationInputComponents;
mResources.MaxTessEvaluationOutputComponents = caps.maxTessEvaluationOutputComponents;
mResources.MaxTessEvaluationTextureImageUnits =
caps.maxShaderTextureImageUnits[ShaderType::TessEvaluation];
mResources.MaxTessEvaluationUniformComponents =
caps.maxShaderUniformComponents[ShaderType::TessEvaluation];
mResources.MaxTessEvaluationImageUniforms =
caps.maxShaderImageUniforms[ShaderType::TessEvaluation];
mResources.MaxTessEvaluationAtomicCounters =
caps.maxShaderAtomicCounters[ShaderType::TessEvaluation];
mResources.MaxTessEvaluationAtomicCounterBuffers =
caps.maxShaderAtomicCounterBuffers[ShaderType::TessEvaluation];
// Subpixel bits.
mResources.SubPixelBits = static_cast<int>(caps.subPixelBits);
// Direct-to-metal constants:
mResources.DriverUniformsBindingIndex = caps.driverUniformsBindingIndex;
mResources.DefaultUniformsBindingIndex = caps.defaultUniformsBindingIndex;
mResources.UBOArgumentBufferBindingIndex = caps.UBOArgumentBufferBindingIndex;
}
Compiler::~Compiler() = default;
void Compiler::onDestroy(const Context *context)
{
std::lock_guard<std::mutex> lock(context->getDisplay()->getDisplayGlobalMutex());
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