[Mesa-dev] [PATCH] Implement HW accelerated GL_SELECT

Brian Paul brianp at vmware.com
Wed Aug 3 07:18:20 PDT 2011


On 08/02/2011 10:24 AM, Micael Dias wrote:
> ---
>   src/mesa/SConscript                          |    1 +
>   src/mesa/main/mtypes.h                       |    7 +
>   src/mesa/sources.mak                         |    1 +
>   src/mesa/state_tracker/st_cb_feedback.c      |   21 +-
>   src/mesa/state_tracker/st_draw.h             |   17 +
>   src/mesa/state_tracker/st_draw_select_emul.c |  475 ++++++++++++++++++++++++++
>   6 files changed, 517 insertions(+), 5 deletions(-)
>   create mode 100644 src/mesa/state_tracker/st_draw_select_emul.c
>
> diff --git a/src/mesa/SConscript b/src/mesa/SConscript
> index 24e2155..288b162 100644
> --- a/src/mesa/SConscript
> +++ b/src/mesa/SConscript
> @@ -262,6 +262,7 @@ statetracker_sources = [
>       'state_tracker/st_debug.c',
>       'state_tracker/st_draw.c',
>       'state_tracker/st_draw_feedback.c',
> +    'state_tracker/st_draw_select_emul.c',
>       'state_tracker/st_extensions.c',
>       'state_tracker/st_format.c',
>       'state_tracker/st_gen_mipmap.c',
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index b881183..10222d8 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -1721,6 +1721,13 @@ struct gl_selection
>      GLboolean HitFlag;	/**<  hit flag */
>      GLfloat HitMinZ;	/**<  minimum hit depth */
>      GLfloat HitMaxZ;	/**<  maximum hit depth */
> +   struct gl_selection_emul /* data related to hw accelerated GL_SELECT */
> +   {
> +      GLboolean hw_unsupported;
> +      struct gl_framebuffer *fbo;
> +      GLuint renderBuffer_depth;
> +      GLuint renderBuffer_color;
> +   } emul;
>   };

These extra selection fields should go into st_context since they're 
only used in the state tracker.


