Support resource limits in C, C++ API
diff --git a/libshaderc/include/shaderc/shaderc.h b/libshaderc/include/shaderc/shaderc.h
index 64d94ea..26d5421 100644
--- a/libshaderc/include/shaderc/shaderc.h
+++ b/libshaderc/include/shaderc/shaderc.h
@@ -86,6 +86,93 @@
   shaderc_optimization_level_size,  // optimize towards reducing code size
 } shaderc_optimization_level;
 
+// Resource limits.
+typedef enum {
+  shaderc_limit_max_lights,
+  shaderc_limit_max_clip_planes,
+  shaderc_limit_max_texture_units,
+  shaderc_limit_max_texture_coords,
+  shaderc_limit_max_vertex_attribs,
+  shaderc_limit_max_vertex_uniform_components,
+  shaderc_limit_max_varying_floats,
+  shaderc_limit_max_vertex_texture_image_units,
+  shaderc_limit_max_combined_texture_image_units,
+  shaderc_limit_max_texture_image_units,
+  shaderc_limit_max_fragment_uniform_components,
+  shaderc_limit_max_draw_buffers,
+  shaderc_limit_max_vertex_uniform_vectors,
+  shaderc_limit_max_varying_vectors,
+  shaderc_limit_max_fragment_uniform_vectors,
+  shaderc_limit_max_vertex_output_vectors,
+  shaderc_limit_max_fragment_input_vectors,
+  shaderc_limit_min_program_texel_offset,
+  shaderc_limit_max_program_texel_offset,
+  shaderc_limit_max_clip_distances,
+  shaderc_limit_max_compute_work_group_count_x,
+  shaderc_limit_max_compute_work_group_count_y,
+  shaderc_limit_max_compute_work_group_count_z,
+  shaderc_limit_max_compute_work_group_size_x,
+  shaderc_limit_max_compute_work_group_size_y,
+  shaderc_limit_max_compute_work_group_size_z,
+  shaderc_limit_max_compute_uniform_components,
+  shaderc_limit_max_compute_texture_image_units,
+  shaderc_limit_max_compute_image_uniforms,
+  shaderc_limit_max_compute_atomic_counters,
+  shaderc_limit_max_compute_atomic_counter_buffers,
+  shaderc_limit_max_varying_components,
+  shaderc_limit_max_vertex_output_components,
+  shaderc_limit_max_geometry_input_components,
+  shaderc_limit_max_geometry_output_components,
+  shaderc_limit_max_fragment_input_components,
+  shaderc_limit_max_image_units,
+  shaderc_limit_max_combined_image_units_and_fragment_outputs,
+  shaderc_limit_max_combined_shader_output_resources,
+  shaderc_limit_max_image_samples,
+  shaderc_limit_max_vertex_image_uniforms,
+  shaderc_limit_max_tess_control_image_uniforms,
+  shaderc_limit_max_tess_evaluation_image_uniforms,
+  shaderc_limit_max_geometry_image_uniforms,
+  shaderc_limit_max_fragment_image_uniforms,
+  shaderc_limit_max_combined_image_uniforms,
+  shaderc_limit_max_geometry_texture_image_units,
+  shaderc_limit_max_geometry_output_vertices,
+  shaderc_limit_max_geometry_total_output_components,
+  shaderc_limit_max_geometry_uniform_components,
+  shaderc_limit_max_geometry_varying_components,
+  shaderc_limit_max_tess_control_input_components,
+  shaderc_limit_max_tess_control_output_components,
+  shaderc_limit_max_tess_control_texture_image_units,
+  shaderc_limit_max_tess_control_uniform_components,
+  shaderc_limit_max_tess_control_total_output_components,
+  shaderc_limit_max_tess_evaluation_input_components,
+  shaderc_limit_max_tess_evaluation_output_components,
+  shaderc_limit_max_tess_evaluation_texture_image_units,
+  shaderc_limit_max_tess_evaluation_uniform_components,
+  shaderc_limit_max_tess_patch_components,
+  shaderc_limit_max_patch_vertices,
+  shaderc_limit_max_tess_gen_level,
+  shaderc_limit_max_viewports,
+  shaderc_limit_max_vertex_atomic_counters,
+  shaderc_limit_max_tess_control_atomic_counters,
+  shaderc_limit_max_tess_evaluation_atomic_counters,
+  shaderc_limit_max_geometry_atomic_counters,
+  shaderc_limit_max_fragment_atomic_counters,
+  shaderc_limit_max_combined_atomic_counters,
+  shaderc_limit_max_atomic_counter_bindings,
+  shaderc_limit_max_vertex_atomic_counter_buffers,
+  shaderc_limit_max_tess_control_atomic_counter_buffers,
+  shaderc_limit_max_tess_evaluation_atomic_counter_buffers,
+  shaderc_limit_max_geometry_atomic_counter_buffers,
+  shaderc_limit_max_fragment_atomic_counter_buffers,
+  shaderc_limit_max_combined_atomic_counter_buffers,
+  shaderc_limit_max_atomic_counter_buffer_size,
+  shaderc_limit_max_transform_feedback_buffers,
+  shaderc_limit_max_transform_feedback_interleaved_components,
+  shaderc_limit_max_cull_distances,
+  shaderc_limit_max_combined_clip_and_cull_distances,
+  shaderc_limit_max_samples,
+} shaderc_limit;
+
 // Usage examples:
 //
 // Aggressively release compiler resources, but spend time in initialization
