From a2f6e4c8790fd6a5cc1f4b1a97582bc5fc7184d7 Mon Sep 17 00:00:00 2001 From: Pierre-Eric Pelloux-Prayer Date: Thu, 30 Jun 2011 16:32:10 +0200 Subject: [PATCH] Experimental-hacky GL_SELECT hw support for gallium drivers --- src/mesa/main/feedback.c | 163 ++++++++++++++++++++++++++++++- src/mesa/main/mtypes.h | 5 + src/mesa/main/queryobj.c | 8 +- src/mesa/state_tracker/st_cb_feedback.c | 98 ++++++++++++++++++ 4 files changed, 269 insertions(+), 5 deletions(-) diff --git a/src/mesa/main/feedback.c b/src/mesa/main/feedback.c index fcb089f..0d9e9b8 100644 --- a/src/mesa/main/feedback.c +++ b/src/mesa/main/feedback.c @@ -48,7 +48,151 @@ #define FB_COLOR 0x04 #define FB_TEXTURE 0X08 +void _mesa_select_name_param(struct gl_context* ctx) { + if (ctx->Select.NameStackDepth > 0) { + unsigned int n = ctx->Select.NameStack[ctx->Select.NameStackDepth-1]; + if (n != (~0u)) { + unsigned char name[4]; + memcpy(name, &n, sizeof(int)); + // printf("IN => %u %u %u %u\n", name[0], name[1], name[2], name[3]); + assert(name[3] == 0); + _mesa_ProgramLocalParameter4dARB(GL_FRAGMENT_PROGRAM_ARB, 0, name[0]/ 255.0f, name[1]/ 255.0f, name[2]/ 255.0f, name[3]/ 255.0f); + return; + } + } + _mesa_ProgramLocalParameter4dARB(GL_FRAGMENT_PROGRAM_ARB, 0, -1, 0, 0, 0); +} + +void _mesa_select_before_object(struct gl_context* ctx) { + assert(ctx->ReadBuffer->Name == ctx->Select._OffscreenSurface); + assert(ctx->DrawBuffer->Name == ctx->Select._OffscreenSurface); + + _mesa_select_name_param(ctx); + _mesa_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* begin query */ + _mesa_BeginQueryARB(GL_SAMPLES_PASSED, ctx->Select._Query); +} + + +void _mesa_select_after_object(struct gl_context* ctx) { + /* end query */ + _mesa_EndQueryARB(GL_SAMPLES_PASSED); + + assert(ctx->ReadBuffer->Name == ctx->Select._OffscreenSurface); + assert(ctx->DrawBuffer->Name == ctx->Select._OffscreenSurface); + + if (1 && ctx->Select._Query > 0) { + GLint queryResult; + _mesa_GetQueryObjectivARB(ctx->Select._Query, GL_QUERY_RESULT_ARB, &queryResult); + if (1 || queryResult) { + if (queryResult) + fprintf(stderr, "Query result: %d\n", queryResult); + + if (queryResult) { + const unsigned int w = ctx->Select._OffscreenSurfaceWidth, h = ctx->Select._OffscreenSurfaceHeight; + // read result + unsigned char buffer[w*h*4]; + _mesa_ReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + // print 1st pixel + int count = 0; + for(int i=0; iSelect.NameStack[ctx->Select.NameStackDepth-1]) { + _mesa_update_hitflag(ctx, z / 255.0f); + ++count; + } + } + if (count) { + fprintf(stderr, "name=%d count=%d\n", ctx->Select.NameStack[ctx->Select.NameStackDepth-1], count); + } + } + } + } +} + + +static GLuint +_mesa_init_select_fs(struct gl_context* ctx) { + static const char *program = + "!!ARBfp1.0\n" + "MOV result.color.xyzw, program.local[0];\n" //program.local[0];\n" + "MOV result.color.w, fragment.position;\n" + // "MOV result.color.x, 0.5;\n" + // "MOV result.color.z, 1.0;\n" + // "MOV result.color.w, 1.0;\n" + // "MOV result.color, 1;\n" + "END \n"; + GLuint result; + + int fpEnabled = ctx->FragmentProgram.Enabled; + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + _mesa_GenPrograms(1, &result); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, result); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program), (const GLubyte *) program); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, 0); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, fpEnabled); + return result; +} + +static GLuint +_mesa_init_select_fbo(struct gl_context* ctx) { +//return 0; + 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._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + + _mesa_BindRenderbufferEXT(GL_RENDERBUFFER, rbs[1]); + _mesa_RenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA, ctx->Select._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + + _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_query(struct gl_context* ctx) { + GLuint result; + _mesa_GenQueriesARB(1, &result); + return result; +} + +void +_mesa_init_select_emulation(struct gl_context* ctx) +{ + + if (ctx->Select._OffscreenSurface == 0) { + ctx->Select._OffscreenSurfaceWidth = ctx->Select._OffscreenSurfaceHeight = 8; + ctx->Select._OffscreenSurface = _mesa_init_select_fbo(ctx); + } + if (ctx->Select._WriteDepthFS == 0) + ctx->Select._WriteDepthFS = _mesa_init_select_fs(ctx); + if (ctx->Select._Query == 0) + ctx->Select._Query = _mesa_init_select_query(ctx); +} static void GLAPIENTRY _mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer ) @@ -314,6 +458,8 @@ _mesa_LoadName( GLuint name ) return; } + _mesa_select_after_object(ctx); + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); if (ctx->Select.HitFlag) { @@ -325,6 +471,8 @@ _mesa_LoadName( GLuint name ) else { ctx->Select.NameStack[MAX_NAME_STACK_DEPTH-1] = name; } + + _mesa_select_before_object(ctx); } @@ -348,7 +496,9 @@ _mesa_PushName( GLuint name ) if (ctx->RenderMode != GL_SELECT) { return; } - + + if (ctx->Select.NameStackDepth > 0) + _mesa_select_after_object(ctx); FLUSH_VERTICES(ctx, _NEW_RENDERMODE); if (ctx->Select.HitFlag) { write_hit_record( ctx ); @@ -358,6 +508,8 @@ _mesa_PushName( GLuint name ) } else ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name; + + _mesa_select_before_object(ctx); } @@ -380,6 +532,8 @@ _mesa_PopName( void ) return; } + _mesa_select_after_object(ctx); + FLUSH_VERTICES(ctx, _NEW_RENDERMODE); if (ctx->Select.HitFlag) { write_hit_record( ctx ); @@ -446,6 +600,8 @@ _mesa_RenderMode( GLenum mode ) ctx->Select.BufferCount = 0; ctx->Select.Hits = 0; ctx->Select.NameStackDepth = 0; + + _mesa_init_select_emulation(ctx); break; #if _HAVE_FULL_GL case GL_FEEDBACK: @@ -537,6 +693,11 @@ void _mesa_init_feedback( struct gl_context * ctx ) /* Miscellaneous */ ctx->RenderMode = GL_RENDER; + + /* */ + ctx->Select._OffscreenSurface = 0; + ctx->Select._WriteDepthFS = 0; + ctx->Select._Query = 0; } /*@}*/ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index f018c75..262a550 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1721,6 +1721,11 @@ struct gl_selection 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 _Query; /** glQuery */ }; 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..0a4d74b 100644 --- a/src/mesa/state_tracker/st_cb_feedback.c +++ b/src/mesa/state_tracker/st_cb_feedback.c @@ -270,6 +270,95 @@ draw_glselect_stage(struct gl_context *ctx, struct draw_context *draw) return &fs->stage; } +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->FragmentProgram.Current->Base.Id == ctx->Select._WriteDepthFS); + assert(ctx->ReadBuffer->Name == ctx->Select._OffscreenSurface); + assert(ctx->DrawBuffer->Name == ctx->Select._OffscreenSurface); + + /* draw object */ + st_draw_vbo(ctx, arrays, prims, nr_prims, ib, index_bounds_valid, min_index, max_index); +} + + +bool stateSaved; +GLuint fboSave = 0; +GLuint fpSave = 0; +bool fpEnabled = false; +GLfloat projectionMatrix[16]; +GLuint projectionMode; +GLuint depthSave, scissorSave; +struct gl_viewport_attrib vpSave; + + +static void +init_select_mode(struct gl_context *ctx) +{ +// fprintf(stderr, "%s ->\n", __FUNCTION__); + /* save states */ + fboSave = ctx->DrawBuffer->Name; + fpSave = ctx->FragmentProgram.Current->Base.Id; + memcpy(&vpSave, &ctx->Viewport, sizeof(struct gl_viewport_attrib)); + memcpy(projectionMatrix, ctx->ProjectionMatrixStack.Top->m, 16 * sizeof(GLfloat)); + projectionMode = ctx->Transform.MatrixMode; + fpEnabled = ctx->FragmentProgram.Enabled; + depthSave = ctx->Depth.Test; + scissorSave = ctx->Scissor.Enabled; + + /* change render target */ + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, ctx->Select._OffscreenSurface); + + /* change viewport */ + _mesa_Viewport(0, 0, ctx->Select._OffscreenSurfaceWidth, ctx->Select._OffscreenSurfaceHeight); + // _mesa_MatrixMode(GL_PROJECTION); + // _mesa_LoadIdentity(); + + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + /* if not forced to false, Blender selection doesn't works reliably... */ + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); + _mesa_set_enable(ctx, GL_SCISSOR_TEST, GL_FALSE); + + /* change fragment program */ + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, ctx->Select._WriteDepthFS); + + _mesa_update_state(ctx); + + stateSaved = true; +// fprintf(stderr, "<- %s\n", __FUNCTION__); +} + +static void +exit_select_mode(struct gl_context *ctx) +{ +// fprintf(stderr, "%s ->\n", __FUNCTION__); + if (stateSaved) { + /* restore states */ + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, fpSave); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER, fboSave); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, fpEnabled); + _mesa_Viewport(vpSave.X, vpSave.Y, vpSave.Width, vpSave.Height); + _mesa_set_enable(ctx, GL_DEPTH_TEST, depthSave); + _mesa_set_enable(ctx, GL_SCISSOR_TEST, scissorSave); + // _mesa_MatrixMode(projectionMode); + // _mesa_LoadMatrixf(projectionMatrix); + } + stateSaved = false; + + _mesa_update_state(ctx); +// fprintf(stderr, "<- %s\n", __FUNCTION__); +} + + + static void st_RenderMode(struct gl_context *ctx, GLenum newMode ) @@ -277,16 +366,25 @@ st_RenderMode(struct gl_context *ctx, GLenum newMode ) struct st_context *st = st_context(ctx); 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 1 + _mesa_init_select_emulation(ctx); + init_select_mode(ctx); + vbo_set_draw_func(ctx, select_draw_func); + #else 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); + #endif } else { if (!st->feedback_stage) -- 1.7.5.4