> diff --git a/src/mesa/sources.mak b/src/mesa/sources.mak
> index 4b2ec08..9af4079 100644
> --- a/src/mesa/sources.mak
> +++ b/src/mesa/sources.mak
> @@ -229,6 +229,7 @@ STATETRACKER_SOURCES = \
>   	state_tracker/st_debug.c \
>   	state_tracker/st_draw.c \
>   	state_tracker/st_draw_feedback.c \
> +	state_tracker/st_draw_select_emul.c \
>   	state_tracker/st_extensions.c \
>   	state_tracker/st_format.c \
>   	state_tracker/st_gen_mipmap.c \
> diff --git a/src/mesa/state_tracker/st_cb_feedback.c b/src/mesa/state_tracker/st_cb_feedback.c
> index 9b85a39..9382895 100644
> --- a/src/mesa/state_tracker/st_cb_feedback.c
> +++ b/src/mesa/state_tracker/st_cb_feedback.c
> @@ -276,17 +276,28 @@ st_RenderMode(struct gl_context *ctx, GLenum newMode )
>   {
>      struct st_context *st = st_context(ctx);
>      struct draw_context *draw = st->draw;
> +   bool hw_acc_path = _mesa_getenv("MESA_HW_SELECT")&&  !ctx->Select.emul.hw_unsupported;
>
>      if (newMode == GL_RENDER) {
>         /* restore normal VBO draw function */
>         vbo_set_draw_func(ctx, st_draw_vbo);
>      }
>      else if (newMode == GL_SELECT) {
> -      if (!st->selection_stage)
> -         st->selection_stage = draw_glselect_stage(ctx, draw);
> -      draw_set_rasterize_stage(draw, st->selection_stage);
> -      /* Plug in new vbo draw function */
> -      vbo_set_draw_func(ctx, st_feedback_draw_vbo);
> +      if (hw_acc_path) {
> +         if (st_select_emul_begin(ctx)) {
> +            vbo_set_draw_func(ctx, st_select_draw_func);
> +         }
> +         else {
> +            hw_acc_path = false;
> +         }
> +      }
> +      if (!hw_acc_path) {
> +         if (!st->selection_stage)
> +            st->selection_stage = draw_glselect_stage(ctx, draw);
> +         draw_set_rasterize_stage(draw, st->selection_stage);
> +         /* Plug in new vbo draw function */
> +         vbo_set_draw_func(ctx, st_feedback_draw_vbo);
> +      }
>      }
>      else {
>         if (!st->feedback_stage)
> diff --git a/src/mesa/state_tracker/st_draw.h b/src/mesa/state_tracker/st_draw.h
> index a7b50ce..d27e321 100644
> --- a/src/mesa/state_tracker/st_draw.h
> +++ b/src/mesa/state_tracker/st_draw.h
> @@ -87,5 +87,22 @@ pointer_to_offset(const void *ptr)
>      return (unsigned) (((unsigned long) ptr)&  0xffffffffUL);
>   }
>
> +/* Functions used by the hw accelerated GL_SELECT emulator
> + */
> +extern bool
> +st_select_emul_begin(struct gl_context *ctx);
> +
> +extern void
> +st_select_emul_end(struct gl_context *ctx);
> +
> +extern void
> +st_select_draw_func(struct gl_context *ctx,
> +            const struct gl_client_array **arrays,
> +            const struct _mesa_prim *prims,
> +            GLuint nr_prims,
> +            const struct _mesa_index_buffer *ib,
> +            GLboolean index_bounds_valid,
> +            GLuint min_index,
> +            GLuint max_index);
>
>   #endif
> diff --git a/src/mesa/state_tracker/st_draw_select_emul.c b/src/mesa/state_tracker/st_draw_select_emul.c
> new file mode 100644
> index 0000000..ea54f22
> --- /dev/null
> +++ b/src/mesa/state_tracker/st_draw_select_emul.c
> @@ -0,0 +1,475 @@
> +/**************************************************************************
> + *
> + * Copyright 2011 Micael Dias<kam1kaz3 (at) gmail (dot) com>.
> + * All Rights Reserved.
> + *
> + * 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, sub license, 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 NON-INFRINGEMENT.
> + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
> + *
> + **************************************************************************/
> +
> +/**
> + * This file contains code that attempts to accelerate GL_SELECT rendering.
> + * It was created with the intent of solving the following bug:
> + *     https://bugs.freedesktop.org/show_bug.cgi?id=34495
> + *
> + * This code is a rewritten version of the patch "GL_SELECT hw support v5"
> + * posted by user Pierre-Eric Pelloux-Prayer in the previously mentioned bug.
> + *
> + * In order to test this code, the env. variable MESA_HW_SELECT should be
> + * exported.
> + */

Could you add another comment here explaining the method/algorithm 
being used?  Nobody is going to want to dig through the email archives 
to find out what "GL_SELECT hw support v5" is, or piece together bits 
and pieces from the bug report.

BTW, there's another way to do this and avoid drawing everything 
twice.  However, it depends on having floating point color buffers and 
independent blend equations.

Basically, write the fragment Z value to two color outputs:

main()
{
    gl_FragData[0] = gl_FragData[1] = vec4(gl_FragCoord.z);
}

Set up blend equation 0 to be GL_MIN and blend equation 1 to be GL_MAX.

When you're done drawing color buffer 0 should have Zmin and color 
buffer 1 should have Zmax.


> +
> +#include "main/imports.h"
> +#include "main/image.h"
> +#include "main/macros.h"
> +#include "main/mfeatures.h"
> +#include "main/hash.h"
> +
> +#include "main/context.h"
> +#include "main/enable.h"
> +#include "main/fbobject.h"
> +#include "main/depth.h"
> +#include "main/state.h"
> +#include "main/scissor.h"
> +#include "main/viewport.h"
> +#include "main/framebuffer.h"
> +#include "main/feedback.h"
> +
> +#include "vbo/vbo.h"
> +
> +#include "st_context.h"
> +#include "st_atom.h"
> +#include "st_cb_bufferobjects.h"
> +#include "st_draw.h"
> +#include "st_program.h"
> +#include "st_texture.h"
> +#include "st_cb_readpixels.h"
> +
> +#include "pipe/p_context.h"
> +#include "pipe/p_defines.h"
> +#include "pipe/p_state.h"
> +#include "pipe/p_format.h"
> +#include "util/u_inlines.h"
> +
> +#include "draw/draw_private.h"
> +#include "draw/draw_context.h"
> +
> +bool
> +st_select_emul_create_fbo(struct gl_context *ctx);
> +
> +void
> +st_select_emul_destroy_fbo(struct gl_context *ctx);
> +
> +void
> +st_select_emul_check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb);
> +
> +void
> +st_select_emul_check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb);
> +
> +void
> +st_select_emul_clear_fbo(struct gl_context *ctx);
> +
> +void
> +st_select_emul_update_hits(struct gl_context *ctx);