@@ -255,6 +342,10 @@
 void shaderc_compile_options_set_warnings_as_errors(
     shaderc_compile_options_t options);
 
+// Sets a resource limit.
+void shaderc_compile_options_set_limit(
+    shaderc_compile_options_t options, shaderc_limit limit, int value);
+
 // An opaque handle to the results of a call to any shaderc_compile_into_*()
 // function.
 typedef struct shaderc_compilation_result* shaderc_compilation_result_t;
diff --git a/libshaderc/include/shaderc/shaderc.hpp b/libshaderc/include/shaderc/shaderc.hpp
index a3facfc..3023ebb 100644
--- a/libshaderc/include/shaderc/shaderc.hpp
+++ b/libshaderc/include/shaderc/shaderc.hpp
@@ -243,6 +243,11 @@
     shaderc_compile_options_set_warnings_as_errors(options_);
   }
 
+  // Sets a resource limit.
+  void SetLimit(shaderc_limit limit, int value) {
+    shaderc_compile_options_set_limit(options_, limit, value);
+  }
+
  private:
   CompileOptions& operator=(const CompileOptions& other) = delete;
   shaderc_compile_options_t options_;
diff --git a/libshaderc/src/shaderc.cc b/libshaderc/src/shaderc.cc
index 15d16d2..c7b6ef2 100644
--- a/libshaderc/src/shaderc.cc
+++ b/libshaderc/src/shaderc.cc
@@ -238,6 +238,20 @@
   return shaderc_util::Compiler::TargetEnv::Vulkan;
 }
 
+// Returns the Compiler::Limit enum for the given shaderc_limit enum.
+shaderc_util::Compiler::Limit CompilerLimit(shaderc_limit limit) {
+  switch (limit) {
+#define RESOURCE(NAME,FIELD,CNAME) \
+     case shaderc_limit_##CNAME: return shaderc_util::Compiler::Limit::NAME;
+#include "libshaderc_util/resources.inc"
+#undef RESOURCE
+    default:
+      break;
+  }
+  assert(0 && "Should not have reached here");
+  return static_cast<shaderc_util::Compiler::Limit>(0);
+}
+
 }  // anonymous namespace
 
 struct shaderc_compile_options {
@@ -346,6 +360,11 @@
   options->compiler.SetWarningsAsErrors();
 }
 
