[Mesa-dev] [PATCH] Implement HW accelerated GL_SELECT
Alex Deucher
alexdeucher at gmail.com
Thu Aug 25 08:17:29 PDT 2011
On Wed, Aug 24, 2011 at 10:35 AM, Micael <kam1kaz3 at gmail.com> wrote:
> Any more feedback regarding this?
> I now don't have much time to work on it again, but I may find some, so
> knowing what's left to do would be nice...
Does anyone want to see this in a separate branch first, or should it
just go into master?
Alex
>
> On Thu, Aug 4, 2011 at 2:59 PM, Micael Dias <kam1kaz3 at gmail.com> wrote:
>>
>> ---
>> src/mesa/SConscript | 1 +
>> src/mesa/main/fbobject.c | 16 +-
>> src/mesa/main/fbobject.h | 6 +
>> src/mesa/sources.mak | 1 +
>> src/mesa/state_tracker/st_cb_feedback.c | 21 +-
>> src/mesa/state_tracker/st_context.h | 10 +
>> src/mesa/state_tracker/st_draw.h | 17 +
>> src/mesa/state_tracker/st_draw_select_emul.c | 490
>> ++++++++++++++++++++++++++
>> 8 files changed, 549 insertions(+), 13 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/fbobject.c b/src/mesa/main/fbobject.c
>> index 82eb7fb..1aea62b 100644
>> --- a/src/mesa/main/fbobject.c
>> +++ b/src/mesa/main/fbobject.c
>> @@ -1560,8 +1560,8 @@ _mesa_IsFramebufferEXT(GLuint framebuffer)
>> * (render to texture). Call ctx->Driver.RenderTexture() for such
>> * attachments.
>> */
>> -static void
>> -check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer
>> *fb)
>> +void
>> +_mesa_check_begin_texture_render(struct gl_context *ctx, struct
>> gl_framebuffer *fb)
>> {
>> GLuint i;
>> ASSERT(ctx->Driver.RenderTexture);
>> @@ -1583,8 +1583,8 @@ check_begin_texture_render(struct gl_context *ctx,
>> struct gl_framebuffer *fb)
>> * If so, call ctx->Driver.FinishRenderTexture() for each texture to
>> * notify the device driver that the texture image may have changed.
>> */
>> -static void
>> -check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer
>> *fb)
>> +void
>> +_mesa_check_end_texture_render(struct gl_context *ctx, struct
>> gl_framebuffer *fb)
>> {
>> if (is_winsys_fbo(fb))
>> return; /* can't render to texture with winsys framebuffers */
>> @@ -1713,7 +1713,7 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint
>> framebuffer)
>> FLUSH_VERTICES(ctx, _NEW_BUFFERS);
>>
>> /* check if old readbuffer was render-to-texture */
>> - check_end_texture_render(ctx, oldReadFb);
>> + _mesa_check_end_texture_render(ctx, oldReadFb);
>>
>> _mesa_reference_framebuffer(&ctx->ReadBuffer, newReadFb);
>> }
>> @@ -1723,13 +1723,13 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint
>> framebuffer)
>>
>> /* check if old read/draw buffers were render-to-texture */
>> if (!bindReadBuf)
>> - check_end_texture_render(ctx, oldReadFb);
>> + _mesa_check_end_texture_render(ctx, oldReadFb);
>>
>> if (oldDrawFb != oldReadFb)
>> - check_end_texture_render(ctx, oldDrawFb);
>> + _mesa_check_end_texture_render(ctx, oldDrawFb);
>>
>> /* check if newly bound framebuffer has any texture attachments */
>> - check_begin_texture_render(ctx, newDrawFb);
>> + _mesa_check_begin_texture_render(ctx, newDrawFb);
>>
>> _mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
>> }
>> diff --git a/src/mesa/main/fbobject.h b/src/mesa/main/fbobject.h
>> index 7eb2005..ca6251c 100644
>> --- a/src/mesa/main/fbobject.h
>> +++ b/src/mesa/main/fbobject.h
>> @@ -101,6 +101,12 @@ _mesa_is_legal_color_format(const struct gl_context
>> *ctx, GLenum baseFormat);
>> extern GLenum
>> _mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat);
>>
>> +extern void
>> +_mesa_check_begin_texture_render(struct gl_context *ctx, struct
>> gl_framebuffer *fb);
>> +
>> +extern void
>> +_mesa_check_end_texture_render(struct gl_context *ctx, struct
>> gl_framebuffer *fb);
>> +
>> extern GLboolean GLAPIENTRY
>> _mesa_IsRenderbufferEXT(GLuint renderbuffer);
>>
>> 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..c96c97c 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") &&
>> !st->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_context.h
>> b/src/mesa/state_tracker/st_context.h
>> index 0a32202..8a8e11a 100644
>> --- a/src/mesa/state_tracker/st_context.h
>> +++ b/src/mesa/state_tracker/st_context.h
>> @@ -207,6 +207,16 @@ struct st_context
>>
>> int32_t draw_stamp;
>> int32_t read_stamp;
>> +
>> + /* data related to hw accelerated GL_SELECT */
>> + struct gl_selection_emul
>> + {
>> + GLboolean hw_unsupported;
>> + struct gl_framebuffer *fbo;
>> + GLuint rb_depth_name;
>> + GLuint rb_color_name;
>> + void *fs;
>> + } select_emul;
>> };
>>
>>
>> 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..d6bb244
>> --- /dev/null
>> +++ b/src/mesa/state_tracker/st_draw_select_emul.c
>> @@ -0,0 +1,490 @@
>>
>> +/**************************************************************************
>> + *
>> + * Copyright 2011 Micael Dias <kam1kaz3 (at) gmail (dot) com>,
>> + * Pierre-Eric Pelloux-Prayer
>> + * 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.
>> + *
>> + * How this algorithm works:
>> + * - When in GL_SELECT mode, draw calls are redirected to
>> st_select_draw_func()
>> + * which configures states in a way that makes the rendered primitives
>> draw
>> + * to a custom FBO that stores depth values (both min and max values) and
>> + * emits these values through _mesa_update_hitflag().
>> + */
>> +
>> +#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 "pipe/p_shader_tokens.h"
>> +#include "util/u_inlines.h"
>> +#include "util/u_simple_shaders.h"
>> +#include "cso_cache/cso_context.h"
>> +#include "tgsi/tgsi_ureg.h"
>> +
>> +#include "draw/draw_private.h"
>> +#include "draw/draw_context.h"
>> +
>> +/**
>> + * Custom fragment shader that does nothing but ouput a constant color
>> + */
>> +static void*
>> +st_select_emul_create_fs(struct gl_context *ctx)
>> +{
>> + struct st_context *st = st_context(ctx);
>> + struct pipe_context *pipe = st->pipe;
>> + struct ureg_program *ureg;
>> + struct ureg_dst out;
>> + struct ureg_src imm;
>> +
>> + ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
>> + if (ureg == NULL)
>> + return NULL;
>> +
>> + out = ureg_DECL_output( ureg,
>> + TGSI_SEMANTIC_COLOR,
>> + 0 );
>> +
>> + imm = ureg_imm4f( ureg, 0.0f, 0.0f, 0.0f, 1.0f );
>> +
>> + ureg_MOV( ureg, out, imm );
>> + ureg_END( ureg );
>> +
>> + return ureg_create_shader_and_destroy( ureg, pipe );
>> +}
>> +
>> +/**
>> + * Clears the depth values of our FBO by setting the
>> + * 1st pixel to 1.0f and the 2nd to 0.0f
>> + */
>> +static void
>> +st_select_emul_clear_fbo(struct gl_context *ctx)
>> +{
>> + struct st_context *st = st_context(ctx);
>> + struct gl_scissor_attrib saved_scissor;
>> + struct gl_framebuffer *saved_fbo = NULL;
>> + GLfloat clearDepth;
>> +
>> + /* save states */
>> + 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) {
>> + /* XXX: needs flushing? */
>> + _mesa_check_end_texture_render(ctx, saved_fbo);
>> + }
>> +
>> + /* use our fbo */
>> + _mesa_check_begin_texture_render(ctx, st->select_emul.fbo);
>> + _mesa_reference_framebuffer(&ctx->DrawBuffer, st->select_emul.fbo);
>> +
>> + /* update fbo */
>> + _mesa_update_framebuffer(ctx);
>> +
>> + /* make sure context is up to date */
>> + _mesa_update_state(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);
>> +
>> + /* restore states */
>> + _mesa_check_end_texture_render(ctx, st->select_emul.fbo);
>> + if (saved_fbo) {
>> + _mesa_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->Scissor = saved_scissor;
>> + ctx->NewState |= _NEW_SCISSOR | _NEW_DEPTH | _NEW_BUFFERS;
>> + _mesa_update_state(ctx);
>> +}
>> +
>> +/**
>> + * Clean up data
>> + */
>> +static void
>> +st_select_emul_destroy_fbo(struct gl_context *ctx)
>> +{
>> + struct st_context *st = st_context(ctx);
>> + if (st->select_emul.rb_color_name) {
>> + _mesa_DeleteRenderbuffersEXT(1, &st->select_emul.rb_color_name);
>> + st->select_emul.rb_color_name = 0;
>> + }
>> + if (st->select_emul.rb_depth_name) {
>> + _mesa_DeleteRenderbuffersEXT(1, &st->select_emul.rb_depth_name);
>> + st->select_emul.rb_depth_name = 0;
>> + }
>> + if (st->select_emul.fbo) {
>> + _mesa_DeleteFramebuffersEXT(1, &st->select_emul.fbo->Name);
>> + _mesa_reference_framebuffer(&st->select_emul.fbo, NULL);
>> + }
>> + if (st->select_emul.fs) {
>> + cso_delete_fragment_shader(st->cso_context, st->select_emul.fs);
>> + st->select_emul.fs = NULL;
>> + }
>> +}
>> +
>> +/**
>> + * Create and setup FBO needed for our operations
>> + */
>> +static bool
>> +st_select_emul_create_fbo(struct gl_context *ctx)
>> +{
>> + GLuint fboName;
>> + struct st_context *st = st_context(ctx);
>> +
>> + /* make sure we don't leak memory */
>> + st_select_emul_destroy_fbo(ctx);
>> +
>> + /* create buffer names */
>> + _mesa_GenFramebuffersEXT(1, &fboName);
>> + _mesa_GenRenderbuffersEXT(1, &st->select_emul.rb_depth_name);
>> + _mesa_GenRenderbuffersEXT(1, &st->select_emul.rb_color_name);
>> +
>> + /* allocate buffers' memory */
>> + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, fboName);
>> + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER,
>> st->select_emul.rb_depth_name);
>> + _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 2,
>> 1);
>> + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER,
>> st->select_emul.rb_color_name);
>> + _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, 2, 1);
>> + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, 0);
>> +
>> + /* setup fbo */
>> + _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
>> + GL_RENDERBUFFER,
>> + st->select_emul.rb_depth_name);
>> + _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
>> + GL_RENDERBUFFER,
>> + st->select_emul.rb_color_name);
>> +
>> + if (_mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER) !=
>> GL_FRAMEBUFFER_COMPLETE) {
>> + st_select_emul_destroy_fbo(ctx);
>> + return false;
>> + }
>> +
>> + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, 0);
>> +
>> + /* get fbo pointer */
>> + st->select_emul.fbo = _mesa_lookup_framebuffer(ctx, fboName);
>> +
>> + /* create fragment shader */
>> + st->select_emul.fs = st_select_emul_create_fs(ctx);
>> +
>> + /* check fbo pointer validity */
>> + if (!st->select_emul.fbo) {
>> + st_select_emul_destroy_fbo(ctx);
>> + return false;
>> + }
>> +
>> + return true;
>> +}
>> +
>> +/**
>> + * 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)
>> +{
>> + struct st_context *st = st_context(ctx);
>> +
>> + /* perform an hw caps check once */
>> + static bool hw_checked = false;
>> + if (!hw_checked) {
>> + hw_checked = true;
>> + /* XXX: is this a proper way to check for hw support? */
>> + if (!ctx->Driver.ReadPixels ||
>> + !ctx->Driver.DrawPixels ||
>> + !ctx->Driver.NewFramebuffer ||
>> + !ctx->Driver.NewRenderbuffer) {
>> + st->select_emul.hw_unsupported = true;
>> + return false;
>> + }
>> + }
>> +
>> + /* initialize fbo if not yet initialized */
>> + if (!st->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);
>> +}
>> +
>> +/**
>> + * Reads into our FBO and emit z-buffer results
>> + * called by st_select_draw_func()
>> + */
>> +static void
>> +st_select_emul_update_hits(struct gl_context *ctx)
>> +{
>> + struct st_context *st = st_context(ctx);
>> + struct gl_framebuffer *saved_fbo = NULL;
>> + float zData[2];
>> +
>> + /* set state */
>> + if (ctx->ReadBuffer) {
>> + _mesa_reference_framebuffer(&saved_fbo, ctx->ReadBuffer);
>> + _mesa_check_end_texture_render(ctx, saved_fbo);
>> + }
>> + _mesa_check_begin_texture_render(ctx, st->select_emul.fbo);
>> + _mesa_reference_framebuffer(&ctx->ReadBuffer, st->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 */
>> + _mesa_check_end_texture_render(ctx, st->select_emul.fbo);
>> + if (saved_fbo) {
>> + _mesa_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 );
>> +}
>> +
>> +/**
>> + * 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)
>> +{
>> + GLboolean saved_scissorEnabled;
>> + struct gl_framebuffer *saved_fbo = NULL;
>> + struct st_context *st = st_context(ctx);
>> + struct pipe_depth_stencil_alpha_state state_depth;
>> + struct pipe_viewport_state state_viewport;
>> +
>> + /* save states */
>> + if (ctx->DrawBuffer)
>> + _mesa_reference_framebuffer(&saved_fbo, ctx->DrawBuffer);
>> +
>> + saved_scissorEnabled = ctx->Scissor.Enabled;
>> + cso_save_fragment_shader(st->cso_context);
>> + cso_save_depth_stencil_alpha(st->cso_context);
>> + cso_save_viewport(st->cso_context);
>> +
>> + /* prepare stencil state */
>> + memset(&state_depth, 0, sizeof(state_depth));
>> + state_depth.depth.enabled = 1;
>> + state_depth.depth.writemask = 1;
>> +
>> + /* prepare viewport state */
>> + memset(&state_viewport, 0, sizeof(state_viewport));
>> + state_viewport.scale[0] = 0.5f * 2.0f * 0.5;
>> + state_viewport.scale[1] = 0.5f * 1.0f;
>> + state_viewport.scale[2] = 1.0f;
>> + state_viewport.scale[3] = 1.0f;
>> + state_viewport.translate[1] = 0.5f * 1.0f;
>> + state_viewport.translate[2] = 0.0f;
>> + state_viewport.translate[3] = 0.0f;
>> +
>> + /* use our custom fragment shader */
>> + cso_set_fragment_shader_handle(st->cso_context, st->select_emul.fs);
>> +
>> + /* disable scissor */
>> + ctx->Scissor.Enabled = GL_FALSE;
>> +
>> + /* disable old draw fbo */
>> + if (saved_fbo)
>> + _mesa_check_end_texture_render(ctx, saved_fbo);
>> +
>> + /* use our fbo */
>> + _mesa_check_begin_texture_render(ctx, st->select_emul.fbo);
>> + _mesa_reference_framebuffer(&ctx->DrawBuffer, st->select_emul.fbo);
>> +
>> + /* update fbo */
>> + _mesa_update_framebuffer( ctx );
>> +
>> + /* update context */
>> + _mesa_update_state(ctx);
>> +
>> + /* render min-z */
>> + {
>> + /* specific states */
>> + state_depth.depth.func = PIPE_FUNC_LESS;
>> + state_viewport.translate[0] = 0.5f * 1.0f + 0.0f;
>> +
>> + cso_set_depth_stencil_alpha(st->cso_context, &state_depth);
>> + cso_set_viewport(st->cso_context, &state_viewport);
>> +
>> + /* draw */
>> + st_draw_vbo(ctx, arrays, prims, nr_prims, ib, index_bounds_valid,
>> min_index, max_index);
>> + }
>> +
>> + /* render max-z */
>> + {
>> + state_depth.depth.func = PIPE_FUNC_GREATER;
>> + state_viewport.translate[0] = 0.5f * 1.0f + 1.0f;
>> +
>> + cso_set_depth_stencil_alpha(st->cso_context, &state_depth);
>> + cso_set_viewport(st->cso_context, &state_viewport);
>> +
>> + /* draw */
>> + st_draw_vbo(ctx, arrays, prims, nr_prims, ib, index_bounds_valid,
>> min_index, max_index);
>> + }
>> +
>> + /* XXX: needs flushing? */
>> +
>> + /* restore states */
>> + cso_restore_fragment_shader(st->cso_context);
>> + cso_restore_depth_stencil_alpha(st->cso_context);
>> + cso_restore_viewport(st->cso_context);
>> + ctx->Scissor.Enabled = saved_scissorEnabled;
>> + _mesa_check_end_texture_render(ctx, st->select_emul.fbo);
>> + if (saved_fbo) {
>> + _mesa_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_update_state(ctx);
>> +
>> + /* update hits */
>> + st_select_emul_update_hits(ctx);
>> +}
>> +
>> --
>> 1.7.6
>>
>
>
>
> --
> Micael Dias
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
>
More information about the mesa-dev
mailing list