I don't think all these prototypes are needed.  In some cases you can 
simply place the implementation before the first call.  You should 
also declare functions static whenever possible.


> +
> +/**
> + * Check if any of the attachments of the given framebuffer are textures
> + * (render to texture).  Call ctx->Driver.RenderTexture() for such
> + * attachments.
> + */
> +void
> +st_select_emul_check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
> +{
> +   GLuint i;
> +   ASSERT(ctx->Driver.RenderTexture);
> +
> +   if (fb==0)
> +      return; /* can't render to texture with winsys framebuffers */

The test and comment don't agree.  You're testing for a NULL fb 
pointer but the correct test for a winsys framebuffer is

if (fb->Name == 0)

If that's what you intend, we should move the is_winsys_fbo() function 
seen in fbobject.c to fbobject.h and rename it to _mesa_is_winsys_fbo().


> +   for (i = 0; i<  BUFFER_COUNT; i++) {
> +      struct gl_renderbuffer_attachment *att = fb->Attachment + i;
> +      if (att->Texture&&  _mesa_get_attachment_teximage(att)) {
> +         ctx->Driver.RenderTexture(ctx, fb, att);
> +      }
> +   }
> +}
> +
> +
> +/**
> + * Examine all the framebuffer's attachments to see if any are textures.
> + * If so, call ctx->Driver.FinishRenderTexture() for each texture to
> + * notify the device driver that the texture image may have changed.
> + */
> +void
> +st_select_emul_check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
> +{
> +   if (fb==0)
> +      return; /* can't render to texture with winsys framebuffers */
> +
> +   if (ctx->Driver.FinishRenderTexture) {
> +      GLuint i;
> +      for (i = 0; i<  BUFFER_COUNT; i++) {
> +         struct gl_renderbuffer_attachment *att = fb->Attachment + i;
> +         if (att->Texture&&  att->Renderbuffer) {
> +            ctx->Driver.FinishRenderTexture(ctx, att);
> +         }
> +      }
> +   }
> +}
> +
> +/**
> + * Create and setup FBO needed for our operations
> + */
> +bool
> +st_select_emul_create_fbo(struct gl_context *ctx)
> +{
> +   GLuint fboName;
> +
> +   /* make sure we don't leak memory */
> +   st_select_emul_destroy_fbo(ctx);
> +
> +   /* create buffer names */
> +   _mesa_GenFramebuffersEXT(1,&fboName);
> +   _mesa_GenRenderbuffersEXT(1,&ctx->Select.emul.renderBuffer_depth);
> +   _mesa_GenRenderbuffersEXT(1,&ctx->Select.emul.renderBuffer_color);
> +
> +   /* allocate buffers' memory */
> +   _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, fboName);
> +   _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, ctx->Select.emul.renderBuffer_depth);
> +   _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 2, 1);
> +   _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, ctx->Select.emul.renderBuffer_color);
> +   _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, 2, 1);
> +   _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, 0);
> +
> +   /* setup fbo */
> +   _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, ctx->Select.emul.renderBuffer_depth);
> +   _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, ctx->Select.emul.renderBuffer_color);
> +
> +   if( _mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )
> +      return false;
> +
> +   _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, 0);
> +
> +   /* get fbo pointer */
> +   ctx->Select.emul.fbo = _mesa_lookup_framebuffer(ctx, fboName);
> +
> +   return true;
> +}
> +
> +/**
> + * Clean up data
> + */
> +void
> +st_select_emul_destroy_fbo(struct gl_context *ctx)
> +{
 > +   if( ctx->Select.emul.renderBuffer_color ) {

To be consistent, the whitespace should be:

   if (ctx->Select.emul.renderBuffer_color) {


> +      _mesa_DeleteRenderbuffersEXT( 1,&ctx->Select.emul.renderBuffer_color );
> +      ctx->Select.emul.renderBuffer_color = 0;
> +   }
> +   if( ctx->Select.emul.renderBuffer_depth ) {
> +      _mesa_DeleteRenderbuffersEXT( 1,&ctx->Select.emul.renderBuffer_depth );
> +      ctx->Select.emul.renderBuffer_depth = 0;
> +   }
> +   if( ctx->Select.emul.fbo ) {
> +      _mesa_DeleteFramebuffersEXT( 1,&ctx->Select.emul.fbo->Name );
> +      _mesa_reference_framebuffer(&ctx->Select.emul.fbo, NULL );
> +   }
> +}
> +
> +/**
> + * Called when entering GL_SELECT mode.
> + * This function initializes our private data and clears
> + * depth so that the next draw call will have it ready.
> + */
> +bool
> +st_select_emul_begin(struct gl_context *ctx)
> +{
> +   /* TODO: Check for hardware support and fill
> +   ctx->Select.emul.hw_unsupported accordingly */
> +
> +   /* initialize fbo if not yet initialized */
> +   if (!ctx->Select.emul.fbo) {
> +      if (!st_select_emul_create_fbo(ctx)) {
> +         return false;
> +      }
> +   }
> +
> +   /* clear FBO */
> +   st_select_emul_clear_fbo(ctx);
> +
> +   return true;
> +}
> +
> +void
> +st_select_emul_end(struct gl_context *ctx)
> +{
> +   st_select_emul_destroy_fbo(ctx);
> +}
> +
> +/**
> + * Helper function to change depth state
> + */
> +static void
> +select_change_depth_state(struct gl_context *ctx, GLenum func, GLboolean mask, GLboolean test) {

The opening brace should be on a separate line.


> +   /* depth function */
> +   if (ctx->Depth.Func != func) {
> +      ctx->NewState |= _NEW_DEPTH;
> +      ctx->Depth.Func = func;
> +
> +      if (ctx->Driver.DepthFunc)
> +         ctx->Driver.DepthFunc( ctx, func );
> +   }
> +
> +   /* depth mask */
> +   if (ctx->Depth.Mask != mask) {
> +      ctx->NewState |= _NEW_DEPTH;
> +      ctx->Depth.Mask = mask;
> +
> +      if (ctx->Driver.DepthMask)
> +         ctx->Driver.DepthMask( ctx, mask );
> +   }
> +
> +   /* depth test */
> +   if (ctx->Depth.Test != test) {
> +      ctx->NewState |= _NEW_DEPTH;
> +      ctx->Depth.Test = test;
> +   }
> +}
> +
> +/**
> + * Clears the depth values of our FBO by setting the
> + * 1st pixel to 1.0f and the 2nd to 0.0f
> + */
> +void
> +st_select_emul_clear_fbo(struct gl_context *ctx)
> +{
> +   struct gl_scissor_attrib saved_scissor;
> +   struct gl_framebuffer *saved_fbo = NULL;
> +   GLfloat clearDepth;
> +
> +   /* save states */
> +   memcpy(&saved_scissor,&ctx->Scissor, sizeof(struct gl_scissor_attrib));

You could use simple struct copy here:

     saved_scissor = ctx->Scissor;


> +   if (ctx->DrawBuffer) {
> +      _mesa_reference_framebuffer(&saved_fbo, ctx->DrawBuffer );
> +   }
> +   clearDepth = ctx->Depth.Clear;
> +
> +   /* hack needed because Clear does nothing if render mode != GL_RENDER */
> +   ctx->RenderMode = GL_RENDER;
> +
> +   /* disable old draw fbo */
> +   if (saved_fbo)
> +   {

Put brace on preceeding line.


> +      /* XXX: needs flushing? */
> +      st_select_emul_check_end_texture_render(ctx, saved_fbo);
> +   }
> +
> +   /* use our fbo */
> +   st_select_emul_check_begin_texture_render(ctx, ctx->Select.emul.fbo);
> +   _mesa_reference_framebuffer(&ctx->DrawBuffer, ctx->Select.emul.fbo);
> +
> +   /* update fbo */
> +   _mesa_update_framebuffer( ctx );
> +
> +   /* enable scissor */
> +   ctx->Scissor.Enabled = GL_TRUE;
> +
> +   /* clear min-Z */
> +   ctx->Scissor.X = 0;
> +   ctx->Scissor.Y = 0;
> +   ctx->Scissor.Width = 1;
> +   ctx->Scissor.Height = 1;
> +   ctx->Depth.Clear = 1.0f;
> +   if (ctx->Driver.ClearDepth)
> +      (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear );
> +   ctx->NewState |= _NEW_SCISSOR | _NEW_DEPTH | _NEW_BUFFERS;
> +   _mesa_update_state( ctx );
> +   ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH);
> +
> +   /* clear max-Z */
> +   ctx->Scissor.X = 1;
> +   ctx->Scissor.Y = 0;
> +   ctx->Scissor.Width = 1;
> +   ctx->Scissor.Height = 1;
> +   ctx->Depth.Clear = 0.0f;
> +   if (ctx->Driver.ClearDepth)
> +      (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear );
> +   ctx->NewState |= _NEW_SCISSOR | _NEW_DEPTH;
> +   _mesa_update_state( ctx );
> +   ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH);