+void shaderc_compile_options_set_limit(
+    shaderc_compile_options_t options, shaderc_limit limit, int value) {
+  options->compiler.SetLimit(CompilerLimit(limit), value);
+}
+
 shaderc_compiler_t shaderc_compiler_initialize() {
   static shaderc_util::GlslangInitializer* initializer =
       new shaderc_util::GlslangInitializer;
diff --git a/libshaderc/src/shaderc_cpp_test.cc b/libshaderc/src/shaderc_cpp_test.cc
index 6917e59..bf5aa33 100644
--- a/libshaderc/src/shaderc_cpp_test.cc
+++ b/libshaderc/src/shaderc_cpp_test.cc
@@ -1100,4 +1100,52 @@
               HasSubstr("OpEntryPoint Vertex %EntryPoint \"EntryPoint\""));
 }
 
+// Returns a fragment shader accessing a texture with the given
+// offset.
+std::string ShaderWithTexOffset(int offset) {
+  std::ostringstream oss;
+  oss <<
+    "#version 150\n"
+    "uniform sampler1D tex;\n"
+    "void main() { vec4 x = textureOffset(tex, 1.0, " << offset << "); }\n";
+  return oss.str();
+}
+
+// Ensure compilation is sensitive to limit setting.  Sample just
+// two particular limits.
+TEST_F(CppInterface, LimitsTexelOffsetDefault) {
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-9).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_));
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-8).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_));
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(7).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_));
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(8).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_));
+}
+
+TEST_F(CppInterface, LimitsTexelOffsetLowerMinimum) {
+  options_.SetLimit(shaderc_limit_min_program_texel_offset, -99);
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-100).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_));
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-99).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_));
+}
+
+TEST_F(CppInterface, LimitsTexelOffsetHigherMaximum) {
+  options_.SetLimit(shaderc_limit_max_program_texel_offset, 10);
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(10).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_));
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(11).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_));
+}
+
 }  // anonymous namespace
diff --git a/libshaderc/src/shaderc_test.cc b/libshaderc/src/shaderc_test.cc
index bde5cf0..927a53d 100644
--- a/libshaderc/src/shaderc_test.cc
+++ b/libshaderc/src/shaderc_test.cc
@@ -1373,4 +1373,56 @@
       << std::string(shaderc_result_get_bytes(compilation.result()));
 }
 
+// Returns a fragment shader accessing a texture with the given
+// offset.
+std::string ShaderWithTexOffset(int offset) {
+  std::ostringstream oss;
+  oss <<
+    "#version 150\n"
+    "uniform sampler1D tex;\n"
+    "void main() { vec4 x = textureOffset(tex, 1.0, " << offset << "); }\n";
+  return oss.str();
+}
+
+// Ensure compilation is sensitive to limit setting.  Sample just
+// two particular limits.
+TEST_F(CompileStringTest, LimitsTexelOffsetDefault) {
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-9).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_.get()));
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-8).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_.get()));
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(7).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_.get()));
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(8).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_.get()));
+}
+
+TEST_F(CompileStringTest, LimitsTexelOffsetLowerMinimum) {
+  shaderc_compile_options_set_limit(options_.get(),
+                                    shaderc_limit_min_program_texel_offset,
+                                    -99);
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(-100).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_.get()));
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(-99).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_.get()));
+}
+
+TEST_F(CompileStringTest, LimitsTexelOffsetHigherMaximum) {
+  shaderc_compile_options_set_limit(options_.get(),
+                                    shaderc_limit_max_program_texel_offset,
+                                    10);
+  EXPECT_TRUE(CompilationSuccess(ShaderWithTexOffset(10).c_str(),
+                                 shaderc_glsl_fragment_shader,
+                                 options_.get()));
+  EXPECT_FALSE(CompilationSuccess(ShaderWithTexOffset(11).c_str(),
+                                  shaderc_glsl_fragment_shader,
+                                  options_.get()));
+}
+
 }  // anonymous namespace
diff --git a/libshaderc_util/include/libshaderc_util/compiler.h b/libshaderc_util/include/libshaderc_util/compiler.h
index fc47766..50ab01c 100644
--- a/libshaderc_util/include/libshaderc_util/compiler.h
+++ b/libshaderc_util/include/libshaderc_util/compiler.h
@@ -26,6 +26,7 @@
 #include "counting_includer.h"
 #include "file_finder.h"
 #include "mutex.h"
