[Mesa-dev] [PATCH] Bounding box avx2 intrinsic algorithm for openGL/GLES

Jason Ekstrand jason at jlekstrand.net
Fri Aug 31 16:25:03 UTC 2018


On Fri, Aug 31, 2018 at 1:09 AM <kedar.j.karanje at intel.com> wrote:

> From: "J Karanje, Kedar" <kedar.j.karanje at intel.com>
>
> The feature is enabled by default during make however we need to
> add the following to drirc to enable the feature at runtime.
> <option name="enable_bounding_box_culling" value="true"/>
>
> vbo: Main algorithm & code to check for MVP & vertex position location
> Build Files: Flags to enable BBOX Code and check AVX version
> compiler: Code to recognize simple shader
>           (gl_position is a simple function of mvp and vertex)
> i965 & util: dri query to check if feature is enabled
>
> vbo: Implements a bounding box algorithm for mesa,we hook into the default
>     drawelements and drawrangelements and the MVP & vertex positions
> location
>     and the corresponding program is got,we re-create the frustum planes
>     using this data and also create a box around the object and use the 8
>     vertices (box vertices) and check if the box is within the frustum or
> not,
>     we drop the draw calls that are completely outside the view frustum and
>     go for sub-boxes for objects that are intersecting with the frustum
> planes.
>
> The current patch has been verified on KBL+Ubuntu 16.04, we noticed
> 8~10% improvements in GFxBench TREX offscreen and ~2% for Manhattan
> offscreen,
> Platforms where avx2 is not supported shall still see ~6-8% improvement,
> the
> other KPIs were not impacted.
>
> Based on empirical data we have set minimum vertex count as 999 and the
> sub-box size as 198, this provides the best results, we have also
> implemented
> some level of caching for the box co-od and frustum plane co-od.
> we have also optimized some algorithms to use avx2 when a target supports
> it.
>
> Shader classification code is currently in hir and we have got review
> comments
> to move the same to NIR.
>
> Signed-off-by: Aravindan Muthukumar <aravindan.muthukumar at intel.com>
> Signed-off-by: Yogesh Marathe <yogesh.marathe at intel.com>
> ---
>  Android.common.mk                        |   19 +
>  configure.ac                             |   34 +-
>  src/compiler/glsl/ast_to_hir.cpp         |  168 +++-
>  src/compiler/glsl/glsl_parser_extras.cpp |   10 +
>  src/compiler/glsl/glsl_parser_extras.h   |    7 +
>  src/compiler/glsl/linker.cpp             |   18 +
>  src/intel/common/gen_debug.c             |    7 +
>  src/mesa/Makefile.sources                |   11 +
>  src/mesa/drivers/dri/i965/brw_context.c  |   17 +
>  src/mesa/drivers/dri/i965/intel_screen.c |    4 +
>  src/mesa/main/bufferobj.c                |   19 +
>  src/mesa/main/mtypes.h                   |   51 +
>  src/mesa/program/Android.mk              |    1 +
>  src/mesa/program/program.c               |    3 +
>  src/mesa/vbo/vbo_bbox.c                  | 1538
> ++++++++++++++++++++++++++++++
>  src/mesa/vbo/vbo_bbox.h                  |  383 ++++++++
>  src/mesa/vbo/vbo_bbox_cache.c            |  195 ++++
>  src/mesa/vbo/vbo_context.c               |   11 +-
>  src/mesa/vbo/vbo_exec_array.c            |   37 +-
>  src/util/00-mesa-defaults.conf           |    4 +
>  src/util/xmlpool/t_options.h             |    5 +
>  21 files changed, 2535 insertions(+), 7 deletions(-)
>  mode change 100644 => 100755 src/compiler/glsl/ast_to_hir.cpp
>  create mode 100644 src/mesa/vbo/vbo_bbox.c
>  create mode 100644 src/mesa/vbo/vbo_bbox.h
>  create mode 100644 src/mesa/vbo/vbo_bbox_cache.c
>
> diff --git a/Android.common.mk b/Android.common.mk
> index aa1b266..efd6792 100644
> --- a/Android.common.mk
> +++ b/Android.common.mk
> @@ -21,6 +21,8 @@
>  # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>  # DEALINGS IN THE SOFTWARE.
>
> +MESA_BBOX_ENABLE=true
> +
>  ifeq ($(LOCAL_IS_HOST_MODULE),true)
>  LOCAL_CFLAGS += -D_GNU_SOURCE
>  endif
> @@ -80,6 +82,10 @@ LOCAL_CFLAGS += \
>         -fno-trapping-math \
>         -Wno-sign-compare
>
> +ifeq ($(MESA_BBOX_ENABLE),true)
> +LOCAL_CFLAGS += -DMESA_BBOX_OPT
> +endif
> +
>  LOCAL_CPPFLAGS += \
>         -D__STDC_CONSTANT_MACROS \
>         -D__STDC_FORMAT_MACROS \
> @@ -87,6 +93,10 @@ LOCAL_CPPFLAGS += \
>         -Wno-error=non-virtual-dtor \
>         -Wno-non-virtual-dtor
>
> +ifeq ($(MESA_BBOX_ENABLE),true)
> +LOCAL_CPPFLAGS += -DMESA_BBOX_OPT
> +endif
> +
>  # mesa requires at least c99 compiler
>  LOCAL_CONLYFLAGS += \
>         -std=c99
> @@ -98,6 +108,15 @@ ifeq ($(filter 5 6 7 8 9,
> $(MESA_ANDROID_MAJOR_VERSION)),)
>  LOCAL_CFLAGS += -DHAVE_TIMESPEC_GET
>  endif
>
> +ifeq ($(MESA_BBOX_ENABLE),true)
> +#if defined(CONFIG_AS_AVX)
> +LOCAL_CONLYFLAGS += -mavx
> +#elif
> +LOCAL_CONLYFLAGS += -msse4.1
> +#endif
> +endif
> +
> +
>  ifeq ($(strip $(MESA_ENABLE_ASM)),true)
>  ifeq ($(TARGET_ARCH),x86)
>  LOCAL_CFLAGS += \
> diff --git a/configure.ac b/configure.ac
> index 4d9d9e5..dcdbcf3 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -278,7 +278,8 @@ _SAVE_LDFLAGS="$LDFLAGS"
>  _SAVE_CPPFLAGS="$CPPFLAGS"
>
>  dnl Compiler macros
> -DEFINES="-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
> -D__STDC_LIMIT_MACROS"
> +DEFINES="-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
> -D__STDC_LIMIT_MACROS -DMESA_BBOX_OPT"
> +dnl DEFINES="-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
> -D__STDC_LIMIT_MACROS"
>  AC_SUBST([DEFINES])
>  android=no
>  case "$host_os" in
> @@ -295,10 +296,38 @@ esac
>
>  AM_CONDITIONAL(HAVE_ANDROID, test "x$android" = xyes)
>
> +
> +dnl Conditional parameters for enabling BBOX file compilation in Makefile
> +dnl bbox=yes
> +dnl MESA_BBOX_ENABLE=true
> +dnl AM_CONDITIONAL([MESA_BBOX_ENABLE], [test x$bbox= xyes])
> +
>  dnl
>  dnl Check compiler flags
>  dnl
> -AX_CHECK_COMPILE_FLAG([-Wall],
>  [CFLAGS="$CFLAGS -Wall"])
> +
> +AC_ARG_WITH([swr-archs],
> +    [AS_HELP_STRING([--with-swr-archs@<:@=DIRS...@:>@],
> +        [comma delimited swr architectures list, e.g.
> +        "avx,avx2,sse4.1,sse4.2" @<:@default="sse4.1,sse4.2"@:>@])],
> +    [with_swr_archs="$withval"],
> +    [with_swr_archs="sse4.1,sse4.2"])
> +
> +swr_archs=`IFS=', '; echo $with_swr_archs`
> +if test "$swr_archs" = "avx"; then
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CFLAGS="$CFLAGS -Wall -msse4.1 -mavx"])
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CXXFLAGS="$CXXFLAGS -Wall -msse4.1 -mavx"])
> +elif test "$swr_archs" = "avx2"; then
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CFLAGS="$CFLAGS -Wall -msse4.1 -mavx -mavx2"])
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CXXFLAGS="$CXXFLAGS -Wall -msse4.1 -mavx -mavx2"])
> +elif test "$swr_archs" = "sse4.1"; then
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CFLAGS="$CFLAGS -Wall -msse4.1"])
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CXXFLAGS="$CXXFLAGS -Wall -msse4.1"])
> +elif test "$swr_archs" = "sse4.2"; then
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CFLAGS="$CFLAGS -Wall -msse4.1 -msse4.2"])
> +AX_CHECK_COMPILE_FLAG([-Wall],
>  [CXXFLAGS="$CXXFLAGS -Wall -msse4.1 -msse4.2"])
> +fi
> +
>  AX_CHECK_COMPILE_FLAG([-Werror=implicit-function-declaration],
> [CFLAGS="$CFLAGS -Werror=implicit-function-declaration"])
>  AX_CHECK_COMPILE_FLAG([-Werror=missing-prototypes],
> [CFLAGS="$CFLAGS -Werror=missing-prototypes"])
>  AX_CHECK_COMPILE_FLAG([-Wmissing-prototypes],
> [CFLAGS="$CFLAGS -Wmissing-prototypes"])
> @@ -313,7 +342,6 @@ dnl
>  dnl Check C++ compiler flags
>  dnl
>  AC_LANG_PUSH([C++])
> -AX_CHECK_COMPILE_FLAG([-Wall],
>  [CXXFLAGS="$CXXFLAGS -Wall"])
>  AX_CHECK_COMPILE_FLAG([-fno-math-errno],
>  [CXXFLAGS="$CXXFLAGS -fno-math-errno"])
>  AX_CHECK_COMPILE_FLAG([-fno-trapping-math],
> [CXXFLAGS="$CXXFLAGS -fno-trapping-math"])
>  AX_CHECK_COMPILE_FLAG([-fvisibility=hidden],
>  [VISIBILITY_CXXFLAGS="-fvisibility=hidden"])
> diff --git a/src/compiler/glsl/ast_to_hir.cpp
> b/src/compiler/glsl/ast_to_hir.cpp
> old mode 100644
> new mode 100755
> index 5d3f10b..f4e8dea
> --- a/src/compiler/glsl/ast_to_hir.cpp
> +++ b/src/compiler/glsl/ast_to_hir.cpp
> @@ -62,7 +62,6 @@
>  #include "builtin_functions.h"
>
>  using namespace ir_builder;
> -
>  static void
>  detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
>                                 exec_list *instructions);
> @@ -1325,6 +1324,124 @@ ast_expression::set_is_lhs(bool new_value)
>        this->subexpressions[0]->set_is_lhs(new_value);
>  }
>
> +#ifdef MESA_BBOX_OPT
> +static bool
> +is_simple_shader(exec_list *instructions, ast_expression *simple_ast_root,
> +                 struct _mesa_glsl_parse_state *state)
>