Wouldn't it be simpler to initialize the depth buffer with a 
glDrawPixels call?  The ctx->Driver.Clear() calls isn't exactly cheap 
since it's setting up all the state to draw a quad (because scissoring 
is enabled).


> +   /* restore states */
> +   st_select_emul_check_end_texture_render(ctx, ctx->Select.emul.fbo);
> +   if (saved_fbo) {
> +      st_select_emul_check_begin_texture_render(ctx, saved_fbo);
> +      _mesa_reference_framebuffer(&ctx->DrawBuffer, saved_fbo);
> +      _mesa_reference_framebuffer(&saved_fbo, NULL);
> +   }
> +   else
> +      _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL);
> +
> +   ctx->RenderMode = GL_SELECT;
> +   ctx->Depth.Clear = clearDepth;
> +   if (ctx->Driver.ClearDepth)
> +      (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear );

    ctx->Driver.ClearDepth(ctx, ctx->Depth.Clear);


> +   memcpy(&ctx->Scissor,&saved_scissor, sizeof(struct gl_scissor_attrib));

    ctx->Scissor = saved_scissor;


> +   ctx->NewState |= _NEW_SCISSOR | _NEW_DEPTH | _NEW_BUFFERS;
> +   _mesa_update_state( ctx );
> +}
> +
> +/**
> + * Plug in draw function to draw in GL_SELECT mode.
> + * This function does the following steps:
> + *   1) render into the 1st pixel of our FBO with depth state
> + *      configured so that we get the lowest Z values
> + *   2) render into the 2nd pixel of our FBO with depth state
> + *      configured so that we get the highest Z values
> + *   3) calls st_select_emul_update_hits() to emit results
> + */
> +void
> +st_select_draw_func(struct gl_context *ctx,
> +            const struct gl_client_array **arrays,
> +            const struct _mesa_prim *prims,
> +            GLuint nr_prims,
> +            const struct _mesa_index_buffer *ib,
> +            GLboolean index_bounds_valid,
> +            GLuint min_index,
> +            GLuint max_index)

