From 81138766700ecaee2fc0ccced77eb8fad1a97f0f Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Sun, 3 Jul 2011 15:02:30 +0200 Subject: [PATCH] gallium: GL_SELECT hw support v3 --- src/mesa/main/feedback.c | 259 +++++++++++++++++++++++++++---- src/mesa/main/mtypes.h | 17 ++- src/mesa/main/queryobj.c | 8 +- src/mesa/state_tracker/st_cb_feedback.c | 109 ++++++++++++- 4 files changed, 353 insertions(+), 40 deletions(-) diff --git a/src/mesa/main/feedback.c b/src/mesa/main/feedback.c index fcb089f..68e4e79 100644 --- a/src/mesa/main/feedback.c +++ b/src/mesa/main/feedback.c @@ -48,7 +48,82 @@ #define FB_COLOR 0x04 #define FB_TEXTURE 0X08 +void _mesa_select_before_object(struct gl_context* ctx, int batchEntry) { + assert(ctx->ReadBuffer->Name == ctx->Select._OffscreenSurface); + assert(ctx->DrawBuffer->Name == ctx->Select._OffscreenSurface); + /* change viewport */ + _mesa_Viewport( + ctx->Select._OffscreenSurfaceWidth * batchEntry, 0, + ctx->Select._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + + /* begin query */ + _mesa_BeginQueryARB(GL_SAMPLES_PASSED, ctx->Select._Queries[batchEntry]); +} + + +void _mesa_select_after_object(struct gl_context* ctx) { + assert(ctx->ReadBuffer->Name == ctx->Select._OffscreenSurface); + assert(ctx->DrawBuffer->Name == ctx->Select._OffscreenSurface); + + /* end query */ + _mesa_EndQueryARB(GL_SAMPLES_PASSED); +} + +static GLuint +_mesa_init_select_fbo(struct gl_context* ctx) { + GLuint result; + GLuint rbs[2]; + + _mesa_GenFramebuffersEXT(1, &result); + _mesa_GenRenderbuffersEXT(2, rbs); + + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, result); + + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, rbs[0]); + + _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, + ctx->Select.BatchSize * ctx->Select._OffscreenSurfaceWidth, + ctx->Select._OffscreenSurfaceHeight * 2); + + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, rbs[1]); + _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, + ctx->Select.BatchSize * ctx->Select._OffscreenSurfaceWidth, + ctx->Select._OffscreenSurfaceHeight * 2); + + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, 0); + + _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbs[0]); + _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[1]); + + assert(_mesa_CheckFramebufferStatusEXT(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, 0); + + return result; +} + +static GLuint* +_mesa_init_select_queries(struct gl_context* ctx) { + assert(ctx->Select.BatchSize > 0); + + GLuint* result = (GLuint*) malloc(ctx->Select.BatchSize * sizeof(GLuint)); + _mesa_GenQueriesARB(ctx->Select.BatchSize, result); + return result; +} + +void +_mesa_init_select_emulation(struct gl_context* ctx) +{ + + if (ctx->Select._OffscreenSurface == 0) { + ctx->Select._OffscreenSurfaceWidth = ctx->Select._OffscreenSurfaceHeight = 1; + ctx->Select._OffscreenSurface = _mesa_init_select_fbo(ctx); + } + + if (ctx->Select._Queries == 0) + ctx->Select._Queries = _mesa_init_select_queries(ctx); +} static void GLAPIENTRY _mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer ) @@ -177,9 +252,11 @@ _mesa_SelectBuffer( GLsizei size, GLuint *buffer ) ctx->Select.Buffer = buffer; ctx->Select.BufferSize = size; ctx->Select.BufferCount = 0; +/* ctx->Select.HitFlag = GL_FALSE; ctx->Select.HitMinZ = 1.0; ctx->Select.HitMaxZ = 0.0; +*/ } @@ -214,6 +291,7 @@ write_record(struct gl_context *ctx, GLuint value) void _mesa_update_hitflag(struct gl_context *ctx, GLfloat z) { +/* ctx->Select.HitFlag = GL_TRUE; if (z < ctx->Select.HitMinZ) { ctx->Select.HitMinZ = z; @@ -221,6 +299,7 @@ _mesa_update_hitflag(struct gl_context *ctx, GLfloat z) if (z > ctx->Select.HitMaxZ) { ctx->Select.HitMaxZ = z; } +*/ } @@ -236,7 +315,7 @@ _mesa_update_hitflag(struct gl_context *ctx, GLfloat z) * \sa gl_selection. */ static void -write_hit_record(struct gl_context *ctx) +write_hit_record(struct gl_context *ctx, GLfloat hitMinZ, GLfloat hitMaxZ, GLuint nameStackDepth, GLuint* nameStack) { GLuint i; GLuint zmin, zmax, zscale = (~0u); @@ -245,22 +324,110 @@ write_hit_record(struct gl_context *ctx) /* 2^32-1 and round to nearest unsigned integer. */ assert( ctx != NULL ); /* this line magically fixes a SunOS 5.x/gcc bug */ - zmin = (GLuint) ((GLfloat) zscale * ctx->Select.HitMinZ); - zmax = (GLuint) ((GLfloat) zscale * ctx->Select.HitMaxZ); + zmin = (GLuint) ((GLfloat) zscale * hitMinZ); + zmax = (GLuint) ((GLfloat) zscale * hitMaxZ); - write_record( ctx, ctx->Select.NameStackDepth ); + write_record( ctx, nameStackDepth ); write_record( ctx, zmin ); write_record( ctx, zmax ); - for (i = 0; i < ctx->Select.NameStackDepth; i++) { - write_record( ctx, ctx->Select.NameStack[i] ); + for (i = 0; i < nameStackDepth; i++) { + write_record( ctx, nameStack[i] ); } ctx->Select.Hits++; - ctx->Select.HitFlag = GL_FALSE; - ctx->Select.HitMinZ = 1.0; - ctx->Select.HitMaxZ = -1.0; } +void _mesa_select_clear_fbo(struct gl_context *ctx) +{ + assert(ctx->ReadBuffer->Name == ctx->Select._OffscreenSurface); + assert(ctx->DrawBuffer->Name == ctx->Select._OffscreenSurface); + + /* hack needed because Clear does nothing if render mode != GL_RENDER */ + ctx->RenderMode = GL_RENDER; + + _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_TRUE); + + /* clear upper part which holds minZ */ + _mesa_Scissor(0, 0, + ctx->Select.BatchSize * ctx->Select._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + _mesa_ClearDepth(1.0f); + _mesa_Clear(GL_DEPTH_BUFFER_BIT); + + /* clear upper part which holds maxZ */ + _mesa_Scissor( + 0, ctx->Select._OffscreenSurfaceHeight, + ctx->Select.BatchSize * ctx->Select._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + _mesa_ClearDepth(0.0f); + _mesa_Clear(GL_DEPTH_BUFFER_BIT); + + _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE); + ctx->RenderMode = GL_SELECT; +} + + +static void +_mesa_exec_select_batch(struct gl_context *ctx) +{ + if (!ctx->Select.BatchEntryCount) + return; + + /* read back fbo */ + const GLuint fboW = ctx->Select._OffscreenSurfaceWidth * ctx->Select.BatchEntryCount; + const GLuint fboH = ctx->Select._OffscreenSurfaceHeight * 2; + float buffer[fboW * fboH]; + _mesa_ReadPixels(0, 0, + fboW, fboH, + GL_DEPTH_COMPONENT, GL_FLOAT, buffer); + + /* process each entry */ + for(int i=0; iSelect.BatchEntryCount; i++) { + /* gather query result */ + GLint queryResult; + _mesa_GetQueryObjectivARB(ctx->Select._Queries[i], GL_QUERY_RESULT_ARB, &queryResult); + if (queryResult) { + fprintf(stderr, "query_result[%d]: %d\n", i, queryResult); + int count = 0; + int xOffset = ctx->Select._OffscreenSurfaceWidth * i; + float minZ = 1, maxZ = -1; + + for(int y=0; ySelect._OffscreenSurfaceHeight /*&& count < queryResult*/; y++) { + for(int x=0; xSelect._OffscreenSurfaceWidth /*&& count < queryResult*/; x++) { + { + float z = buffer[y * fboW + xOffset + x]; + // fprintf(stderr, " %.1f", z); + if (z < 1.0) { + if (z < minZ) + minZ = z; + ++count; + } + } + { + float z = buffer[(y + ctx->Select._OffscreenSurfaceHeight) * fboW + xOffset + x]; + // fprintf(stderr, " %.3f", z); + if (z > 0.0) { + if (z > maxZ) + maxZ = z; + ++count; + } + } + } + //fprintf(stderr, "\n"); + } + if (count) { + fprintf(stderr, "count[%d]: %d\n", i, count); + write_hit_record(ctx, minZ, maxZ, + ctx->Select.SelectBatch[i].NameStackDepth, + ctx->Select.SelectBatch[i].NameStack); + } + } + } + + /* clear FBO */ + _mesa_select_clear_fbo(ctx); + + /* reset entry count */ + ctx->Select.BatchEntryCount = 0; +} /** * Initialize the name stack. @@ -275,16 +442,17 @@ _mesa_InitNames( void ) GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - /* Record the hit before the HitFlag is wiped out again. */ if (ctx->RenderMode == GL_SELECT) { - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } + _mesa_exec_select_batch(ctx); } + ctx->Select.NameStackDepth = 0; +/* ctx->Select.HitFlag = GL_FALSE; ctx->Select.HitMinZ = 1.0; ctx->Select.HitMaxZ = 0.0; +*/ + ctx->Select.BatchEntryCount = 0; ctx->NewState |= _NEW_RENDERMODE; } @@ -314,17 +482,27 @@ _mesa_LoadName( GLuint name ) return; } - FLUSH_VERTICES(ctx, _NEW_RENDERMODE); + _mesa_select_after_object(ctx); + + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); // ?? + + if (ctx->Select.BatchEntryCount >= ctx->Select.BatchSize) { + _mesa_exec_select_batch(ctx); + assert(ctx->Select.BatchEntryCount == 0); + } - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } if (ctx->Select.NameStackDepth < MAX_NAME_STACK_DEPTH) { ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name; } else { ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name; } + + /* reserve entry in batch */ + ctx->Select.SelectBatch[ctx->Select.BatchEntryCount].NameStackDepth = ctx->Select.NameStackDepth; + memcpy(ctx->Select.SelectBatch[ctx->Select.BatchEntryCount].NameStack, ctx->Select.NameStack, sizeof(ctx->Select.NameStack)); + _mesa_select_before_object(ctx, ctx->Select.BatchEntryCount); + ctx->Select.BatchEntryCount++; } @@ -349,17 +527,32 @@ _mesa_PushName( GLuint name ) return; } + if (ctx->Select.NameStackDepth > 0) + _mesa_select_after_object(ctx); + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } + if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) { _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" ); } - else + else { ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name; + + /* reserve entry in batch */ + if (ctx->Select.BatchEntryCount >= ctx->Select.BatchSize) { + _mesa_exec_select_batch(ctx); + assert(ctx->Select.BatchEntryCount == 0); + } + ctx->Select.SelectBatch[ctx->Select.BatchEntryCount].NameStackDepth = ctx->Select.NameStackDepth; + memcpy(ctx->Select.SelectBatch[ctx->Select.BatchEntryCount].NameStack, ctx->Select.NameStack, sizeof(ctx->Select.NameStack)); + _mesa_select_before_object(ctx, ctx->Select.BatchEntryCount); + ctx->Select.BatchEntryCount++; + } } +struct SelectBufferEntry { + GLuint NameStack[MAX_NAME_STACK_DEPTH]; +}; /** * Pop a name into the name stack. @@ -380,10 +573,10 @@ _mesa_PopName( void ) return; } + _mesa_select_after_object(ctx); + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } + if (ctx->Select.NameStackDepth == 0) { _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" ); } @@ -430,9 +623,8 @@ _mesa_RenderMode( GLenum mode ) result = 0; break; case GL_SELECT: - if (ctx->Select.HitFlag) { - write_hit_record( ctx ); - } + _mesa_exec_select_batch(ctx); + if (ctx->Select.BufferCount > ctx->Select.BufferSize) { /* overflow */ #ifdef DEBUG @@ -446,6 +638,9 @@ _mesa_RenderMode( GLenum mode ) ctx->Select.BufferCount = 0; ctx->Select.Hits = 0; ctx->Select.NameStackDepth = 0; + ctx->Select.BatchEntryCount = 0; + + _mesa_init_select_emulation(ctx); break; #if _HAVE_FULL_GL case GL_FEEDBACK: @@ -537,6 +732,16 @@ void _mesa_init_feedback( struct gl_context * ctx ) /* Miscellaneous */ ctx->RenderMode = GL_RENDER; + + /* */ + ctx->Select._OffscreenSurface = 0; + ctx->Select._WriteDepthFS = 0; + ctx->Select._Queries = 0; + + ctx->Select.BatchSize = 16; + ctx->Select.BatchEntryCount = 0; + ctx->Select.SelectBatch = + (struct Entry*) malloc(sizeof(struct Entry) * ctx->Select.BatchSize); } /*@}*/ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index f018c75..1165679 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1718,9 +1718,20 @@ struct gl_selection GLuint Hits; /**< number of records in the selection buffer */ GLuint NameStackDepth; /**< name stack depth */ GLuint NameStack[MAX_NAME_STACK_DEPTH]; /**< name stack */ - GLboolean HitFlag; /**< hit flag */ - GLfloat HitMinZ; /**< minimum hit depth */ - GLfloat HitMaxZ; /**< maximum hit depth */ + // GLboolean HitFlag; /**< hit flag */ + // GLfloat HitMinZ; /**< minimum hit depth */ + // GLfloat HitMaxZ; /**< maximum hit depth */ + + GLuint _OffscreenSurface; /** off-screen rendering surface */ + GLuint _OffscreenSurfaceWidth, _OffscreenSurfaceHeight; /** off-screen rendering surface */ + GLuint _WriteDepthFS; /** GL_SELECT special fragment shader */ + GLuint* _Queries; /** glQuery */ + + struct Entry { + GLuint NameStackDepth; /**< name stack depth */ + GLuint NameStack[MAX_NAME_STACK_DEPTH]; /**< name stack */ + }* SelectBatch; + GLint BatchSize, BatchEntryCount; }; diff --git a/src/mesa/main/queryobj.c b/src/mesa/main/queryobj.c index f0a9a79..9e9c817 100644 --- a/src/mesa/main/queryobj.c +++ b/src/mesa/main/queryobj.c @@ -173,7 +173,7 @@ get_query_binding_point(struct gl_context *ctx, GLenum target) } -static void GLAPIENTRY +void GLAPIENTRY _mesa_GenQueriesARB(GLsizei n, GLuint *ids) { GLuint first; @@ -264,7 +264,7 @@ _mesa_IsQueryARB(GLuint id) } -static void GLAPIENTRY +void GLAPIENTRY _mesa_BeginQueryARB(GLenum target, GLuint id) { struct gl_query_object *q, **bindpt; @@ -319,7 +319,7 @@ _mesa_BeginQueryARB(GLenum target, GLuint id) } -static void GLAPIENTRY +void GLAPIENTRY _mesa_EndQueryARB(GLenum target) { struct gl_query_object *q, **bindpt; @@ -386,7 +386,7 @@ _mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params) } -static void GLAPIENTRY +void GLAPIENTRY _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params) { struct gl_query_object *q = NULL; diff --git a/src/mesa/state_tracker/st_cb_feedback.c b/src/mesa/state_tracker/st_cb_feedback.c index 9b85a39..b10f8b7 100644 --- a/src/mesa/state_tracker/st_cb_feedback.c +++ b/src/mesa/state_tracker/st_cb_feedback.c @@ -270,6 +270,102 @@ draw_glselect_stage(struct gl_context *ctx, struct draw_context *draw) return &fs->stage; } +/* move to appropriate place (gl_context ?) */ +bool stateSaved = false; +GLuint fboSave = 0; +GLuint depthSave; +struct gl_viewport_attrib vpSave; +struct gl_scissor_attrib scissorSave; +GLenum depthFuncSave; +GLclampd depthClearSave; + +static void +init_select_mode(struct gl_context *ctx) +{ + /* save states */ + fboSave = ctx->DrawBuffer->Name; + memcpy(&vpSave, &ctx->Viewport, sizeof(struct gl_viewport_attrib)); + memcpy(&scissorSave, &ctx->Scissor, sizeof(struct gl_scissor_attrib)); + + depthSave = ctx->Depth.Test; + + /* change render target */ + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, ctx->Select._OffscreenSurface); + + depthClearSave = ctx->Depth.Clear; + depthFuncSave = ctx->Depth.Func; + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); + _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE); + + //_mesa_update_state(ctx); + stateSaved = true; + + _mesa_select_clear_fbo(ctx); +} + +static void +exit_select_mode(struct gl_context *ctx) +{ + if (stateSaved) { + /* restore states */ + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, fboSave); + _mesa_Viewport(vpSave.X, vpSave.Y, vpSave.Width, vpSave.Height); + _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissorSave.Enabled); + _mesa_Scissor(scissorSave.X, scissorSave.Y, scissorSave.Width, scissorSave.Height); + _mesa_set_enable(ctx, GL_DEPTH_TEST, depthSave); + _mesa_DepthFunc(depthFuncSave); + _mesa_ClearDepth(depthClearSave); + } + stateSaved = false; + _mesa_update_state(ctx); +} + +static void +select_change_depth_func(struct gl_context *ctx, GLenum func) { + if (ctx->Depth.Func == func) + return; + + ctx->NewState |= _NEW_DEPTH; + ctx->Depth.Func = func; + + if (ctx->Driver.DepthFunc) + ctx->Driver.DepthFunc( ctx, func ); +} + +static void +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) + { + /* called once par object */ + assert(ctx->ReadBuffer->Name == ctx->Select._OffscreenSurface); + assert(ctx->DrawBuffer->Name == ctx->Select._OffscreenSurface); + + /* draw object for minZ*/ + assert(ctx->Select.BatchEntryCount > 0); + int batchEntry = ctx->Select.BatchEntryCount - 1; + _mesa_set_viewport(ctx, + ctx->Select._OffscreenSurfaceWidth * batchEntry, 0, + ctx->Select._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + select_change_depth_func(ctx, GL_LESS);//_mesa_DepthFunc(GL_LESS); + _mesa_update_state(ctx); + + st_draw_vbo(ctx, arrays, prims, nr_prims, ib, index_bounds_valid, min_index, max_index); + + /* draw object for maxZ */ + _mesa_set_viewport(ctx, + ctx->Select._OffscreenSurfaceWidth * batchEntry, ctx->Select._OffscreenSurfaceHeight, + ctx->Select._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + select_change_depth_func(ctx, GL_GREATER);//_mesa_DepthFunc(GL_GREATER); + _mesa_update_state(ctx); + + st_draw_vbo(ctx, arrays, prims, nr_prims, ib, index_bounds_valid, min_index, max_index); + } static void st_RenderMode(struct gl_context *ctx, GLenum newMode ) @@ -278,15 +374,17 @@ st_RenderMode(struct gl_context *ctx, GLenum newMode ) struct draw_context *draw = st->draw; if (newMode == GL_RENDER) { + exit_select_mode(ctx); + /* 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); + _mesa_init_select_emulation(ctx); + init_select_mode(ctx); + + /* use normal VBO draw function */ + vbo_set_draw_func(ctx, select_draw_func); } else { if (!st->feedback_stage) @@ -300,7 +398,6 @@ st_RenderMode(struct gl_context *ctx, GLenum newMode ) } - void st_init_feedback_functions(struct dd_function_table *functions) { functions->RenderMode = st_RenderMode; -- 1.7.5.4