This is in desparate need of some comments.  I think what it's trying to do
is detect a "simple" shader that's just

uniform mat4 MVP
in vec4 v0;
void main()
{
   gl_Position = MVP * v0;
}

However, the mess of AST code doesn't make that obvious.

Also, as others have said, this should be done lower down in the stack in
GLSL IR (HIR) or, better yet, in NIR so that we can detect the same case
for ARB programs.

+{
> +   ast_expression * subex0 = simple_ast_root->subexpressions[0];
> +   ast_expression * subex1 = simple_ast_root->subexpressions[1];
> +
> +   char temp_identifier[100];
> +
> +   subex0->set_is_lhs(true);
> +
> +   if (subex1->oper == ast_mul)
> +   {
> +      ir_rvalue *rhsParts[3];
> +      rhsParts[0] = subex1->subexpressions[0]->hir(instructions, state);
> +      rhsParts[1] = subex1->subexpressions[1]->hir(instructions, state);
> +
> +      if (rhsParts[0]->type->gl_type == GL_FLOAT_MAT4 &&
> +          rhsParts[1]->type->gl_type == GL_FLOAT_VEC4) {
> +         foreach_list_typed (ast_node, ast, link,
> +                             &subex1->subexpressions[1]->expressions) {
> +            if (((ast_expression *)ast)->oper != ast_identifier &&
> +               (((ast_expression *)ast)->oper != ast_int_constant) &&
> +               (((ast_expression *)ast)->oper != ast_float_constant)) {
> +               return false;
> +            }
> +            if (((ast_expression *)ast)->oper == ast_identifier &&
> +                ((ast_expression *)ast)->primary_expression.identifier) {
> +                   strncpy((char *)state->stateVertPosition,
> +                   ((ast_expression *)ast)->primary_expression.identifier,
> +                strlen(((ast_expression
> *)ast)->primary_expression.identifier));
> +            }
> +         }
> +      }
> +      if (subex0->oper == ast_identifier) {
> +         if
> (!strcmp(subex0->primary_expression.identifier,"gl_Position")) {
> +            if(subex0 && subex0->primary_expression.identifier) {
> +               strncpy((char *)temp_identifier,
> +                    subex0->primary_expression.identifier,
> +                    strlen(subex0->primary_expression.identifier));
> +            } else {
> +              return false;
> +            }
> +            if(subex1 && subex1->subexpressions[0] &&
> +              subex1->subexpressions[0]->primary_expression.identifier) {
> +                strncpy((char *)state->stateMVP,
> +
>  subex1->subexpressions[0]->primary_expression.identifier,
> +
> strlen(subex1->subexpressions[0]->primary_expression.identifier));
> +            } else {
> +              return false;
> +            }
> +
> +            return true;
> +         } else {
> +            if(subex0 && subex0->primary_expression.identifier) {
> +               strncpy((char *)temp_identifier,
> +                  subex0->primary_expression.identifier,
> +                  strlen(subex0->primary_expression.identifier));
> +            } else {
> +              return true;
> +            }
> +
> +            if (subex1->subexpressions[0]->oper == ast_identifier) {
> +               if(subex1 && subex1->subexpressions[0] &&
> +
> subex1->subexpressions[0]->primary_expression.identifier) {
> +                     strncpy((char *)state->stateMVP,
> +
>  subex1->subexpressions[0]->primary_expression.identifier,
> +
> strlen(subex1->subexpressions[0]->primary_expression.identifier));
> +               } else {
> +                  return true;
> +               }
> +            }
> +            return false; //Return false to trigger further parsing.
> +         }
> +      } else {
> +        return false;
> +      }
> +   } else {
> +      if (subex0->primary_expression.identifier != NULL)
> +        if (!strcmp(subex0->primary_expression.identifier,"gl_Position")
> &&
> +          (strlen(temp_identifier) > 0)) { //gl_position = temp;
> +           if (subex1->oper == ast_identifier) {
> +              if (!strcmp((char *)temp_identifier,
> +                 subex1->primary_expression.identifier)) {
> +                   return true;
> +              }
> +           } else {
> +              return false;
> +           }
> +        }
> +   }
> +   return false;
> +}
> +/*
> + * Function to check if LHS of assign is an input variable Eg: in_position
> + */
> +
> +static bool
> +is_attribute(struct _mesa_glsl_parse_state *state)
> +{
> +   ir_variable *const var =
> state->symbols->get_variable(state->stateVertPosition);
> +   ir_rvalue *result = NULL;
> +   void *ctx = state;
> +   if (var != NULL)
> +   {
> +         result = new(ctx) ir_dereference_variable(var);
> +         (void)result;
> +         if (var->data.mode ==  ir_var_shader_in)
> +             return true;
> +
> +   }
> +
> +   return false;
> +
> +}
> +#endif //MESA_BBOX_OPT
> +
>  ir_rvalue *
>  ast_expression::do_hir(exec_list *instructions,
>                         struct _mesa_glsl_parse_state *state,
> @@ -1400,6 +1517,55 @@ ast_expression::do_hir(exec_list *instructions,
>        unreachable("ast_aggregate: Should never get here.");
>
>     case ast_assign: {
> +#ifdef MESA_BBOX_OPT
> +      if (state->stage == MESA_SHADER_VERTEX &&
> +          !state->state_bbox_simple_shader &&
> +          is_simple_shader(instructions,this,state) &&
> +          !state->state_shader_analysis_complete)
> +      {
> +         state->state_bbox_simple_shader = true;
> +      }
> +
> +      if (state->state_bbox_simple_shader &&
> +          !state->state_shader_analysis_complete) {
> +         if (!is_attribute(state)) {
> +            if ((ir_dereference_variable *)op[0] != NULL &&
> +                ((ir_dereference_variable *)op[0])->var->name != NULL &&
> +                strlen(state->stateVertPosition) != 0)
> +            if (!strcmp(((ir_dereference_variable *)op[0])->var->name,
> +                          state->stateVertPosition) ) {
> +               if (((ir_instruction *)op[0])->ir_type == ir_type_variable
> ||
> +                    ((ir_instruction *)op[0])->ir_type ==
> +                                      ir_type_dereference_variable &&
> +                    (ir_dereference_variable *)op[1] != NULL &&
> +                    ((ir_dereference_variable *)op[1])->ir_type ==
> +                     ir_type_dereference_variable) {
> +                  if ((((ir_instruction *)op[1])->ir_type ==
> ir_type_variable ||
> +                      ((ir_instruction *)op[1])->ir_type ==
> +                        ir_type_dereference_variable) &&
> +                       ((ir_dereference_variable *)op[1])->var->name) {
> +                     strncpy((char *)state->stateVertPosition,
> +                           (char *)((ir_dereference_variable
> *)op[1])->var->name,
> +                        strlen(((ir_dereference_variable
> *)op[1])->var->name));
> +                        state->state_shader_analysis_complete = true;
> +                  }
> +               }
> +               else {
> +                  state->state_bbox_simple_shader = false;
> +                  state->state_shader_analysis_complete = true;
> +               }
> +            }
> +            else {
> +               state->state_bbox_simple_shader = false;
> +               state->state_shader_analysis_complete = true;
> +
> +            }
> +         }
> +         else {
> +            state->state_shader_analysis_complete = true;
> +         }
> +      }
> +#endif //MESA_BBOX_OPT
>        this->subexpressions[0]->set_is_lhs(true);
>        op[0] = this->subexpressions[0]->hir(instructions, state);
>        op[1] = this->subexpressions[1]->hir(instructions, state);
> diff --git a/src/compiler/glsl/glsl_parser_extras.cpp
> b/src/compiler/glsl/glsl_parser_extras.cpp
> index 42ba88f..c540b3a 100644
> --- a/src/compiler/glsl/glsl_parser_extras.cpp
> +++ b/src/compiler/glsl/glsl_parser_extras.cpp
> @@ -2121,6 +2121,16 @@ _mesa_glsl_compile_shader(struct gl_context *ctx,
> struct gl_shader *shader,
>     if (!state->error && !state->translation_unit.is_empty())
>        _mesa_ast_to_hir(shader->ir, state);
>
> +#ifdef MESA_BBOX_OPT
> +   shader->shader_bbox_simple_shader = state->state_bbox_simple_shader;
> +   if (shader->shader_bbox_simple_shader)
> +   {
> +        strncpy((char *)shader->shaderMVP,state->stateMVP,
> +                        strlen(state->stateMVP));
> +        strncpy((char
> *)shader->shaderVertPosition,state->stateVertPosition,
> +                        strlen(state->stateVertPosition));
> +   }
> +#endif //MESA_BBOX_OPT
>     if (!state->error) {
>        validate_ir_tree(shader->ir);
>
> diff --git a/src/compiler/glsl/glsl_parser_extras.h
> b/src/compiler/glsl/glsl_parser_extras.h
> index da44d37..b951a66 100644
> --- a/src/compiler/glsl/glsl_parser_extras.h
> +++ b/src/compiler/glsl/glsl_parser_extras.h
> @@ -887,6 +887,13 @@ struct _mesa_glsl_parse_state {
>      * so we can check totals aren't too large.
>      */
>     unsigned clip_dist_size, cull_dist_size;
> +
> +#ifdef MESA_BBOX_OPT
> +   bool state_shader_analysis_complete;
> +   bool state_bbox_simple_shader;
> +   char stateMVP[20] = {'\0'};
> +   char stateVertPosition[100] = {'\0'};
> +#endif
>  };
>
>  # define YYLLOC_DEFAULT(Current, Rhs, N)                        \
> diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp
> index 3ce78fe..210f37f 100644
> --- a/src/compiler/glsl/linker.cpp
> +++ b/src/compiler/glsl/linker.cpp
> @@ -4876,6 +4876,24 @@ link_shaders(struct gl_context *ctx, struct
> gl_shader_program *prog)
>
>           switch (stage) {
>           case MESA_SHADER_VERTEX:
> +#ifdef MESA_BBOX_OPT
> +            if (shader_list[MESA_SHADER_VERTEX][0] != NULL) {
> +               sh->linked_bbox_simple_shader =
> +
> shader_list[MESA_SHADER_VERTEX][0]->shader_bbox_simple_shader;
> +                 /*TBD: How do we handle multiple Vertex Shaders
> +                  *     being linked ??
> +                  *     MVP Name copied to get MVP in VBO
> +                  */
> +                 strncpy((char *)sh->linkedshaderMVP,
> +                     shader_list[MESA_SHADER_VERTEX][0]->shaderMVP,
> +
>  strlen(shader_list[MESA_SHADER_VERTEX][0]->shaderMVP));
> +                 /* Vertex Position attribute name */
> +                 strncpy((char *)sh->linkedshaderVertPosition,
> +
>  shader_list[MESA_SHADER_VERTEX][0]->shaderVertPosition,
> +                     strlen(
> +
>  shader_list[MESA_SHADER_VERTEX][0]->shaderVertPosition));
> +              }
> +#endif
>              validate_vertex_shader_executable(prog, sh, ctx);
>              break;
>           case MESA_SHADER_TESS_CTRL:
> diff --git a/src/intel/common/gen_debug.c b/src/intel/common/gen_debug.c
> index a978f2f..c677208 100644
> --- a/src/intel/common/gen_debug.c
> +++ b/src/intel/common/gen_debug.c
> @@ -106,6 +106,13 @@ intel_debug_flag_for_shader_stage(gl_shader_stage
> stage)
>  static void
>  brw_process_intel_debug_variable_once(void)
>  {
> +#if defined(__ANDROID__) || defined(ANDROID)
> +   setenv("MESA_GLSL_CACHE_DISABLE","true",1);
> +   setenv("MESA_BBOX_MIN_VERTEX_CNT", "999", 1);
> +   setenv("MESA_BBOX_OPT_ENABLE", "3", 1);
> +   setenv("MESA_OPT_SPLIT_SIZE", "198", 1);
> +#endif
> +
>     INTEL_DEBUG = parse_debug_string(getenv("INTEL_DEBUG"), debug_control);
>  }
>
> diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources
> index 0d3c277..8148622 100644
> --- a/src/mesa/Makefile.sources
> +++ b/src/mesa/Makefile.sources
> @@ -1,4 +1,5 @@
>  ### Lists of source files, included by Makefiles
> +MESA_BBOX_ENABLE = false
>
>  # this is part of MAIN_FILES
>  MAIN_ES_FILES = \
> @@ -400,6 +401,7 @@ TNL_FILES = \
>         tnl/t_vp_build.c \
>         tnl/t_vp_build.h
>
> +
>  VBO_FILES = \
>         vbo/vbo_attrib.h \
>         vbo/vbo_attrib_tmp.h \
> @@ -422,6 +424,15 @@ VBO_FILES = \
>         vbo/vbo_save.h \
>         vbo/vbo_save_loopback.c
>
> +#ifeq($(MESA_BBOX_ENABLE), true)
> +
> +VBO_FILES += \
> +       vbo/vbo_bbox_cache.c \
> +       vbo/vbo_bbox.c \
> +       vbo/vbo_bbox.h
> +
> +#endif
> +
>  STATETRACKER_FILES = \
>         state_tracker/st_atifs_to_tgsi.c \
>         state_tracker/st_atifs_to_tgsi.h \
> diff --git a/src/mesa/drivers/dri/i965/brw_context.c
> b/src/mesa/drivers/dri/i965/brw_context.c
> index 6ba64e4..03cf861 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.c
> +++ b/src/mesa/drivers/dri/i965/brw_context.c
> @@ -48,6 +48,10 @@
>
>  #include "vbo/vbo.h"
>
> +#ifdef MESA_BBOX_OPT
> +#include "vbo/vbo_bbox.h"
> +#endif
> +
>  #include "drivers/common/driverfuncs.h"
>  #include "drivers/common/meta.h"
>  #include "utils.h"
> @@ -890,6 +894,11 @@ brw_process_driconf_options(struct brw_context *brw)
>     ctx->Const.AllowGLSLCrossStageInterpolationMismatch =
>        driQueryOptionb(options,
> "allow_glsl_cross_stage_interpolation_mismatch");
>
> +#ifdef MESA_BBOX_OPT
> +   ctx->Const.EnableBoundingBoxCulling =
> +      driQueryOptionb(options, "enable_bounding_box_culling");
> +#endif //MESA_BBOX_OPT
> +
>     ctx->Const.dri_config_options_sha1 = ralloc_array(brw, unsigned char,
> 20);
>     driComputeOptionsSha1(&brw->screen->optionCache,
>                           ctx->Const.dri_config_options_sha1);
> @@ -1001,6 +1010,14 @@ brwCreateContext(gl_api api,
>
>     brw_process_driconf_options(brw);
>
> +#ifdef MESA_BBOX_OPT
> +   if (ctx->Const.EnableBoundingBoxCulling) {
> +        MESA_BBOX("EnableBoundingBoxCulling True\n");
> +        vbo_bbox_init(ctx);
> +   } else
> +        MESA_BBOX("EnableBoundingBoxCulling False\n");
> +#endif //MESA_BBOX_OPT
> +
>     if (INTEL_DEBUG & DEBUG_PERF)
>        brw->perf_debug = true;
>
> diff --git a/src/mesa/drivers/dri/i965/intel_screen.c
> b/src/mesa/drivers/dri/i965/intel_screen.c
> index eaf5a3b..35c7624 100644
> --- a/src/mesa/drivers/dri/i965/intel_screen.c
> +++ b/src/mesa/drivers/dri/i965/intel_screen.c
> @@ -88,6 +88,10 @@ DRI_CONF_BEGIN
>        DRI_CONF_ALLOW_HIGHER_COMPAT_VERSION("false")
>        DRI_CONF_FORCE_GLSL_ABS_SQRT("false")
>
> +#ifdef MESA_BBOX_OPT
> +      DRI_CONF_ENABLE_BOUNDING_BOX_CULLING("true")
> +#endif
> +
>        DRI_CONF_OPT_BEGIN_B(shader_precompile, "true")
>          DRI_CONF_DESC(en, "Perform code generation at shader link time.")
>        DRI_CONF_OPT_END
> diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
> index 1d1e51b..67a369b 100644
> --- a/src/mesa/main/bufferobj.c
> +++ b/src/mesa/main/bufferobj.c
> @@ -48,6 +48,9 @@
>  #include "varray.h"
>  #include "util/u_atomic.h"
>
> +#ifdef MESA_BBOX_OPT
> +#include "vbo/vbo_bbox.h"
> +#endif
>
>  /* Debug flags */
>  /*#define VBO_DEBUG*/
> @@ -2254,6 +2257,10 @@ buffer_sub_data(GLenum target, GLuint buffer,
> GLintptr offset,
>
>     if (no_error || validate_buffer_sub_data(ctx, bufObj, offset, size,
> func))
>        _mesa_buffer_sub_data(ctx, bufObj, offset, size, data);
> +
> +#ifdef MESA_BBOX_OPT
> +   vbo_bbox_element_buffer_update(ctx,bufObj,data,offset,size);
> +#endif
>  }
>
>
> @@ -2589,9 +2596,17 @@ validate_and_unmap_buffer(struct gl_context *ctx,
>  #endif
>
>  #ifdef VBO_DEBUG
> +#ifdef MESA_BBOX_OPT
> +   if (bufObj->StorageFlags & GL_MAP_WRITE_BIT) {
> +#else
>     if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
> +#endif
>        GLuint i, unchanged = 0;
> +#ifdef MESA_BBOX_OPT
> +      GLubyte *b = (GLubyte *) bufObj->Data;
> +#else
>        GLubyte *b = (GLubyte *) bufObj->Pointer;
> +#endif
>        GLint pos = -1;
>        /* check which bytes changed */
>        for (i = 0; i < bufObj->Size - 1; i++) {
> @@ -3154,7 +3169,11 @@ map_buffer_range(struct gl_context *ctx, struct
> gl_buffer_object *bufObj,
>        /* Access must be write only */
>        if ((access & GL_MAP_WRITE_BIT) && (!(access & ~GL_MAP_WRITE_BIT)))
> {
>           GLuint i;
> +#ifdef MESA_BBOX_OPT
> +         GLubyte *b = (GLubyte *) bufObj->Data;
> +#else
>           GLubyte *b = (GLubyte *) bufObj->Pointer;
> +#endif
>           for (i = 0; i < bufObj->Size; i++)
>              b[i] = i & 0xff;
>        }
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index 9fd577d..c262173 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -1359,6 +1359,9 @@ struct gl_buffer_object
>     bool MinMaxCacheDirty;
>
>     bool HandleAllocated; /**< GL_ARB_bindless_texture */
> +#ifdef MESA_BBOX_OPT
> +   int data_change_counter; //TBD: Same as RefCount to check
> +#endif
>  };
>
>
> @@ -2535,6 +2538,12 @@ struct gl_linked_shader
>      * stores information that is also needed during linking.
>      */
>     struct gl_shader_spirv_data *spirv_data;
> +
> +#ifdef MESA_BBOX_OPT
> +   bool linked_bbox_simple_shader;
> +   char linkedshaderMVP[20];
> +   char linkedshaderVertPosition[100];
> +#endif
>  };
>
>
> @@ -2631,6 +2640,11 @@ struct gl_shader
>
>     /* ARB_gl_spirv related data */
>     struct gl_shader_spirv_data *spirv_data;
> +#ifdef MESA_BBOX_OPT
> +   bool shader_bbox_simple_shader;
> +   char shaderMVP[20];
> +   char shaderVertPosition[100];
> +#endif
>  };
>
>
> @@ -2902,6 +2916,9 @@ struct gl_shader_program_data
>      * ARB_gl_spirv extension.
>      */
>     bool spirv;
> +#ifdef MESA_BBOX_OPT
> +   GLuint vbo_bbox_mvp_location;
> +#endif
>  };
>
>  /**
> @@ -3108,6 +3125,10 @@ struct gl_pipeline_shader_state
>
>     /** Pipeline objects */
>     struct _mesa_HashTable *Objects;
> +#ifdef MESA_BBOX_OPT
> +   /* Bounding box draw optimization control structure */
> +   struct mesa_bbox_opt *BboxOpt;
> +#endif
>  };
>
>  /**
> @@ -4076,6 +4097,12 @@ struct gl_constants
>
>     /** GL_ARB_gl_spirv */
>     struct spirv_supported_capabilities SpirVCapabilities;
> +
> +#ifdef MESA_BBOX_OPT
> +   /** MESA_BBOX_OPT Runtime enable_bounding_box_culling*/
> +   bool EnableBoundingBoxCulling;
> +#endif
> +
>  };
>
>
> @@ -4720,6 +4747,21 @@ struct gl_semaphore_object
>     GLuint Name;            /**< hash table ID/name */
>  };
>
> +#ifdef MESA_BBOX_OPT
> +/**
> + * Bounding volume classification types
> + */
> +typedef enum
> +{
> +    BOUNDING_VOLUME_AABB = 0,
> +    BOUNDING_VOLUME_OBB = 1,
> +    BOUNDING_VOLUME_SPHERE = 2,
> +    BOUNDING_VOLUME_DOP = 3,
> +    BOUNDING_VOULME_MIXED = 4,
> +    BOUNDING_VOLUME_MAX = 5,
> +} bounding_volume_type;
> +#endif //MESA_BBOX_OPT
> +
>  /**
>   * Mesa rendering context.
>   *
> @@ -5096,6 +5138,15 @@ struct gl_context
>     struct hash_table_u64 *ResidentTextureHandles;
>     struct hash_table_u64 *ResidentImageHandles;
>     /*@}*/
> +
> +#ifdef MESA_BBOX_OPT
> +   /**
> +    * Bounding volume type
> +    *
> +    */
> +    bounding_volume_type volume_type;
> +#endif //MESA_BBOX_OPT
> +
>  };
>
>  /**
> diff --git a/src/mesa/program/Android.mk b/src/mesa/program/Android.mk
> index c6470e6..6489d3e 100644
> --- a/src/mesa/program/Android.mk
> +++ b/src/mesa/program/Android.mk
> @@ -75,6 +75,7 @@ $(intermediates)/program/lex.yy.c:
> $(LOCAL_PATH)/program_lexer.l
>  LOCAL_C_INCLUDES := \
>         $(MESA_TOP)/src/mapi \
>         $(MESA_TOP)/src/mesa \
> +       $(MESA_TOP)/src/mesa/vbo \
>         $(MESA_TOP)/src/compiler/nir \
>         $(MESA_TOP)/src/gallium/auxiliary \
>         $(MESA_TOP)/src/gallium/include
> diff --git a/src/mesa/program/program.c b/src/mesa/program/program.c
> index 6ab1bf5..e0b3563 100644
> --- a/src/mesa/program/program.c
> +++ b/src/mesa/program/program.c
> @@ -43,6 +43,9 @@
>  #include "util/ralloc.h"
>  #include "util/u_atomic.h"
>
> +#ifdef MESA_BBOX_OPT
> +#include "vbo/vbo_bbox.h"
> +#endif
>
>  /**
>   * A pointer to this dummy program is put into the hash table when
> diff --git a/src/mesa/vbo/vbo_bbox.c b/src/mesa/vbo/vbo_bbox.c
> new file mode 100644
> index 0000000..f1e153d
> --- /dev/null
> +++ b/src/mesa/vbo/vbo_bbox.c
> @@ -0,0 +1,1538 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without
> limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> next
> + * paragraph) shall be included in all copies or substantial portions of
> the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
> OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +/**
> + * \brief  VBO BBOX module implementation
> + * \author Kedar Karanje
> + */
> +
> +#pragma GCC optimize (0)
> +#include "vbo_bbox.h"
> +#include <fcntl.h>
> +#define  BBOX_MAX_FRAMES_TO_DYNAMICALLY_UPDATE (5)
> +#define  BBOX_MIN_EFFECTIVE_DRAWS_TO_DYNAMICALLY_UPDATE (5)
> +#define  BBOX_MIN_VAL_FOR_EFFECTIVE_DRAWS_COUNTER (-100)
> +#define  BBOX_MAX_VAL_FOR_EFFECTIVE_DRAWS_COUNTER (100)
> +#define  BBOX_MIN_GPU_HEAD_ROOM_TO_PROCESS_ELEMENT_BUFFER (100)
> +
> +/**
> +  *  Min part of split draw that we want to drop
> +  */
> +#define  BBOX_MIN_SPLITTED_DRAW_TO_DROP (1)
> +
> +#ifdef __AVX__
> +static __m256 fullMin;
> +static __m256 fullMax;
> +#else
> +static __m128 fullMin;
> +static __m128 fullMax;
> +#endif
> +
> +/* Segment functions */
> +
> +static inline GLboolean
> +intersect(const struct gl_segment *s_src,const struct gl_segment *s_tar)
> +{
> +   return (s_src->Left < s_tar->Right && s_src->Right > s_tar->Left);
> +}
> +
> +
> +static inline GLboolean
> +subsegment(const struct gl_segment *s_src,const struct gl_segment *s_tar)
> +{
> +  return (s_src->Left <= s_tar->Left && s_src->Right >= s_tar->Right);
> +}
> +
> +
> +static inline GLboolean
> +superset(const struct gl_segment *s_src,const struct gl_segment *s_tar)
> +{
> +  return subsegment(s_tar,s_src);
> +}
> +
> +
> +static void
> +normalize(vbo_bbox_frustum_plane *fr_plane)
> +{
> +        GLfloat a,b,c;
> +        a = fr_plane->a;
> +        b = fr_plane->b;
> +        c = fr_plane->c;
> +
> +        GLfloat norm = 1.0f/sqrt(a*a + b*b + c*c);
> +
> +        fr_plane->a *= norm;
> +        fr_plane->b *= norm;
> +        fr_plane->c *= norm;
> +        fr_plane->d *= norm;
> +};
> +
> +static inline
> +int vbo_bbox_get_delay(struct mesa_bbox_opt *opt)
> +{
> +   if (mesa_bbox_env_variables.bbox_enable <
> MESA_BBOX_ENABLE_FORCE_RECALC) {
> +      if (opt->calc_delay > BBOX_CALC_MAX_DELAY) {
> +         opt->calc_delay = BBOX_CALC_MIN_DELAY;
> +      }
> +      return opt->calc_delay++;
> +   }
> +   else {
> +      return 0;
> +   }
> +}
> +
> +static inline
> +bool vbo_init_sub_bbox_array(int bbox_count, struct vbo_bbox_cache_data*
> data)
> +{
> +   bool allocate_bbox = true;
> +   if(data->sub_bbox_array != NULL) {
> +      if(bbox_count == data->sub_bbox_cnt) {
> +         allocate_bbox = false;
> +      }
> +      else {
> +         free(data->sub_bbox_array);
> +         data->sub_bbox_array = NULL;
> +      }
> +   }
> +   if (allocate_bbox)
> +      data->sub_bbox_array = (struct bounding_info*) malloc(
> +                                    bbox_count * sizeof (struct
> bounding_info));
> +
> +   if (!data->sub_bbox_array)
> +   return false;
> +
> +   data->sub_bbox_cnt = bbox_count;
> +   return true;
> +}
> +
> +static inline GLint
> +vbo_bbox_get_mvp(struct gl_context *ctx)
> +{
> +   struct gl_linked_shader * linked_shader =
> +
> ctx->Shader.ActiveProgram->_LinkedShaders[MESA_SHADER_VERTEX];
> +
> +   return _mesa_GetUniformLocation(ctx->Shader.ActiveProgram->Name,
> +                                   linked_shader->linkedshaderMVP);
> +}
> +
> +/*
> + * Gets the currently linked shaders flag for simple shader
> + *
> + */
> +static inline int
> +vbo_is_simple_shader(struct gl_context *ctx)
> +{
> +   struct gl_linked_shader * linked_shader =
> +
> ctx->Shader.ActiveProgram->_LinkedShaders[MESA_SHADER_VERTEX];
> +
> +   return linked_shader->linked_bbox_simple_shader;
> +}
> +
> +/**
> + * Get current VAO
> + */
> +static inline struct gl_vertex_array_object*
> +vbo_get_current_vao(struct gl_context *const gc)
> +{
> +   assert(gc);
> +   struct gl_vertex_array_object* vao = gc->Array.VAO;
> +   assert(vao);
> +
> +   return vao;
> +}
> +
> +/**
> + *  Returns the location of the "position" in the attributes of the
> + *  currently active program
> + */
> +static inline
> +int vbo_get_simple_vs_position_attr_location(
> +    struct gl_context *const gc)
> +{
> +   assert(gc);
> +   struct gl_linked_shader * linked_shader =
> +
>  gc->Shader.ActiveProgram->_LinkedShaders[MESA_SHADER_VERTEX];
> +   GLint vertexPosLocation = _mesa_GetAttribLocation(
> +                           gc->Shader.ActiveProgram->Name,
> +                           linked_shader->linkedshaderVertPosition);
> +   if (vertexPosLocation >= 0)
> +      return vertexPosLocation;
> +   else
> +      return -1;
> +}
> +
> +/**
> + *   Get element-buffer handle of the current VAO
> + */
> +static inline struct gl_buffer_object*
> +vbo_get_current_element_buffer(struct gl_context *const gc)
> +{
> +   assert(gc);
> +   struct gl_buffer_object* element_buffer =
> +
> vbo_get_current_vao(gc)->IndexBufferObj;
> +   assert(element_buffer);
> +   return element_buffer;
> +}
> +
> +/**
> + *   Get vertex-binding of position from the current VAO
> + */
> +static inline struct gl_vertex_buffer_binding*
> +vbo_get_current_vertex_buffer_binding_of_position(struct gl_context
> *const gc)
> +{
> +   assert(gc);
> +   struct gl_vertex_array_object* vao = vbo_get_current_vao(gc);
> +
> +   GLbitfield mask = vao->_Enabled & vao->VertexAttribBufferMask;
> +   const struct gl_array_attributes *attrib_array =
> +                                           &vao->VertexAttrib[ffs(mask) -
> 1];
> +   struct gl_vertex_buffer_binding *buffer_binding =
> +
>  &vao->BufferBinding[attrib_array->BufferBindingIndex];
> +
> +   return buffer_binding;
> +}
> +
> +/**
> + * Get vertex-buffer handle of the current VAO
> + */
> +static inline struct gl_buffer_object*
> +vbo_get_current_vertex_buffer(struct gl_context *const gc)
> +{
> +   assert(gc);
> +   struct gl_buffer_object* pVertexBuffer =
> +
>  vbo_get_current_vertex_buffer_binding_of_position(gc)->BufferObj;
> +   assert(pVertexBuffer);
> +   return pVertexBuffer;
> +}
> +
> +
> +/**
> + * Condition to enter bounding box optimization
> + */
> +static inline bool
> +vbo_bbox_check_supported_draw_call(struct gl_context *const gc,
> +                                   GLenum mode, GLsizei count, GLenum
> type,
> +                                   const GLvoid *indices, GLint
> basevertex)
> +{
> +
> +   assert(gc);
> +   int shader_scenario;
> +   struct gl_linked_shader *_LinkedShaders;
> +
> +   /* Check if the minimum vertex count is met. */
> +   if (count < (GLsizei) mesa_bbox_env_variables.bbox_min_vrtx_count) {
> +     /* Count is most common cause to bail out form optimization
> +      * so should be first.
> +      */
> +     MESA_BBOX("Aborting MESA_BBOX :%d: Vertex count too small, minimum
> count = %d\n",
> +                     count,mesa_bbox_env_variables.bbox_min_vrtx_count);
> +     return false;
> +   }
> +
> +   if (mode != GL_TRIANGLES) {
> +      MESA_BBOX("Aborting MESA_BBOX :%d: Primitive mode is not
> GL_TRIANGLES, \
> +                      mode = %d\n", count, mode);
> +      return false;
> +   }
> +
> +   /* Examine current shader */
> +   if (!gc->_Shader->ActiveProgram) {
> +      MESA_BBOX("Aborting MESA_BBOX:%d: No active GLSL program.\n",
> count);
> +      return false;
> +   }
> +
> +   /* BASIC Shader scenario is when we have just VS & FS */
> +   if (gc->_Shader->CurrentProgram[MESA_SHADER_VERTEX] != NULL &&
> +       gc->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT] != NULL &&
> +       gc->_Shader->CurrentProgram[MESA_SHADER_TESS_CTRL] == NULL &&
> +       gc->_Shader->CurrentProgram[MESA_SHADER_TESS_EVAL] == NULL &&
> +       gc->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY] == NULL) {
> +      shader_scenario = 0;
> +   }
> +   else
> +     shader_scenario = 1;
> +
> +   if (shader_scenario) {
> +     MESA_BBOX("Aborting MESA_BBOX:%d: GLSL program must contain only
> vertex and \
> +                     fragment shaders, shader scenario = \n", count );
> +     return false;
> +   }
> +
> +   if (!vbo_is_simple_shader(gc)) {
> +      MESA_BBOX("Aborting MESA_BBOX:%d: GLSL vertex shader does not have
> simple \
> +                 position calculation \n", count);
> +      return false;
> +   }
> +   if (gc->Shader.ActiveProgram->_LinkedShaders[MESA_SHADER_VERTEX]) {
> +       _LinkedShaders =
> +
>  gc->Shader.ActiveProgram->_LinkedShaders[MESA_SHADER_VERTEX];
> +
> +       MESA_BBOX("MVP:%s, VertPos:%s\n",_LinkedShaders->linkedshaderMVP,
> +                   _LinkedShaders->linkedshaderVertPosition);
> +   }
> +
> +   /* Examine element buffer */
> +   struct gl_buffer_object* element_buffer =
> vbo_get_current_element_buffer(gc);
> +   if ((!element_buffer) || element_buffer->Name == 0) {
> +      MESA_BBOX("Aborting MESA_BBOX:%d: Element buffer name is 0\n",
> count);
> +      return false;
> +   }
> +
> +   if (!(element_buffer->StorageFlags &
> +      (GL_CLIENT_STORAGE_BIT | GL_DYNAMIC_STORAGE_BIT))){
> +       MESA_BBOX("Aborting MESA_BBOX:%d: Element buffer not resident:
> %#x\n", count,
> +                     element_buffer->StorageFlags);
> +       return false;
> +   }
> +
> +   /* Get VertexPosLocation */
> +   int vertexPosLocation = 0;
> +   if (gc->Shader.ActiveProgram)
> +      vertexPosLocation = vbo_get_simple_vs_position_attr_location(gc);
> +   if (vertexPosLocation < 0)
> +   {
> +      MESA_BBOX("Aborting MESA_BBOX:%d: VertexPosition Location is
> inValid:\n", count);
> +      return false;
> +   }
> +
> +   struct gl_vertex_array_object*  vao = vbo_get_current_vao(gc);
> +   int posAttribMapMode =
> +
> _mesa_vao_attribute_map[vao->_AttributeMapMode][vertexPosLocation];
> +
> +   if (((vao->_Enabled >> posAttribMapMode) & 0x1) != 1)
> +   {
> +      MESA_BBOX("Aborting MESA_BBOX:%d: Vertex data does not come from
> VBO , GL-API:%d\n", count,gc->API);
> +//#if !defined(__ANDROID__) || !defined(ANDROID)
> +//This is not specific to Android but to the GLES API
> +      if (gc->API != API_OPENGLES && gc->API != API_OPENGLES2)
> +          return false;
> +//#endif
> +   }
> +
> +   struct gl_buffer_object* vertexattrib_buffer  =
> +                            vbo_get_current_vertex_buffer(gc);
> +   if ((!vertexattrib_buffer) || vertexattrib_buffer->Name == 0) {
> +     MESA_BBOX("Aborting MESA_BBOX:%d: Vertex buffer %p name is %d\n",
> count,
> +                     vertexattrib_buffer,vertexattrib_buffer->Name);
> +#if !defined(__ANDROID__) || !defined(ANDROID)
> +     return false;
> +#endif
> +   }
> +
> +   if (!(vertexattrib_buffer->StorageFlags &
> +        (GL_CLIENT_STORAGE_BIT | GL_DYNAMIC_STORAGE_BIT))){
> +       MESA_BBOX("Aborting MESA_BBOX:%d:Vertex buffer not resident %#x
> \n", count,
> +                     vertexattrib_buffer->StorageFlags);
> +       MESA_BBOX("Aborting MESA_BBOX:VAO AttributeMode is %d\n",
> vao->_AttributeMapMode);
> +#if !defined(__ANDROID__) || !defined(ANDROID)
> +       return false;
> +#endif
> +   }
> +
> +    /* Examine vertex position attribute configuration */
> +   if (vao->VertexAttrib[posAttribMapMode].Enabled) {
> +      if (vao->VertexAttrib[posAttribMapMode].Size != 3)
> +      {
> +          MESA_BBOX("Aborting MESA_BBOX:%d: Vertex attrib size :%d, only
> 3 supported\n",
> +                         count, vao->VertexAttrib[VERT_ATTRIB_POS].Size);
> +#if !defined(__ANDROID__) || !defined(ANDROID)
> +          return false;
> +#endif
> +      }
> +      if (vao->VertexAttrib[posAttribMapMode].Type != GL_FLOAT)
> +      {
> +         MESA_BBOX("Aborting MESA_BBOX:%d: Vertex attrib type is %d, only
> GL_FLOAT \
> +                 supported\n", count,
> vao->VertexAttrib[VERT_ATTRIB_POS].Type);
> +         return false;
> +      }
> +   }
> +
> +   if (type != GL_UNSIGNED_SHORT) {
> +      MESA_BBOX("Aborting MESA_BBOX:%d: type is %d, only
> GL_UNSIGNED_SHORT \
> +                 supported\n", count, type);
> +      return false;
> +   }
> +   if (basevertex != 0) {
> +      MESA_BBOX("Aborting MESA_BBOX:%d: basevertex is 0 \n", count);
> +      return false;
> +   }
> +
> +   /* If size ==3 and type == GL_FLOAT, then element stride must be 12. */
> +   assert(vao->VertexAttrib[VERT_ATTRIB_POS].StrideB == 12);
> +
> +   /* When transform feedback is capturing we cannot do early clipping
> since
> +   * xfb must write unclipped vertices
> +   * Note - we could check for IsCapturing() but that would require
> +   * more elaborate checking for VBO modifications.
> +   */
> +   if (gc->TransformFeedback.CurrentObject->Active) {
> +      MESA_BBOX("MESA_BBOX:%d: Transform feedback is active, \
> +                      cannot clip\n", count);
> +      return false;
> +   }
> +   return true;
> +}
> +
> +
> +/**
> + *  Check condition to enter bounding box optimization and if draw call
> + *  is suitable prepare key describing given geometry.
> + */
> +static inline
> +void vbo_bbox_prepare_key(struct gl_context *const gc, GLenum mode,
> +                          GLsizei count, GLenum type, GLuint type_size,
> +                          const GLvoid *indices, GLint basevertex,
> +                          vbo_bbox_cache_key *key)
> +{
> +   assert(gc);
> +
> +   /* Examine element buffer */
> +   struct gl_buffer_object* element_buffer =
> vbo_get_current_element_buffer(gc);
> +   struct gl_buffer_object* vertexattrib_buffer  =
> +
>  vbo_get_current_vertex_buffer(gc);
> +   struct gl_vertex_buffer_binding* vbinding =
> +
>  vbo_get_current_vertex_buffer_binding_of_position(gc);
> +
> +   memset(key,0,sizeof(vbo_bbox_cache_key));
> +
> +   key->mode = mode;
> +   key->count = count;
> +   key->indices_type = type;
> +   key->type_size = type_size;
> +   key->indices = (GLint) (uintptr_t) indices;
> +   key->basevertex = basevertex;
> +
> +   key->element_buf_name = element_buffer->Name;
> +   key->vertex_buf_name = vertexattrib_buffer->Name;
> +
> +   key->offset = (GLint)vbinding->Offset;
> +   key->stride = vbinding->Stride;
> +}
> +
> +
> +/**
> + *  Create a bounding box descriptor in a form of 8 correctly
> + *  ordered vertex coordinates. The order of coordinates is significant.
> + */
> +static
> +void vbo_bbox_create_bounding_box(float* const minVec3f, float* const
> maxVec3F,
> +                                  vbo_vec4f* vertices4)
> +{
> +   assert(minVec3f);
> +   assert(maxVec3F);
> +   assert(vertices4);
> +
> +   float Xmin = minVec3f[0];
> +   float Ymin = minVec3f[1];
> +   float Zmin = minVec3f[2];
> +   float Wmin = 1.0f;
> +
> +   float Xmax = maxVec3F[0];
> +   float Ymax = maxVec3F[1];
> +   float Zmax = maxVec3F[2];
> +   float Wmax = 1.0f;
> +
> +   float* v = (float*)vertices4;
> +   int i = 0;
> +   v[i+0] = Xmin; v[i+1] = Ymin; v[i+2] = Zmin;v[i+3]=Wmin; i+=4;
> +   v[i+0] = Xmax; v[i+1] = Ymin; v[i+2] = Zmin;v[i+3]=Wmin; i+=4;
> +   v[i+0] = Xmin; v[i+1] = Ymax; v[i+2] = Zmin;v[i+3]=Wmin; i+=4;
> +   v[i+0] = Xmax; v[i+1] = Ymax; v[i+2] = Zmin;v[i+3]=Wmin; i+=4;
> +
> +   v[i+0] = Xmin; v[i+1] = Ymin; v[i+2] = Zmax;v[i+3]=Wmax; i+=4;
> +   v[i+0] = Xmax; v[i+1] = Ymin; v[i+2] = Zmax;v[i+3]=Wmax; i+=4;
> +   v[i+0] = Xmin; v[i+1] = Ymax; v[i+2] = Zmax;v[i+3]=Wmax; i+=4;
> +   v[i+0] = Xmax; v[i+1] = Ymax; v[i+2] = Zmax;v[i+3]=Wmax; i+=4;
> +}
> +
> +#ifdef __AVX__
> +/* Calculate bbox Subbox Coordinates */
> +static void
> +vbo_bbox_calc_subbox_coordinates(unsigned int vertSubBox,unsigned int
> vertCount,
> +                                 unsigned int first_idx,unsigned int
> second_idx,
> +                                 unsigned short* indices,float* vertices,
> +                                 unsigned int stride,
> +                                 struct vbo_bbox_cache_data *data)
> +{
> +
> +   /* Retrieving the starting offset of the first and second subbox */
> +   unsigned int first = first_idx * vertSubBox;
> +   unsigned int second = second_idx * vertSubBox;
> +
> +   float tmpVertexBuf[8] = {0.0};
> +   float tmp_buf_min[8] = {0.0};
> +   float tmp_buf_max[8] = {0.0};
> +
> +   __m256 subMin = _mm256_set1_ps(FLT_MAX);
> +   __m256 subMax = _mm256_set1_ps(-FLT_MAX);
> +
> +   /* Run both the subboxes for vertex count */
> +   for(unsigned int iter = 0; iter < vertCount; iter++){
> +      /* Calculate the vertex offset of first subbox */
> +      unsigned short index1 = indices[first+iter];
> +      /* Fetching the vertices for the first subbox */
> +      float* vertex1 = (float *)((char *)(vertices) + stride*index1);
> +      memcpy(tmpVertexBuf,vertex1, 3 * sizeof(float));
> +
> +      /* Calculate the vertex offset of second subbox */
> +      unsigned short index2 = indices[second+iter];
> +
> +      /* Fetching the vertices for the second subbox */
> +      float* vertex2 = (float *)((char *)(vertices) + stride*index2);
> +      memcpy(tmpVertexBuf+4,vertex2, 3 * sizeof(float));
> +
> +      __m256 tmp = _mm256_loadu_ps(tmpVertexBuf);
> +      subMin = _mm256_min_ps(subMin, tmp);
> +      subMax = _mm256_max_ps(subMax, tmp);
> +   }
> +
> +   /* compare full box values */
> +   fullMin = _mm256_min_ps(fullMin, subMin);
> +   fullMax = _mm256_max_ps(fullMax, subMax);
> +
> +   /* store results */
> +   _mm256_storeu_ps(tmp_buf_min, subMin);
> +   _mm256_storeu_ps(tmp_buf_max, subMax);
> +
> +
> +   /* Update the min and max values in sub box coordinates for both
> +    * the subboxes
> +    */
> +   vbo_bbox_create_bounding_box(tmp_buf_min, tmp_buf_max,
> +
> &(data->sub_bbox_array[first_idx].bounding_volume.vert_vec4[0]));
> +   vbo_bbox_create_bounding_box(tmp_buf_min+4, tmp_buf_max+4,
> +
>  &(data->sub_bbox_array[second_idx].bounding_volume.vert_vec4[0]));
> +}
> +#else
> +static void
> +vbo_bbox_calc_subbox_coordinates(
> +            unsigned int vertSubBox,
> +            unsigned int vertCount,
> +            unsigned int idx,
> +            unsigned short *indices,
> +            float *vertices,
> +            unsigned int stride,
> +            struct vbo_bbox_cache_data *data)
> +{
> +   /* Retrieving the starting offset of the first and second subbox */
> +   unsigned int first = idx * vertSubBox;
> +
> +   float tmpVertexBuf[4] = {0.0};
> +   float tmp_buf_min[4] = {0.0};
> +   float tmp_buf_max[4] = {0.0};
> +
> +   __m128 subMin = _mm_set1_ps(FLT_MAX);
> +   __m128 subMax = _mm_set1_ps(-FLT_MAX);
> +
> +   /* Run both the subboxes for vertex count */
> +   for(unsigned int iter = 0; iter < vertCount; iter++){
> +
> +      /* Calculate the vertex offset of first subbox */
> +      unsigned short index = indices[first+iter];
> +      /* Fetching the vertices for the first subbox */
> +      float* vertex = (float *)((char *)(vertices) + stride*index);
> +      memcpy(tmpVertexBuf,vertex, 3 * sizeof(float));
> +
> +      __m128 tmp = _mm_loadu_ps(tmpVertexBuf);
> +      subMin = _mm_min_ps(subMin, tmp);
> +      subMax = _mm_max_ps(subMax, tmp);
> +   }
> +
> +   /* compare full box values */
> +   fullMin = _mm_min_ps(fullMin, subMin);
> +   fullMax = _mm_max_ps(fullMax, subMax);
> +
> +   /* store results */
> +   _mm_storeu_ps(tmp_buf_min, subMin);
> +   _mm_storeu_ps(tmp_buf_max, subMax);
> +
> +   /* Update the min and max values in sub box coordinates for both
> +    * the subboxes
> +    */
> +   vbo_bbox_create_bounding_box(tmp_buf_min, tmp_buf_max,
> +
> &(data->sub_bbox_array[idx].bounding_volume.vert_vec4[0]));
> +}
> +#endif
> +
> +/**
> + *  Get pointer to VBO data.
> + *  Pointer should be suitable for fast data reading, not data change.
> + */
> +static
> +bool vbo_bbox_get_vbo_ptr(struct gl_context* gc, struct gl_buffer_object*
> vbo,
> +                          int offset, void** data, int* dataSize)
> +{
> +   assert(gc);
> +   assert(vbo);
> +   GLubyte* vboDataPtr = NULL;
> +
> +   if (offset >= vbo->Size) {
> +      return false;
> +   }
> +   vboDataPtr = _mesa_MapNamedBuffer(vbo->Name,GL_WRITE_ONLY_ARB);
> +   if (vboDataPtr == NULL) {
> +      return false;
> +   }
> +   *data = vboDataPtr + offset;
> +   *dataSize = vbo->Size - offset;
> +
> +   return true;
> +}
> +
> +/**
> + * Unlock VBO
> + */
> +static inline
> +void vbo_bbox_release_vbo_ptr(struct gl_context* gc,
> +                              struct gl_buffer_object* vbo)
> +{
> +    assert(gc);
> +    assert(vbo);
> +    _mesa_UnmapNamedBuffer_no_error(vbo->Name);
> +}
> +
> +/**
> +  * Check if given range of indices contains only degenerate triangles.
> +  */
> +static
> +bool vbo_bbox_is_degenerate(GLvoid *indices, GLuint count_in)
> +{
> +   assert(indices);
> +   assert(count_in % 3 == 0);
> +
> +   GLuint triangle_count = count_in / 3;
> +   GLuint input_idx = 0;
> +
> +   GLushort* ptr = (GLushort*)indices;
> +   for (GLuint i = 0; i < triangle_count; i++) {
> +      GLushort a = ptr[input_idx++];
> +      GLushort b = ptr[input_idx++];
> +      GLushort c = ptr[input_idx++];
> +      if (!(a == b || a == c || b == c)) {
> +          return false;
> +      }
> +   }
> +   return true;
> +}
> +
> +
> +/**
> + * Calculate bounding boxes for given geometry.
> + */
> +static
> +bool vbo_bbox_calculate_bounding_boxes_with_indices(struct gl_context
> *const gc,
> +                                             const vbo_bbox_cache_key
> *key,
> +                                             struct vbo_bbox_cache_data
> *data,
> +                                             void* indexData,
> +                                             int   indexDataSize)
> +{
> +   assert(gc);
> +
> +   void* vertex_data = NULL;
> +   int vertex_datasize = 0;
> +   int vert_per_subBbox = mesa_bbox_env_variables.bbox_split_size;
> +   int sub_bbox_cnt = (key->count + vert_per_subBbox -1)/vert_per_subBbox;
> +   int *subbox_array;
> +   int idx =0;
> +   int non_degen_count = 0;
> +
> +   assert(sub_bbox_cnt);
> +
> +   struct gl_buffer_object* element_buffer = _mesa_lookup_bufferobj(gc,
> +                                                key->element_buf_name);
> +
> +   struct gl_buffer_object * vertexattrib_buffer =
> _mesa_lookup_bufferobj(gc,
> +
>  key->vertex_buf_name);
> +
> +   if (element_buffer == NULL || vertexattrib_buffer == NULL) {
> +   return false;
> +   }
> +
> +   if (!vbo_bbox_get_vbo_ptr(gc, vertexattrib_buffer,(int) key->offset,
> +                           &vertex_data, &vertex_datasize)) {
> +   return false;
> +   }
> +
> +   assert(vertex_data);
> +   assert(vertex_datasize > 0);
> +   assert(indexData);
> +   assert(indexDataSize > 0);
> +   assert(key->indices_type == GL_UNSIGNED_SHORT);
> +   assert(indexDataSize > key->count * (int)key->type_size);
> +
> +   /* Allocate memory for bounding boxes */
> +   if (!vbo_init_sub_bbox_array(sub_bbox_cnt,data)) {
> +   vbo_bbox_release_vbo_ptr(gc, vertexattrib_buffer);
> +   return false;
> +   }
> +   /* Initialize size of bounding boxes */
> +   for (int i = 0; i < sub_bbox_cnt; i++) {
> +   data->sub_bbox_array[i].vert_count = (i==sub_bbox_cnt-1)?
> +                            (key->count -
> i*vert_per_subBbox):vert_per_subBbox;
> +   data->sub_bbox_array[i].start_offset = i*vert_per_subBbox *
> key->type_size;
> +   }
> +
> +   subbox_array = malloc(sub_bbox_cnt * sizeof(int));
> +
> +   /* Check if all triangles withing bbox are degenerate (i.e triangles
> with
> +      zero area) */
> +   for (int i = 0; i < sub_bbox_cnt; i++) {
> +      GLubyte* ptr = (GLubyte *)indexData;
> +      data->sub_bbox_array[i].is_degenerate =
> +          vbo_bbox_is_degenerate((ptr +
> data->sub_bbox_array[i].start_offset),
> +                  data->sub_bbox_array[i].vert_count);
> +
> +       if(!data->sub_bbox_array[i].is_degenerate)
> +       {
> +          subbox_array[idx++] = i;
> +          non_degen_count++;
> +       }
> +   }
> +
> +   float tmp_buf_min[8] = {0.0};
> +   float tmp_buf_max[8] = {0.0};
> +
> +#ifdef __AVX__
> +   int odd = non_degen_count % 2;
> +   int num_iter = non_degen_count/2;
> +   int iter;
> +
> +   fullMin = _mm256_set1_ps(FLT_MAX);
> +   fullMax = _mm256_set1_ps(-FLT_MAX);
> +   idx = 0;
> +   for(iter = 0; iter < num_iter;iter++){
> +      idx = 2*iter;
> +      if(data->sub_bbox_array[subbox_array[idx]].vert_count ==
> +         data->sub_bbox_array[subbox_array[idx+1]].vert_count)
> +      {
> +         /* call the algorithm with the count */
> +         vbo_bbox_calc_subbox_coordinates(
> +                       vert_per_subBbox,
> +                       data->sub_bbox_array[subbox_array[idx]].vert_count,
> +                       subbox_array[idx],
> +                       subbox_array[idx+1],
> +                       (GLushort*)indexData,
> +                       (GLfloat*)vertex_data,
> +                       key->stride,
> +                       data
> +                     );
> +      }
> +      else
> +      {
> +         /* call the first one separately */
> +         vbo_bbox_calc_subbox_coordinates(vert_per_subBbox,
> +
> data->sub_bbox_array[subbox_array[idx]].vert_count,
> +                            subbox_array[idx],
> +                            subbox_array[idx],
> +                            (GLushort*)indexData,
> +                            (GLfloat*)vertex_data,
> +                            key->stride,
> +                            data);
> +
> +         /* call the second one separately */
> +         vbo_bbox_calc_subbox_coordinates(vert_per_subBbox,
> +
> data->sub_bbox_array[subbox_array[idx+1]].vert_count,
> +                          subbox_array[idx+1],
> +                          subbox_array[idx+1],
> +                          (GLushort*)indexData,
> +                          (GLfloat*)vertex_data,
> +                          key->stride,
> +                          data);
> +
> +      }
> +
> +   }
> +
> +   if(odd)
> +   {
> +      idx = 2*iter;
> +      /* call the last one separately */
> +      vbo_bbox_calc_subbox_coordinates(vert_per_subBbox,
> +
> data->sub_bbox_array[subbox_array[idx]].vert_count,
> +                            subbox_array[idx],
> +                            subbox_array[idx],
> +                            (GLushort*)indexData,
> +                            (GLfloat*)vertex_data,
> +                            key->stride,
> +                            data);
> +   }
> +
> +   /* Finding the minimum from the full box 256 */
> +   __m128 firstlane   = _mm256_extractf128_ps(fullMin,0);
> +   __m128 secondlane = _mm256_extractf128_ps(fullMin,1);
> +   firstlane = _mm_min_ps(firstlane,secondlane);
> +   _mm_storeu_ps(tmp_buf_min,firstlane);
> +
> +   /* Finding the maximum from the full box 256 */
> +    firstlane  = _mm256_extractf128_ps(fullMax,0);
> +    secondlane = _mm256_extractf128_ps(fullMax,1);
> +    firstlane = _mm_max_ps(firstlane,secondlane);
> +    _mm_storeu_ps(tmp_buf_max,firstlane);
> +
> +#else
> +    fullMin = _mm_set1_ps(FLT_MAX);
> +    fullMax = _mm_set1_ps(-FLT_MAX);
> +
> +    for(unsigned int i=0; i< non_degen_count; i++){
> +       //call the algorithm with the count
> +       vbo_bbox_calc_subbox_coordinates(vert_per_subBbox,
> +
> data->sub_bbox_array[subbox_array[i]].vert_count,
> +                              subbox_array[i],
> +                              (GLushort*)indexData,
> +                              (GLfloat*)vertex_data,
> +                              key->stride,
> +                              data);
> +       }
> +       _mm_storeu_ps(tmp_buf_min, fullMin);
> +       _mm_storeu_ps(tmp_buf_max, fullMax);
> +#endif
> +
> +    /* Set up bounding box as 8 vertices and store in bbox data */
> +    vbo_bbox_create_bounding_box(tmp_buf_min, tmp_buf_max,
> +                          &(data->full_box.bounding_volume.vert_vec4[0]));
> +
> +    if(subbox_array)
> +      free(subbox_array);
> +    vbo_bbox_release_vbo_ptr(gc, vertexattrib_buffer);
> +    data->valid = true;
> +
> +    return true;
> +}
> +
> +
> +/**
> +  * Calculate bounding boxes for given geometry.
> +  */
> +static inline
> +bool vbo_bbox_calculate_bounding_boxes(struct gl_context *const gc,
> +                                       const vbo_bbox_cache_key *key,
> +                                       struct vbo_bbox_cache_data* data)
> +{
> +    assert(gc);
> +    assert(key->indices_type == GL_UNSIGNED_SHORT);
> +
> +    void* pIndexData     = NULL;
> +    int   indexDataSize  = 0;
> +
> +    struct gl_buffer_object* element_buffer = _mesa_lookup_bufferobj(gc,
> +
> key->element_buf_name);
> +    if (element_buffer == NULL) {
> +      return false;
> +    }
> +    if (!vbo_bbox_get_vbo_ptr(gc, element_buffer, (int) key->indices,
> +                              &pIndexData, &indexDataSize)) {
> +      return false;
> +    }
> +
> +    bool ret = vbo_bbox_calculate_bounding_boxes_with_indices(gc, key,
> data,
> +                                                    pIndexData,
> indexDataSize);
> +
> +    vbo_bbox_release_vbo_ptr(gc, element_buffer);
> +
> +    return ret;
> +}
> +
> +
> +/**
> +  *  Create new bounding box cache entry
> +  */
> +static
> +struct vbo_bbox_cache_data* vbo_bbox_create_data(struct gl_context *const
> gc,
> +                                                 const vbo_bbox_cache_key
> *key)
> +{
> +   assert(gc);
> +
> +   struct gl_buffer_object* element_buffer =
> vbo_get_current_element_buffer(gc);
> +   struct gl_buffer_object* vertexattrib_buffer =
> +
>  vbo_get_current_vertex_buffer(gc);
> +
> +   if ((vertexattrib_buffer == NULL) ||
> +     (element_buffer == NULL)){
> +      return NULL;
> +   }
> +
> +   mesa_bbox_opt * BboxOpt = gc->Pipeline.BboxOpt;
> +   assert(BboxOpt);
> +
> +   struct vbo_bbox_cache_data* data = (struct vbo_bbox_cache_data *)
> malloc(
> +                                      sizeof (struct
> vbo_bbox_cache_data));
> +   data->full_box.is_degenerate = false;
> +
> +   if (data == NULL){
> +      return NULL;
> +   }
> +   /* Initialize the cache data and variables in cache data */
> +   data->valid = false;
> +   data->need_new_calculation = true;
> +   data->init_delaycnt = 0;
> +   data->init_delaylimit = 0;
> +   data->vertpos_vbo_changecnt = 0;
> +   data->indices_vbo_changecnt = 0;
> +   data->sub_bbox_cnt = 0;
> +   data->sub_bbox_array = NULL;
> +   data->drawcnt_bbox_helped = 0;
> +   data->last_use_frame = 0;
> +   data->vertpos_vbo_changecnt   =
> vertexattrib_buffer->data_change_counter;
> +   data->indices_vbo_changecnt   = element_buffer->data_change_counter;
> +
> +   /* This defines for how many cache hits we wait before actually
> creating the
> +    * data */
> +   data->init_delaylimit = vbo_bbox_get_delay(BboxOpt);
> +
> +   /* At this point data is not valid yet */
> +   _mesa_bbox_cache_insert(gc,gc->Pipeline.BboxOpt->cache,
> +                           key,sizeof(vbo_bbox_cache_key),data);
> +
> +   return data;
> +}
> +
> +
> +/**
> + * Check if contents of the VBO buffers have changed since data entry
> + * was created.
> + */
> +static inline
> +bool vbo_bbox_validate_data(
> +    struct gl_context *const gc,
> +    const vbo_bbox_cache_key *key,
> +    struct vbo_bbox_cache_data* data)
> +{
> +   assert(gc);
> +
> +   struct gl_buffer_object* element_buffer = _mesa_lookup_bufferobj(gc,
> +                                               key->element_buf_name);
> +
> +   struct gl_buffer_object * vertexattrib_buffer =
> _mesa_lookup_bufferobj(gc,
> +
> key->vertex_buf_name);
> +
> +   if (element_buffer == NULL || vertexattrib_buffer == NULL) {
> +      return false;
> +   }
> +
> +   if ((element_buffer->data_change_counter !=
> data->indices_vbo_changecnt) ||
> +     (vertexattrib_buffer->data_change_counter !=
> data->vertpos_vbo_changecnt)
> +     ) {
> +      return false;
> +   }
> +   return true;
> +}
> +
> +/**
> + *  Retrieve bounding box data from cache.
> + */
> +static inline
> +struct vbo_bbox_cache_data* vbo_bbox_get_bounding_boxes(
> +                                                 struct gl_context *const
> gc,
> +                                                 const vbo_bbox_cache_key
> *key)
> + {
> +
> +   assert(gc);
> +   mesa_bbox_opt * BboxOpt = gc->Pipeline.BboxOpt;
> +   assert(BboxOpt);
> +   struct vbo_bbox_cache_data* data =
> _mesa_search_bbox_cache(BboxOpt->cache,
> +                                              key,
> sizeof(vbo_bbox_cache_key));
> +   if (data) {
> +      if (data->need_new_calculation == false)
> +      {
> +         /* Data is initialized and valid */
> +         if (data->valid) {
> +             if (vbo_bbox_validate_data(gc, key, data)) {
> +                data->mvp_valid = true;
> +                return data;
> +             }
> +         }
> +         else {
> +             data->valid = false;
> +             return NULL;
> +         }
> +      }
> +   }
> +   else {
> +      /* Data does not exist, create it */
> +      data = vbo_bbox_create_data(gc, key);
> +      if (data == NULL)
> +      {
> +         return NULL;
> +      }
> +   }
> +   if ((data->need_new_calculation) &&
> +     (data->init_delaycnt++ >= data->init_delaylimit)) {
> +     data->valid = false;
> +     data->need_new_calculation = false;
> +     data->mvp_valid = false;
> +
> +     if (!vbo_bbox_validate_data(gc, key, data)) {
> +         struct gl_buffer_object * element_buffer =
> +                 _mesa_lookup_bufferobj(gc,key->element_buf_name);
> +
> +         struct gl_buffer_object * vertexattrib_buffer =
> +                 _mesa_lookup_bufferobj(gc,key->vertex_buf_name);
> +
> +         if ((vertexattrib_buffer == NULL) ||
> +             (element_buffer == NULL)) {
> +             return NULL;
> +         }
> +         data->vertpos_vbo_changecnt =
> vertexattrib_buffer->data_change_counter;
> +         data->indices_vbo_changecnt =
> element_buffer->data_change_counter;
> +      }
> +      if (gc->volume_type == BOUNDING_VOLUME_AABB) {
> +         /* Calculate bounding boxes */
> +         if (vbo_bbox_calculate_bounding_boxes(gc, key, data)) {
> +             return data;
> +         }
> +      }
> +   }
> +   return NULL;
> +}
> +
> +/**
> + * This function is called when we updating the element buffer. because
> the
> + * element-buffer has changed we have to update the relevant bbox data:
> + */
> +void vbo_bbox_element_buffer_update(struct gl_context *const gc,
> +                                    struct gl_buffer_object *buffer,
> +                                    const void* data,
> +                                    int offset,
> +                                    int size)
> +{
> +   mesa_bbox_opt * BboxOpt = gc->Pipeline.BboxOpt;
> +
> +   if (BboxOpt) {
> +      struct gl_segment updateSegment;
> +      updateSegment.Left = offset;
> +      updateSegment.Right = offset+size;
> +
> +      mesa_bbox_cache
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20180831/c0c97920/attachment-0001.html>


More information about the mesa-dev mailing list