Those lines should be indented further, past the '('.


> +{
> +   struct gl_depthbuffer_attrib saved_depth;
> +   struct gl_viewport_attrib saved_viewport;
> +   GLboolean saved_scissorEnabled;
> +   struct gl_framebuffer *saved_fbo = NULL;
> +   struct st_context *st = st_context(ctx);
> +   struct pipe_context *pipe = st->pipe;
> +   struct pipe_fence_handle *fence;
> +
> +   /* save states */
> +   if (ctx->DrawBuffer)
> +      _mesa_reference_framebuffer(&saved_fbo, ctx->DrawBuffer);
> +   memcpy(&saved_depth,&ctx->Depth, sizeof(struct gl_depthbuffer_attrib));
> +   memcpy(&saved_viewport,&ctx->Viewport, sizeof(struct gl_viewport_attrib));

Can use struct copy again here.


> +   saved_scissorEnabled = ctx->Scissor.Enabled;
> +
> +   /* disable scissor */
> +   ctx->Scissor.Enabled = GL_FALSE;
> +
> +   /* disable old draw fbo */
> +   if (saved_fbo)
> +      st_select_emul_check_end_texture_render(ctx, saved_fbo);
> +
> +   /* use our fbo */
> +   st_select_emul_check_begin_texture_render(ctx, ctx->Select.emul.fbo);
> +   _mesa_reference_framebuffer(&ctx->DrawBuffer, ctx->Select.emul.fbo);
> +
> +   /* update fbo */
> +   _mesa_update_framebuffer( ctx );
> +
> +   /* render min-z */
> +   select_change_depth_state(ctx, GL_LESS, GL_TRUE, GL_TRUE);
> +   _mesa_set_viewport(ctx,
> +                      0, 0,
> +                      1, 1);

I'd put these params all on one line.  It's a simple call.


> +   _mesa_update_state(ctx);
> +   st_draw_vbo(ctx, arrays, prims, nr_prims, ib, index_bounds_valid, min_index, max_index);
> +
> +   /* render max-z */
> +   select_change_depth_state(ctx, GL_GREATER, GL_TRUE, GL_TRUE);
> +   _mesa_set_viewport(ctx,
> +                      1, 0,
> +                      1, 1);
> +   _mesa_update_state(ctx);
> +   st_draw_vbo(ctx, arrays, prims, nr_prims, ib, index_bounds_valid, min_index, max_index);
> +
> +   /* XXX: needs flushing? */
> +
> +   /* restore states */
> +   ctx->Scissor.Enabled = saved_scissorEnabled;
> +   select_change_depth_state(ctx, saved_depth.Func, saved_depth.Mask, saved_depth.Test);
> +   st_select_emul_check_end_texture_render(ctx, ctx->Select.emul.fbo);
> +   if (saved_fbo) {
> +      st_select_emul_check_begin_texture_render(ctx, saved_fbo);
> +      _mesa_reference_framebuffer(&ctx->DrawBuffer, saved_fbo);
> +      _mesa_reference_framebuffer(&saved_fbo, NULL);
> +   }
> +   else
> +      _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL);
> +   _mesa_set_viewport(ctx, saved_viewport.X, saved_viewport.Y, saved_viewport.Width, saved_viewport.Height);
> +   _mesa_update_state(ctx);
> +
> +   /* update hits */
> +   st_select_emul_update_hits(ctx);
> +}
> +
> +/**
> + * Reads into our FBO and emit z-buffer results
> + * called by st_select_draw_func()
> + */
> +void
> +st_select_emul_update_hits(struct gl_context *ctx)
> +{
> +   struct gl_framebuffer *saved_fbo = NULL;
> +   float zData[2];
> +
> +   /* set state */
> +   if (ctx->ReadBuffer) {
> +      _mesa_reference_framebuffer(&saved_fbo, ctx->ReadBuffer);
> +      st_select_emul_check_end_texture_render(ctx, saved_fbo);
> +   }
> +   st_select_emul_check_begin_texture_render(ctx, ctx->Select.emul.fbo);
> +   _mesa_reference_framebuffer(&ctx->ReadBuffer, ctx->Select.emul.fbo);
> +
> +   /* update fbo */
> +   _mesa_update_framebuffer( ctx );
> +
> +   /* update state */
> +   ctx->NewState |= _NEW_BUFFERS;
> +   _mesa_update_state( ctx );
> +
> +   /* read pixels */
> +   ctx->Driver.ReadPixels( ctx, 0, 0, 2, 1,
> +                           GL_DEPTH_COMPONENT, GL_FLOAT,
> +&ctx->Pack, (void*)zData );
> +
> +   /* emit z-buffer results */
> +   if (zData[0] != 1.0f)
> +      _mesa_update_hitflag( ctx, zData[0] );
> +   if (zData[1] != 0.0f)
> +      _mesa_update_hitflag( ctx, zData[1] );
> +
> +   /* clear FBO */
> +   st_select_emul_clear_fbo(ctx);
> +
> +   /* restore state */
> +   st_select_emul_check_end_texture_render(ctx, ctx->Select.emul.fbo);
> +   if (saved_fbo) {
> +      st_select_emul_check_begin_texture_render(ctx, saved_fbo);
> +      _mesa_reference_framebuffer(&ctx->ReadBuffer, saved_fbo);
> +      _mesa_reference_framebuffer(&saved_fbo, NULL);
> +   }
> +   else
> +      _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL);
> +
> +   /* update state */
> +   ctx->NewState |= _NEW_BUFFERS;
> +   _mesa_update_state( ctx );
> +}
> +

After these things are cleaned up I'd like the code to go into a new 
feature branch in git so we can play with it for a while and make sure 
there's no regressions.

Thanks.

-Brian


More information about the mesa-dev mailing list