+#include "resources.h"
 #include "string_piece.h"
 
 namespace shaderc_util {
@@ -117,6 +118,13 @@
     Size,  // Optimization towards reducing code size.
   };
 
+  // Resource limits.  These map to the "max*" fields in glslang::TBuiltInResource.
+  enum class Limit {
+#define RESOURCE(NAME,FIELD,CNAME) NAME,
+#include "resources.inc"
+#undef RESOURCE
+  };
+
   // Creates an default compiler instance targeting at Vulkan environment. Uses
   // version 110 and no profile specification as the default for GLSL.
   Compiler()
@@ -130,7 +138,8 @@
         generate_debug_info_(false),
         enabled_opt_passes_(),
         target_env_(TargetEnv::Vulkan),
-        source_language_(SourceLanguage::GLSL) {}
+        source_language_(SourceLanguage::GLSL),
+        limits_(kDefaultTBuiltInResource) {}
 
   // Requests that the compiler place debug information into the object code,
   // such as identifier names and line numbers.
@@ -163,14 +172,19 @@
   // subsequent CompileShader() calls.
   void SetForcedVersionProfile(int version, EProfile profile);
 
+  // Sets a resource limit.
+  void SetLimit(Limit limit, int value);
+
+  // Returns the current limit.
+  int GetLimit(Limit limit) const;
+
   // Compiles the shader source in the input_source_string parameter.
   //
   // If the forced_shader stage parameter is not EShLangCount then
   // the shader is assumed to be of the given stage.
   //
   // For HLSL compilation, entry_point_name is the null-terminated string for
-  // the
-  // entry point.  For GLSL compilation, entry_point_name is ignored, and
+  // the entry point.  For GLSL compilation, entry_point_name is ignored, and
   // compilation assumes the entry point is named "main".
   //
   // The stage_callback function will be called if a shader_stage has
@@ -310,6 +324,9 @@
 
   // The source language.  Defaults to GLSL.
   SourceLanguage source_language_;
+
+  // The resource limits to be used.
+  TBuiltInResource limits_;
 };
 
 // Converts a string to a vector of uint32_t by copying the content of a given
diff --git a/libshaderc_util/include/libshaderc_util/resources.h b/libshaderc_util/include/libshaderc_util/resources.h
index 5b185b8..a8f635b 100644
--- a/libshaderc_util/include/libshaderc_util/resources.h
+++ b/libshaderc_util/include/libshaderc_util/resources.h
@@ -15,10 +15,13 @@
 #ifndef LIBSHADERC_UTIL_RESOURCES_H_
 #define LIBSHADERC_UTIL_RESOURCES_H_
 
