diff options
-rw-r--r-- | src/mesa/drivers/dri/intel/intel_context.h | 10 | ||||
-rw-r--r-- | src/mesa/drivers/dri/intel/intel_pixel.c | 133 | ||||
-rw-r--r-- | src/mesa/drivers/dri/intel/intel_pixel.h | 8 | ||||
-rw-r--r-- | src/mesa/drivers/dri/intel/intel_pixel_bitmap.c | 199 |
4 files changed, 350 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/intel/intel_context.h b/src/mesa/drivers/dri/intel/intel_context.h index ac08117bb4c..4100677750c 100644 --- a/src/mesa/drivers/dri/intel/intel_context.h +++ b/src/mesa/drivers/dri/intel/intel_context.h @@ -157,6 +157,16 @@ struct intel_context void (*debug_batch)(struct intel_context *intel); } vtbl; + struct { + struct gl_fragment_program *bitmap_fp; + struct gl_vertex_program *passthrough_vp; + + struct gl_fragment_program *saved_fp; + GLboolean saved_fp_enable; + struct gl_vertex_program *saved_vp; + GLboolean saved_vp_enable; + } meta; + GLint refcount; GLuint Fallback; GLuint NewGLState; diff --git a/src/mesa/drivers/dri/intel/intel_pixel.c b/src/mesa/drivers/dri/intel/intel_pixel.c index 5702ad9bb57..91027d37e74 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel.c +++ b/src/mesa/drivers/dri/intel/intel_pixel.c @@ -27,7 +27,11 @@ #include "main/enums.h" #include "main/state.h" +#include "main/context.h" +#include "main/enable.h" #include "swrast/swrast.h" +#include "shader/arbprogram.h" +#include "shader/program.h" #include "intel_context.h" #include "intel_pixel.h" @@ -167,6 +171,125 @@ intel_check_blit_format(struct intel_region * region, return GL_FALSE; } +/** + * Set up a vertex program to pass through the position and first texcoord + * for pixel path. + */ +void +intel_meta_set_passthrough_vertex_program(struct intel_context *intel) +{ + GLcontext *ctx = &intel->ctx; + static const char *vp = + "!!ARBvp1.0\n" + "TEMP vertexClip;\n" + "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position;\n" + "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position;\n" + "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position;\n" + "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position;\n" + "MOV result.position, vertexClip;\n" + "MOV result.texcoord[0], vertex.texcoord[0];\n" + "MOV result.color, vertex.color;\n" + "END\n"; + + assert(intel->meta.saved_vp == NULL); + + _mesa_reference_vertprog(ctx, &intel->meta.saved_vp, + ctx->VertexProgram.Current); + if (intel->meta.passthrough_vp == NULL) { + GLuint prog_name; + _mesa_GenPrograms(1, &prog_name); + _mesa_BindProgram(GL_VERTEX_PROGRAM_ARB, prog_name); + _mesa_ProgramStringARB(GL_VERTEX_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(vp), (const GLubyte *)vp); + _mesa_reference_vertprog(ctx, &intel->meta.passthrough_vp, + ctx->VertexProgram.Current); + _mesa_DeletePrograms(1, &prog_name); + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + intel->meta.passthrough_vp); + ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, + &intel->meta.passthrough_vp->Base); + + intel->meta.saved_vp_enable = ctx->VertexProgram.Enabled; + _mesa_Enable(GL_VERTEX_PROGRAM_ARB); +} + +/** + * Restores the previous vertex program after + * intel_meta_set_passthrough_vertex_program() + */ +void +intel_meta_restore_vertex_program(struct intel_context *intel) +{ + GLcontext *ctx = &intel->ctx; + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, + intel->meta.saved_vp); + _mesa_reference_vertprog(ctx, &intel->meta.saved_vp, NULL); + ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, + &ctx->VertexProgram.Current->Base); + + if (!intel->meta.saved_vp_enable) + _mesa_Disable(GL_VERTEX_PROGRAM_ARB); +} + +/** + * Binds the given program string to GL_FRAGMENT_PROGRAM_ARB, caching the + * program object. + */ +void +intel_meta_set_fragment_program(struct intel_context *intel, + struct gl_fragment_program **prog, + const char *prog_string) +{ + GLcontext *ctx = &intel->ctx; + assert(intel->meta.saved_fp == NULL); + + _mesa_reference_fragprog(ctx, &intel->meta.saved_fp, + ctx->FragmentProgram.Current); + if (*prog == NULL) { + GLuint prog_name; + _mesa_GenPrograms(1, &prog_name); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, prog_name); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, + GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(prog_string), (const GLubyte *)prog_string); + _mesa_reference_fragprog(ctx, prog, ctx->FragmentProgram.Current); + /* Note that DeletePrograms unbinds the program on us */ + _mesa_DeletePrograms(1, &prog_name); + } + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, *prog); + ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, &((*prog)->Base)); + + intel->meta.saved_fp_enable = ctx->FragmentProgram.Enabled; + _mesa_Enable(GL_FRAGMENT_PROGRAM_ARB); +} + +/** + * Restores the previous fragment program after + * intel_meta_set_fragment_program() + */ +void +intel_meta_restore_fragment_program(struct intel_context *intel) +{ + GLcontext *ctx = &intel->ctx; + + FLUSH_VERTICES(ctx, _NEW_PROGRAM); + _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, + intel->meta.saved_fp); + _mesa_reference_fragprog(ctx, &intel->meta.saved_fp, NULL); + ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, + &ctx->FragmentProgram.Current->Base); + + if (!intel->meta.saved_fp_enable) + _mesa_Disable(GL_FRAGMENT_PROGRAM_ARB); +} void intelInitPixelFuncs(struct dd_function_table *functions) @@ -181,3 +304,13 @@ intelInitPixelFuncs(struct dd_function_table *functions) #endif } } + +void +intel_free_pixel_state(struct intel_context *intel) +{ + GLcontext *ctx = &intel->ctx; + + _mesa_reference_vertprog(ctx, &intel->meta.passthrough_vp, NULL); + _mesa_reference_fragprog(ctx, &intel->meta.bitmap_fp, NULL); +} + diff --git a/src/mesa/drivers/dri/intel/intel_pixel.h b/src/mesa/drivers/dri/intel/intel_pixel.h index 6fa6effe835..9556efc71c2 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel.h +++ b/src/mesa/drivers/dri/intel/intel_pixel.h @@ -32,6 +32,14 @@ void intelInitPixelFuncs(struct dd_function_table *functions); +void intel_meta_set_passthrough_vertex_program(struct intel_context *intel); +void intel_meta_restore_vertex_program(struct intel_context *intel); +void intel_meta_set_fragment_program(struct intel_context *intel, + struct gl_fragment_program **prog, + const char *prog_string); +void intel_meta_restore_fragment_program(struct intel_context *intel); +void intel_free_pixel_state(struct intel_context *intel); + GLboolean intel_check_blit_fragment_ops(GLcontext * ctx, GLboolean src_alpha_is_one); diff --git a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c index 5e0e0d29ca5..88e181a51f2 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c +++ b/src/mesa/drivers/dri/intel/intel_pixel_bitmap.c @@ -32,7 +32,19 @@ #include "main/mtypes.h" #include "main/macros.h" #include "main/bufferobj.h" +#include "main/pixelstore.h" #include "main/state.h" +#include "main/teximage.h" +#include "main/texenv.h" +#include "main/texobj.h" +#include "main/texstate.h" +#include "main/texparam.h" +#include "main/matrix.h" +#include "main/varray.h" +#include "main/attrib.h" +#include "main/enable.h" +#include "shader/arbprogram.h" +#include "glapi/dispatch.h" #include "swrast/swrast.h" #include "intel_screen.h" @@ -87,6 +99,11 @@ static GLboolean test_bit( const GLubyte *src, return (src[bit/8] & (1<<(bit % 8))) ? 1 : 0; } +static GLboolean test_msb_bit(const GLubyte *src, GLuint bit) +{ + return (src[bit/8] & (1<<(7 - (bit % 8)))) ? 1 : 0; +} + static void set_bit( GLubyte *dest, GLuint bit ) { @@ -317,9 +334,187 @@ out: return GL_TRUE; } +static GLboolean +intel_texture_bitmap(GLcontext * ctx, + GLint dst_x, GLint dst_y, + GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap) +{ + struct intel_context *intel = intel_context(ctx); + static const char *fp = + "!!ARBfp1.0\n" + "TEMP val;\n" + "PARAM color=program.local[0];\n" + "TEX val, fragment.texcoord[0], texture[0], 2D;\n" + "ADD val, val.wwww, {-.5, -.5, -.5, -.5};\n" + "KIL val;\n" + "MOV result.color, color;\n" + "END\n"; + GLuint texname; + GLfloat vertices[4][4]; + GLfloat texcoords[4][2]; + GLint old_active_texture; + GLubyte *unpacked_bitmap; + GLubyte *a8_bitmap; + int x, y; + + /* We need a fragment program for the KIL effect */ + if (!ctx->Extensions.ARB_fragment_program || + !ctx->Extensions.ARB_vertex_program) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, + "glBitmap fallback: No fragment/vertex program support\n"); + return GL_FALSE; + } + + /* We're going to mess with texturing with no regard to existing texture + * state, so if there is some set up we have to bail. + */ + if (ctx->Texture._EnabledUnits != 0) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "glBitmap fallback: texturing enabled\n"); + return GL_FALSE; + } + + /* Can't do textured DrawPixels with a fragment program, unless we were + * to generate a new program that sampled our texture and put the results + * in the fragment color before the user's program started. + */ + if (ctx->FragmentProgram.Enabled) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "glBitmap fallback: fragment program enabled\n"); + return GL_FALSE; + } + + if (ctx->VertexProgram.Enabled) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "glBitmap fallback: vertex program enabled\n"); + return GL_FALSE; + } + + /* Check that we can load in a texture this big. */ + if (width > (1 << (ctx->Const.MaxTextureLevels - 1)) || + height > (1 << (ctx->Const.MaxTextureLevels - 1))) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "glBitmap fallback: bitmap too large (%dx%d)\n", + width, height); + return GL_FALSE; + } + /* Convert the A1 bitmap to an A8 format suitable for glTexImage */ + if (unpack->BufferObj->Name) { + bitmap = map_pbo(ctx, width, height, unpack, bitmap); + if (bitmap == NULL) + return GL_TRUE; /* even though this is an error, we're done */ + } + unpacked_bitmap = _mesa_unpack_bitmap(width, height, bitmap, + unpack); + a8_bitmap = _mesa_calloc(width * height); + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + if (test_msb_bit(unpacked_bitmap, ALIGN(width, 8) * y + x)) + a8_bitmap[y * width + x] = 0xff; + } + } + _mesa_free(unpacked_bitmap); + if (unpack->BufferObj->Name) { + /* done with PBO so unmap it now */ + ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, + unpack->BufferObj); + } + /* Save GL state before we start setting up our drawing */ + _mesa_PushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_CURRENT_BIT | + GL_VIEWPORT_BIT); + _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT | + GL_CLIENT_PIXEL_STORE_BIT); + old_active_texture = ctx->Texture.CurrentUnit; + + _mesa_Disable(GL_POLYGON_STIPPLE); + + /* Upload our bitmap data to an alpha texture */ + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB); + _mesa_Enable(GL_TEXTURE_2D); + _mesa_GenTextures(1, &texname); + _mesa_BindTexture(GL_TEXTURE_2D, texname); + _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + _mesa_PixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); + _mesa_PixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); + _mesa_PixelStorei(GL_UNPACK_ROW_LENGTH, 0); + _mesa_PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); + _mesa_PixelStorei(GL_UNPACK_SKIP_ROWS, 0); + _mesa_PixelStorei(GL_UNPACK_ALIGNMENT, 1); + _mesa_TexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, + GL_ALPHA, GL_UNSIGNED_BYTE, a8_bitmap); + _mesa_free(a8_bitmap); + + _mesa_Viewport(0, 0, ctx->DrawBuffer->Width, ctx->DrawBuffer->Height); + _mesa_MatrixMode(GL_PROJECTION); + _mesa_PushMatrix(); + _mesa_LoadIdentity(); + _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1); + + _mesa_MatrixMode(GL_MODELVIEW); + _mesa_PushMatrix(); + _mesa_LoadIdentity(); + + intel_meta_set_fragment_program(intel, &intel->meta.bitmap_fp, fp); + _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, + ctx->Current.RasterColor); + intel_meta_set_passthrough_vertex_program(intel); + + vertices[0][0] = dst_x; + vertices[0][1] = dst_y; + vertices[0][2] = ctx->Current.RasterPos[2]; + vertices[0][3] = 1.0; + vertices[1][0] = dst_x + width; + vertices[1][1] = dst_y; + vertices[1][2] = ctx->Current.RasterPos[2]; + vertices[1][3] = 1.0; + vertices[2][0] = dst_x + width; + vertices[2][1] = dst_y + height; + vertices[2][2] = ctx->Current.RasterPos[2]; + vertices[2][3] = 1.0; + vertices[3][0] = dst_x; + vertices[3][1] = dst_y + height; + vertices[3][2] = ctx->Current.RasterPos[2]; + vertices[3][3] = 1.0; + + texcoords[0][0] = 0.0; + texcoords[0][1] = 0.0; + texcoords[1][0] = 1.0; + texcoords[1][1] = 0.0; + texcoords[2][0] = 1.0; + texcoords[2][1] = 1.0; + texcoords[3][0] = 0.0; + texcoords[3][1] = 1.0; + + _mesa_VertexPointer(4, GL_FLOAT, 4 * sizeof(GLfloat), &vertices); + _mesa_TexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &texcoords); + _mesa_Enable(GL_VERTEX_ARRAY); + _mesa_Enable(GL_TEXTURE_COORD_ARRAY); + CALL_DrawArrays(ctx->Exec, (GL_TRIANGLE_FAN, 0, 4)); + + intel_meta_restore_fragment_program(intel); + intel_meta_restore_vertex_program(intel); + + _mesa_MatrixMode(GL_PROJECTION); + _mesa_PopMatrix(); + _mesa_MatrixMode(GL_MODELVIEW); + _mesa_PopMatrix(); + + _mesa_PopClientAttrib(); + _mesa_Disable(GL_TEXTURE_2D); /* asserted that it was disabled at entry */ + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture); + _mesa_PopAttrib(); + + _mesa_DeleteTextures(1, &texname); + return GL_TRUE; +} /* There are a large number of possible ways to implement bitmap on * this hardware, most of them have some sort of drawback. Here are a @@ -352,6 +547,10 @@ intelBitmap(GLcontext * ctx, unpack, pixels)) return; + if (intel_texture_bitmap(ctx, x, y, width, height, + unpack, pixels)) + return; + if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s: fallback to swrast\n", __FUNCTION__); |