-struct TBuiltInResource;
+// We want TBuiltInResource
+#include "glslang/Include/ResourceLimits.h"
 
 namespace shaderc_util {
 
+using TBuiltInResource = ::TBuiltInResource;
+
 // A set of suitable defaults.
 extern const TBuiltInResource kDefaultTBuiltInResource;
 
diff --git a/libshaderc_util/include/libshaderc_util/resources.inc b/libshaderc_util/include/libshaderc_util/resources.inc
new file mode 100644
index 0000000..8e86f01
--- /dev/null
+++ b/libshaderc_util/include/libshaderc_util/resources.inc
@@ -0,0 +1,107 @@
+// Copyright 2016 The Shaderc Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// These are the resource limits in a glslang::TBuiltInResource.
+// The first field is the string name to be used in a configuration setting.
+// The second field is the fieldname in TBuiltInResource.
+// The third field is the enum name fragment for shaderc_limit.
+//
+// TODO(dneto): Consider using a single list of names, but use a Python script
+// to generate *this* file.  The original data file would have the first field,
+// then generate the second field by lowering the case of the first letter, and
+// generate the third field by taking the second field, and converting a
+// lower-to-upper case transition into an underscore with lower-case.
+RESOURCE(MaxLights,maxLights,max_lights)
+RESOURCE(MaxClipPlanes,maxClipPlanes,max_clip_planes)
+RESOURCE(MaxTextureUnits,maxTextureUnits,max_texture_units)
+RESOURCE(MaxTextureCoords,maxTextureCoords,max_texture_coords)
+RESOURCE(MaxVertexAttribs,maxVertexAttribs,max_vertex_attribs)
+RESOURCE(MaxVertexUniformComponents,maxVertexUniformComponents,max_vertex_uniform_components)
+RESOURCE(MaxVaryingFloats,maxVaryingFloats,max_varying_floats)
+RESOURCE(MaxVertexTextureImageUnits,maxVertexTextureImageUnits,max_vertex_texture_image_units)
+RESOURCE(MaxCombinedTextureImageUnits,maxCombinedTextureImageUnits,max_combined_texture_image_units)
+RESOURCE(MaxTextureImageUnits,maxTextureImageUnits,max_texture_image_units)
+RESOURCE(MaxFragmentUniformComponents,maxFragmentUniformComponents,max_fragment_uniform_components)
+RESOURCE(MaxDrawBuffers,maxDrawBuffers,max_draw_buffers)
+RESOURCE(MaxVertexUniformVectors,maxVertexUniformVectors,max_vertex_uniform_vectors)
+RESOURCE(MaxVaryingVectors,maxVaryingVectors,max_varying_vectors)
+RESOURCE(MaxFragmentUniformVectors,maxFragmentUniformVectors,max_fragment_uniform_vectors)
+RESOURCE(MaxVertexOutputVectors,maxVertexOutputVectors,max_vertex_output_vectors)
+RESOURCE(MaxFragmentInputVectors,maxFragmentInputVectors,max_fragment_input_vectors)
+RESOURCE(MinProgramTexelOffset,minProgramTexelOffset,min_program_texel_offset)
+RESOURCE(MaxProgramTexelOffset,maxProgramTexelOffset,max_program_texel_offset)
+RESOURCE(MaxClipDistances,maxClipDistances,max_clip_distances)
+RESOURCE(MaxComputeWorkGroupCountX,maxComputeWorkGroupCountX,max_compute_work_group_count_x)
+RESOURCE(MaxComputeWorkGroupCountY,maxComputeWorkGroupCountY,max_compute_work_group_count_y)
+RESOURCE(MaxComputeWorkGroupCountZ,maxComputeWorkGroupCountZ,max_compute_work_group_count_z)
+RESOURCE(MaxComputeWorkGroupSizeX,maxComputeWorkGroupSizeX,max_compute_work_group_size_x)
+RESOURCE(MaxComputeWorkGroupSizeY,maxComputeWorkGroupSizeY,max_compute_work_group_size_y)
+RESOURCE(MaxComputeWorkGroupSizeZ,maxComputeWorkGroupSizeZ,max_compute_work_group_size_z)
+RESOURCE(MaxComputeUniformComponents,maxComputeUniformComponents,max_compute_uniform_components)
+RESOURCE(MaxComputeTextureImageUnits,maxComputeTextureImageUnits,max_compute_texture_image_units)
+RESOURCE(MaxComputeImageUniforms,maxComputeImageUniforms,max_compute_image_uniforms)
+RESOURCE(MaxComputeAtomicCounters,maxComputeAtomicCounters,max_compute_atomic_counters)
+RESOURCE(MaxComputeAtomicCounterBuffers,maxComputeAtomicCounterBuffers,max_compute_atomic_counter_buffers)
+RESOURCE(MaxVaryingComponents,maxVaryingComponents,max_varying_components)
+RESOURCE(MaxVertexOutputComponents,maxVertexOutputComponents,max_vertex_output_components)
+RESOURCE(MaxGeometryInputComponents,maxGeometryInputComponents,max_geometry_input_components)
+RESOURCE(MaxGeometryOutputComponents,maxGeometryOutputComponents,max_geometry_output_components)
+RESOURCE(MaxFragmentInputComponents,maxFragmentInputComponents,max_fragment_input_components)
+RESOURCE(MaxImageUnits,maxImageUnits,max_image_units)
+RESOURCE(MaxCombinedImageUnitsAndFragmentOutputs,maxCombinedImageUnitsAndFragmentOutputs,max_combined_image_units_and_fragment_outputs)
+RESOURCE(MaxCombinedShaderOutputResources,maxCombinedShaderOutputResources,max_combined_shader_output_resources)
+RESOURCE(MaxImageSamples,maxImageSamples,max_image_samples)
+RESOURCE(MaxVertexImageUniforms,maxVertexImageUniforms,max_vertex_image_uniforms)
+RESOURCE(MaxTessControlImageUniforms,maxTessControlImageUniforms,max_tess_control_image_uniforms)
+RESOURCE(MaxTessEvaluationImageUniforms,maxTessEvaluationImageUniforms,max_tess_evaluation_image_uniforms)
+RESOURCE(MaxGeometryImageUniforms,maxGeometryImageUniforms,max_geometry_image_uniforms)
+RESOURCE(MaxFragmentImageUniforms,maxFragmentImageUniforms,max_fragment_image_uniforms)
+RESOURCE(MaxCombinedImageUniforms,maxCombinedImageUniforms,max_combined_image_uniforms)
+RESOURCE(MaxGeometryTextureImageUnits,maxGeometryTextureImageUnits,max_geometry_texture_image_units)
+RESOURCE(MaxGeometryOutputVertices,maxGeometryOutputVertices,max_geometry_output_vertices)
+RESOURCE(MaxGeometryTotalOutputComponents,maxGeometryTotalOutputComponents,max_geometry_total_output_components)
+RESOURCE(MaxGeometryUniformComponents,maxGeometryUniformComponents,max_geometry_uniform_components)
+RESOURCE(MaxGeometryVaryingComponents,maxGeometryVaryingComponents,max_geometry_varying_components)
+RESOURCE(MaxTessControlInputComponents,maxTessControlInputComponents,max_tess_control_input_components)
+RESOURCE(MaxTessControlOutputComponents,maxTessControlOutputComponents,max_tess_control_output_components)
+RESOURCE(MaxTessControlTextureImageUnits,maxTessControlTextureImageUnits,max_tess_control_texture_image_units)
+RESOURCE(MaxTessControlUniformComponents,maxTessControlUniformComponents,max_tess_control_uniform_components)
+RESOURCE(MaxTessControlTotalOutputComponents,maxTessControlTotalOutputComponents,max_tess_control_total_output_components)
+RESOURCE(MaxTessEvaluationInputComponents,maxTessEvaluationInputComponents,max_tess_evaluation_input_components)
+RESOURCE(MaxTessEvaluationOutputComponents,maxTessEvaluationOutputComponents,max_tess_evaluation_output_components)
+RESOURCE(MaxTessEvaluationTextureImageUnits,maxTessEvaluationTextureImageUnits,max_tess_evaluation_texture_image_units)
+RESOURCE(MaxTessEvaluationUniformComponents,maxTessEvaluationUniformComponents,max_tess_evaluation_uniform_components)
+RESOURCE(MaxTessPatchComponents,maxTessPatchComponents,max_tess_patch_components)
+RESOURCE(MaxPatchVertices,maxPatchVertices,max_patch_vertices)
+RESOURCE(MaxTessGenLevel,maxTessGenLevel,max_tess_gen_level)
+RESOURCE(MaxViewports,maxViewports,max_viewports)
+RESOURCE(MaxVertexAtomicCounters,maxVertexAtomicCounters,max_vertex_atomic_counters)
+RESOURCE(MaxTessControlAtomicCounters,maxTessControlAtomicCounters,max_tess_control_atomic_counters)
+RESOURCE(MaxTessEvaluationAtomicCounters,maxTessEvaluationAtomicCounters,max_tess_evaluation_atomic_counters)
+RESOURCE(MaxGeometryAtomicCounters,maxGeometryAtomicCounters,max_geometry_atomic_counters)
+RESOURCE(MaxFragmentAtomicCounters,maxFragmentAtomicCounters,max_fragment_atomic_counters)
+RESOURCE(MaxCombinedAtomicCounters,maxCombinedAtomicCounters,max_combined_atomic_counters)
+RESOURCE(MaxAtomicCounterBindings,maxAtomicCounterBindings,max_atomic_counter_bindings)
+RESOURCE(MaxVertexAtomicCounterBuffers,maxVertexAtomicCounterBuffers,max_vertex_atomic_counter_buffers)
+RESOURCE(MaxTessControlAtomicCounterBuffers,maxTessControlAtomicCounterBuffers,max_tess_control_atomic_counter_buffers)
+RESOURCE(MaxTessEvaluationAtomicCounterBuffers,maxTessEvaluationAtomicCounterBuffers,max_tess_evaluation_atomic_counter_buffers)
+RESOURCE(MaxGeometryAtomicCounterBuffers,maxGeometryAtomicCounterBuffers,max_geometry_atomic_counter_buffers)
+RESOURCE(MaxFragmentAtomicCounterBuffers,maxFragmentAtomicCounterBuffers,max_fragment_atomic_counter_buffers)
+RESOURCE(MaxCombinedAtomicCounterBuffers,maxCombinedAtomicCounterBuffers,max_combined_atomic_counter_buffers)
+RESOURCE(MaxAtomicCounterBufferSize,maxAtomicCounterBufferSize,max_atomic_counter_buffer_size)
+RESOURCE(MaxTransformFeedbackBuffers,maxTransformFeedbackBuffers,max_transform_feedback_buffers)
+RESOURCE(MaxTransformFeedbackInterleavedComponents,maxTransformFeedbackInterleavedComponents,max_transform_feedback_interleaved_components)
+RESOURCE(MaxCullDistances,maxCullDistances,max_cull_distances)
+RESOURCE(MaxCombinedClipAndCullDistances,maxCombinedClipAndCullDistances,max_combined_clip_and_cull_distances)
+RESOURCE(MaxSamples,maxSamples,max_samples)
diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc
index a170a4c..574ccfd 100644
--- a/libshaderc_util/src/compiler.cc
+++ b/libshaderc_util/src/compiler.cc
@@ -91,6 +91,29 @@
 }  // anonymous namespace
 
 namespace shaderc_util {
+
+void Compiler::SetLimit(Compiler::Limit limit, int value) {
+  switch (limit) {
+#define RESOURCE(NAME, FIELD, CNAME) \
+  case Limit::NAME:                  \
+    limits_.FIELD = value;           \
+    break;
+#include "libshaderc_util/resources.inc"
+#undef RESOURCE
+  }
+}
+
+int Compiler::GetLimit(Compiler::Limit limit) const {
+  switch (limit) {
+#define RESOURCE(NAME, FIELD, CNAME) \
+  case Limit::NAME:                  \
+    return limits_.FIELD;
+#include "libshaderc_util/resources.inc"
+#undef RESOURCE
+  }
+  return 0;  // Unreachable
+}
+
 std::tuple<bool, std::vector<uint32_t>, size_t> Compiler::Compile(
     const string_piece& input_source_string, EShLanguage forced_shader_stage,
     const std::string& error_tag, const char* entry_point_name,
@@ -183,10 +206,10 @@
   shader.setEntryPoint(entry_point_name);
 
   // TODO(dneto): Generate source-level debug info if requested.
-  bool success = shader.parse(
-      &shaderc_util::kDefaultTBuiltInResource, default_version_,
-      default_profile_, force_version_profile_, kNotForwardCompatible,
-      GetMessageRules(target_env_, source_language_), includer);
+  bool success =
+      shader.parse(&limits_, default_version_, default_profile_,
+                   force_version_profile_, kNotForwardCompatible,
+                   GetMessageRules(target_env_, source_language_), includer);
 
   success &= PrintFilteredErrors(error_tag, error_stream, warnings_as_errors_,
                                  suppress_warnings_, shader.getInfoLog(),
@@ -306,9 +329,8 @@
 
   std::string preprocessed_shader;
   const bool success = shader.preprocess(
-      &shaderc_util::kDefaultTBuiltInResource, default_version_,
-      default_profile_, force_version_profile_, kNotForwardCompatible, rules,
-      &preprocessed_shader, includer);
+      &limits_, default_version_, default_profile_, force_version_profile_,
+      kNotForwardCompatible, rules, &preprocessed_shader, includer);
 
   if (success) {
     return std::make_tuple(true, preprocessed_shader, shader.getInfoLog());
diff --git a/libshaderc_util/src/compiler_test.cc b/libshaderc_util/src/compiler_test.cc
index 3af7c22..9938848 100644
--- a/libshaderc_util/src/compiler_test.cc
+++ b/libshaderc_util/src/compiler_test.cc
@@ -25,6 +25,7 @@
 
 using shaderc_util::Compiler;
 using ::testing::HasSubstr;
+using ::testing::Eq;
 
 // A trivial vertex shader
 const char kVertexShader[] =
@@ -360,4 +361,73 @@
       << assembly;
 }
 
+// A test case for setting resource limits.
+struct SetLimitCase {
+  Compiler::Limit limit;
+  int default_value;
+  int value;
+};
+
+using LimitTest = testing::TestWithParam<SetLimitCase>;
+
+TEST_P(LimitTest, Sample) {
+  Compiler compiler;
+  EXPECT_THAT(compiler.GetLimit(GetParam().limit),
+              Eq(GetParam().default_value));
+  compiler.SetLimit(GetParam().limit, GetParam().value);
+  EXPECT_THAT(compiler.GetLimit(GetParam().limit), Eq(GetParam().value));
+}
+
+#define CASE(LIMIT, DEFAULT, NEW) \
+  { Compiler::Limit::LIMIT, DEFAULT, NEW }
+INSTANTIATE_TEST_CASE_P(
+    CompilerTest, LimitTest,
+    // See resources.cc for the defaults.
+    testing::ValuesIn(std::vector<SetLimitCase>{
+        // clang-format off
+        // This is just a sampling of the possible values.
+        CASE(MaxLights, 8, 99),
+        CASE(MaxClipPlanes, 6, 10929),
+        CASE(MaxTessControlAtomicCounters, 0, 72),
+        CASE(MaxSamples, 4, 8),
+        // clang-format on
+    }), );
+#undef CASE
+
+// Returns a fragment shader accessing a texture with the given
+// offset.
+std::string ShaderWithTexOffset(int offset) {
+  std::ostringstream oss;
+  oss << "#version 150\n"
+         "uniform sampler1D tex;\n"
+         "void main() { vec4 x = textureOffset(tex, 1.0, "
+      << offset << "); }\n";
+  return oss.str();
+}
+
+// Ensure compilation is sensitive to limit setting.  Sample just
+// two particular limits.  The default minimum texel offset is -8,
+// and the default maximum texel offset is 7.
+TEST_F(CompilerTest, TexelOffsetDefaults) {
+  const EShLanguage stage = EShLangFragment;
+  EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(-9), stage));
+  EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(-8), stage));
+  EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(7), stage));
+  EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(8), stage));
+}
+
+TEST_F(CompilerTest, TexelOffsetLowerTheMinimum) {
+  const EShLanguage stage = EShLangFragment;
+  compiler_.SetLimit(Compiler::Limit::MinProgramTexelOffset, -99);
+  EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(-100), stage));
+  EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(-99), stage));
+}
+
+TEST_F(CompilerTest, TexelOffsetRaiseTheMaximum) {
+  const EShLanguage stage = EShLangFragment;
+  compiler_.SetLimit(Compiler::Limit::MaxProgramTexelOffset, 100);
+  EXPECT_TRUE(SimpleCompilationSucceeds(ShaderWithTexOffset(100), stage));
+  EXPECT_FALSE(SimpleCompilationSucceeds(ShaderWithTexOffset(101), stage));
+}
+
 }  // anonymous namespace