diff options
Diffstat (limited to 'src/mesa/drivers/common/meta.c')
-rw-r--r-- | src/mesa/drivers/common/meta.c | 997 |
1 files changed, 826 insertions, 171 deletions
diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c index 02194a39b47..0b9781027e7 100644 --- a/src/mesa/drivers/common/meta.c +++ b/src/mesa/drivers/common/meta.c @@ -37,12 +37,16 @@ #include "main/arrayobj.h" #include "main/blend.h" #include "main/bufferobj.h" +#include "main/buffers.h" #include "main/depth.h" #include "main/enable.h" +#include "main/fbobject.h" #include "main/image.h" #include "main/macros.h" #include "main/matrix.h" +#include "main/mipmap.h" #include "main/polygon.h" +#include "main/readpix.h" #include "main/scissor.h" #include "main/shaders.h" #include "main/stencil.h" @@ -54,6 +58,7 @@ #include "main/varray.h" #include "main/viewport.h" #include "shader/program.h" +#include "shader/arbprogram.h" #include "swrast/swrast.h" #include "drivers/common/meta.h" @@ -82,8 +87,8 @@ struct save_state /** META_FOG */ GLboolean Fog; - /** META_PIXELSTORE */ - /* XXX / TO-DO */ + /** META_PIXEL_STORE */ + struct gl_pixelstore_attrib Pack, Unpack; /** META_RASTERIZATION */ GLenum FrontPolygonMode, BackPolygonMode; @@ -136,13 +141,31 @@ struct save_state /** + * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc. + * This is currently shared by all the meta ops. But we could create a + * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc. + */ +struct temp_texture +{ + GLuint TexObj; + GLenum Target; /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */ + GLsizei MinSize; /**< Min texture size to allocate */ + GLsizei MaxSize; /**< Max possible texture size */ + GLboolean NPOT; /**< Non-power of two size OK? */ + GLsizei Width, Height; /**< Current texture size */ + GLenum IntFormat; + GLfloat Sright, Ttop; /**< right, top texcoords */ +}; + + +/** * State for glBlitFramebufer() */ struct blit_state { GLuint ArrayObj; GLuint VBO; - GLfloat verts[4][4]; /** four verts of X,Y,S,T */ + GLuint DepthFP; }; @@ -153,7 +176,6 @@ struct clear_state { GLuint ArrayObj; GLuint VBO; - GLfloat verts[4][7]; /** four verts of X,Y,Z,R,G,B,A */ }; @@ -164,7 +186,6 @@ struct copypix_state { GLuint ArrayObj; GLuint VBO; - GLfloat verts[4][5]; /** four verts of X,Y,Z,S,T */ }; @@ -175,24 +196,31 @@ struct drawpix_state { GLuint ArrayObj; GLuint VBO; - GLfloat verts[4][5]; /** four verts of X,Y,Z,S,T */ + + GLuint StencilFP; /**< Fragment program for drawing stencil images */ + GLuint DepthFP; /**< Fragment program for drawing depth images */ }; /** - * Temporary texture used for glBlitFramebuffer, glDrawPixels, etc. - * This is currently shared by all the meta ops. But we could create a - * separate one for each of glDrawPixel, glBlitFramebuffer, glCopyPixels, etc. + * State for glBitmap() */ -struct temp_texture +struct bitmap_state { - GLuint TexObj; - GLenum Target; /**< GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE */ - GLsizei MaxSize; /**< Max possible texture size */ - GLboolean NPOT; /**< Non-power of two size OK? */ - GLsizei Width, Height; /**< Current texture size */ - GLenum IntFormat; - GLfloat Sright, Ttop; /**< right, top texcoords */ + GLuint ArrayObj; + GLuint VBO; + struct temp_texture Tex; /**< separate texture from other meta ops */ +}; + + +/** + * State for _mesa_meta_generate_mipmap() + */ +struct gen_mipmap_state +{ + GLuint ArrayObj; + GLuint VBO; + GLuint FBO; }; @@ -209,11 +237,8 @@ struct gl_meta_state struct clear_state Clear; /**< For _mesa_meta_clear() */ struct copypix_state CopyPix; /**< For _mesa_meta_copy_pixels() */ struct drawpix_state DrawPix; /**< For _mesa_meta_draw_pixels() */ - - /* other possible meta-ops: - * glBitmap() - * glGenerateMipmap() - */ + struct bitmap_state Bitmap; /**< For _mesa_meta_bitmap() */ + struct gen_mipmap_state Mipmap; /**< For _mesa_meta_generate_mipmap() */ }; @@ -239,28 +264,37 @@ _mesa_meta_free(GLcontext *ctx) { struct gl_meta_state *meta = ctx->Meta; - if (meta->TempTex.TexObj) { + if (_mesa_get_current_context()) { + /* if there's no current context, these textures, buffers, etc should + * still get freed by _mesa_free_context_data(). + */ + + /* the temporary texture */ _mesa_DeleteTextures(1, &meta->TempTex.TexObj); - } - if (meta->Blit.VBO) { + /* glBlitFramebuffer */ _mesa_DeleteBuffersARB(1, & meta->Blit.VBO); _mesa_DeleteVertexArraysAPPLE(1, &meta->Blit.ArrayObj); - } + _mesa_DeletePrograms(1, &meta->Blit.DepthFP); - if (meta->Clear.VBO) { + /* glClear */ _mesa_DeleteBuffersARB(1, & meta->Clear.VBO); _mesa_DeleteVertexArraysAPPLE(1, &meta->Clear.ArrayObj); - } - if (meta->CopyPix.VBO) { + /* glCopyPixels */ _mesa_DeleteBuffersARB(1, & meta->CopyPix.VBO); _mesa_DeleteVertexArraysAPPLE(1, &meta->CopyPix.ArrayObj); - } - if (meta->DrawPix.VBO) { + /* glDrawPixels */ _mesa_DeleteBuffersARB(1, & meta->DrawPix.VBO); _mesa_DeleteVertexArraysAPPLE(1, &meta->DrawPix.ArrayObj); + _mesa_DeletePrograms(1, &meta->DrawPix.DepthFP); + _mesa_DeletePrograms(1, &meta->DrawPix.StencilFP); + + /* glBitmap */ + _mesa_DeleteBuffersARB(1, & meta->Bitmap.VBO); + _mesa_DeleteVertexArraysAPPLE(1, &meta->Bitmap.ArrayObj); + _mesa_DeleteTextures(1, &meta->Bitmap.Tex.TexObj); } _mesa_free(ctx->Meta); @@ -285,16 +319,16 @@ _mesa_meta_begin(GLcontext *ctx, GLbitfield state) if (state & META_ALPHA_TEST) { save->AlphaEnabled = ctx->Color.AlphaEnabled; if (ctx->Color.AlphaEnabled) - _mesa_Disable(GL_ALPHA_TEST); + _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_FALSE); } if (state & META_BLEND) { save->BlendEnabled = ctx->Color.BlendEnabled; if (ctx->Color.BlendEnabled) - _mesa_Disable(GL_BLEND); + _mesa_set_enable(ctx, GL_BLEND, GL_FALSE); save->ColorLogicOpEnabled = ctx->Color.ColorLogicOpEnabled; if (ctx->Color.ColorLogicOpEnabled) - _mesa_Disable(GL_COLOR_LOGIC_OP); + _mesa_set_enable(ctx, GL_COLOR_LOGIC_OP, GL_FALSE); } if (state & META_COLOR_MASK) { @@ -309,7 +343,7 @@ _mesa_meta_begin(GLcontext *ctx, GLbitfield state) if (state & META_DEPTH_TEST) { save->Depth = ctx->Depth; /* struct copy */ if (ctx->Depth.Test) - _mesa_Disable(GL_DEPTH_TEST); + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_FALSE); } if (state & META_FOG) { @@ -318,6 +352,13 @@ _mesa_meta_begin(GLcontext *ctx, GLbitfield state) _mesa_set_enable(ctx, GL_FOG, GL_FALSE); } + if (state & META_PIXEL_STORE) { + save->Pack = ctx->Pack; + save->Unpack = ctx->Unpack; + ctx->Pack = ctx->DefaultPacking; + ctx->Unpack = ctx->DefaultPacking; + } + if (state & META_RASTERIZATION) { save->FrontPolygonMode = ctx->Polygon.FrontMode; save->BackPolygonMode = ctx->Polygon.BackMode; @@ -359,7 +400,7 @@ _mesa_meta_begin(GLcontext *ctx, GLbitfield state) if (state & META_STENCIL_TEST) { save->Stencil = ctx->Stencil; /* struct copy */ if (ctx->Stencil.Enabled) - _mesa_Disable(GL_STENCIL_TEST); + _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_FALSE); /* NOTE: other stencil state not reset */ } @@ -370,6 +411,11 @@ _mesa_meta_begin(GLcontext *ctx, GLbitfield state) save->ClientActiveUnit = ctx->Array.ActiveTexture; save->EnvMode = ctx->Texture.Unit[0].EnvMode; + if (ctx->Texture._EnabledUnits | + ctx->Texture._EnabledCoordUnits | + ctx->Texture._TexGenEnabled | + ctx->Texture._TexMatEnabled) { + /* Disable all texture units */ for (u = 0; u < ctx->Const.MaxTextureUnits; u++) { save->TexEnabled[u] = ctx->Texture.Unit[u].Enabled; @@ -388,6 +434,7 @@ _mesa_meta_begin(GLcontext *ctx, GLbitfield state) _mesa_set_enable(ctx, GL_TEXTURE_GEN_Q, GL_FALSE); } } + } /* save current texture objects for unit[0] only */ for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { @@ -508,6 +555,11 @@ _mesa_meta_end(GLcontext *ctx) _mesa_set_enable(ctx, GL_FOG, save->Fog); } + if (state & META_PIXEL_STORE) { + ctx->Pack = save->Pack; + ctx->Unpack = save->Unpack; + } + if (state & META_RASTERIZATION) { _mesa_PolygonMode(GL_FRONT, save->FrontPolygonMode); _mesa_PolygonMode(GL_BACK, save->BackPolygonMode); @@ -682,8 +734,35 @@ _mesa_meta_end(GLcontext *ctx) /** - * Return pointer to temp_texture info. This does some one-time init - * if needed. + * One-time init for a temp_texture object. + * Choose tex target, compute max tex size, etc. + */ +static void +init_temp_texture(GLcontext *ctx, struct temp_texture *tex) +{ + /* prefer texture rectangle */ + if (ctx->Extensions.NV_texture_rectangle) { + tex->Target = GL_TEXTURE_RECTANGLE; + tex->MaxSize = ctx->Const.MaxTextureRectSize; + tex->NPOT = GL_TRUE; + } + else { + /* use 2D texture, NPOT if possible */ + tex->Target = GL_TEXTURE_2D; + tex->MaxSize = 1 << (ctx->Const.MaxTextureLevels - 1); + tex->NPOT = ctx->Extensions.ARB_texture_non_power_of_two; + } + tex->MinSize = 16; /* 16 x 16 at least */ + assert(tex->MaxSize > 0); + + _mesa_GenTextures(1, &tex->TexObj); + _mesa_BindTexture(tex->Target, tex->TexObj); +} + + +/** + * Return pointer to temp_texture info for non-bitmap ops. + * This does some one-time init if needed. */ static struct temp_texture * get_temp_texture(GLcontext *ctx) @@ -691,24 +770,25 @@ get_temp_texture(GLcontext *ctx) struct temp_texture *tex = &ctx->Meta->TempTex; if (!tex->TexObj) { - /* do one-time init */ + init_temp_texture(ctx, tex); + } + + return tex; +} - /* prefer texture rectangle */ - if (0*ctx->Extensions.NV_texture_rectangle) { - tex->Target = GL_TEXTURE_RECTANGLE; - tex->MaxSize = ctx->Const.MaxTextureRectSize; - tex->NPOT = GL_TRUE; - } - else { - /* use 2D texture, NPOT if possible */ - tex->Target = GL_TEXTURE_2D; - tex->MaxSize = 1 << (ctx->Const.MaxTextureLevels - 1); - tex->NPOT = 0*ctx->Extensions.ARB_texture_non_power_of_two; - } - assert(tex->MaxSize > 0); - _mesa_GenTextures(1, &tex->TexObj); - _mesa_BindTexture(tex->Target, tex->TexObj); +/** + * Return pointer to temp_texture info for _mesa_meta_bitmap(). + * We use a separate texture for bitmaps to reduce texture + * allocation/deallocation. + */ +static struct temp_texture * +get_bitmap_temp_texture(GLcontext *ctx) +{ + struct temp_texture *tex = &ctx->Meta->Bitmap.Tex; + + if (!tex->TexObj) { + init_temp_texture(ctx, tex); } return tex; @@ -730,6 +810,9 @@ alloc_texture(struct temp_texture *tex, { GLboolean newTex = GL_FALSE; + ASSERT(width <= tex->MaxSize); + ASSERT(height <= tex->MaxSize); + if (width > tex->Width || height > tex->Height || intFormat != tex->IntFormat) { @@ -737,13 +820,13 @@ alloc_texture(struct temp_texture *tex, if (tex->NPOT) { /* use non-power of two size */ - tex->Width = width; - tex->Height = height; + tex->Width = MAX2(tex->MinSize, width); + tex->Height = MAX2(tex->MinSize, height); } else { /* find power of two size */ GLsizei w, h; - w = h = 16; + w = h = tex->MinSize; while (w < width) w *= 2; while (h < height) @@ -855,6 +938,38 @@ setup_drawpix_texture(struct temp_texture *tex, /** + * One-time init for drawing depth pixels. + */ +static void +init_blit_depth_pixels(GLcontext *ctx) +{ + static const char *program = + "!!ARBfp1.0\n" + "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" + "END \n"; + char program2[200]; + struct blit_state *blit = &ctx->Meta->Blit; + struct temp_texture *tex = get_temp_texture(ctx); + const char *texTarget; + + assert(blit->DepthFP == 0); + + /* replace %s with "RECT" or "2D" */ + assert(strlen(program) + 4 < sizeof(program2)); + if (tex->Target == GL_TEXTURE_RECTANGLE) + texTarget = "RECT"; + else + texTarget = "2D"; + _mesa_snprintf(program2, sizeof(program2), program, texTarget); + + _mesa_GenPrograms(1, &blit->DepthFP); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program2), (const GLubyte *) program2); +} + + +/** * Meta implementation of ctx->Driver.BlitFramebuffer() in terms * of texture mapping and polygon rendering. */ @@ -873,6 +988,7 @@ _mesa_meta_blit_framebuffer(GLcontext *ctx, const GLint srcH = abs(srcY1 - srcY0); const GLboolean srcFlipX = srcX1 < srcX0; const GLboolean srcFlipY = srcY1 < srcY0; + GLfloat verts[4][4]; /* four verts of X,Y,S,T */ GLboolean newTex; if (srcW > maxTexSize || srcH > maxTexSize) { @@ -907,13 +1023,13 @@ _mesa_meta_blit_framebuffer(GLcontext *ctx, /* create vertex array buffer */ _mesa_GenBuffersARB(1, &blit->VBO); _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, blit->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(blit->verts), - blit->verts, GL_STREAM_DRAW_ARB); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); /* setup vertex arrays */ - _mesa_VertexPointer(2, GL_FLOAT, 4 * sizeof(GLfloat), - (void*) (0 * sizeof(GLfloat))); - _mesa_TexCoordPointer(2, GL_FLOAT, 4 * sizeof(GLfloat), + _mesa_VertexPointer(2, GL_FLOAT, sizeof(verts[0]), + (void *) (0 * sizeof(GLfloat))); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(verts[0]), (void *) (2 * sizeof(GLfloat))); _mesa_EnableClientState(GL_VERTEX_ARRAY); _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -927,30 +1043,29 @@ _mesa_meta_blit_framebuffer(GLcontext *ctx, /* vertex positions/texcoords (after texture allocation!) */ { - blit->verts[0][0] = (GLfloat) dstX0; - blit->verts[0][1] = (GLfloat) dstY0; - blit->verts[1][0] = (GLfloat) dstX1; - blit->verts[1][1] = (GLfloat) dstY0; - blit->verts[2][0] = (GLfloat) dstX1; - blit->verts[2][1] = (GLfloat) dstY1; - blit->verts[3][0] = (GLfloat) dstX0; - blit->verts[3][1] = (GLfloat) dstY1; - - blit->verts[0][2] = 0.0F; - blit->verts[0][3] = 0.0F; - blit->verts[1][2] = tex->Sright; - blit->verts[1][3] = 0.0F; - blit->verts[2][2] = tex->Sright; - blit->verts[2][3] = tex->Ttop; - blit->verts[3][2] = 0.0F; - blit->verts[3][3] = tex->Ttop; + verts[0][0] = (GLfloat) dstX0; + verts[0][1] = (GLfloat) dstY0; + verts[1][0] = (GLfloat) dstX1; + verts[1][1] = (GLfloat) dstY0; + verts[2][0] = (GLfloat) dstX1; + verts[2][1] = (GLfloat) dstY1; + verts[3][0] = (GLfloat) dstX0; + verts[3][1] = (GLfloat) dstY1; + + verts[0][2] = 0.0F; + verts[0][3] = 0.0F; + verts[1][2] = tex->Sright; + verts[1][3] = 0.0F; + verts[2][2] = tex->Sright; + verts[2][3] = tex->Ttop; + verts[3][2] = 0.0F; + verts[3][3] = tex->Ttop; /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, - sizeof(blit->verts), blit->verts); + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); } - _mesa_Enable(tex->Target); + _mesa_set_enable(ctx, tex->Target, GL_TRUE); if (mask & GL_COLOR_BUFFER_BIT) { setup_copypix_texture(tex, newTex, srcX, srcY, srcW, srcH, @@ -958,19 +1073,45 @@ _mesa_meta_blit_framebuffer(GLcontext *ctx, _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); mask &= ~GL_COLOR_BUFFER_BIT; } + if (mask & GL_DEPTH_BUFFER_BIT) { - /* XXX todo (need fragment shader) */ + GLuint *tmp = (GLuint *) _mesa_malloc(srcW * srcH * sizeof(GLuint)); + if (tmp) { + if (!blit->DepthFP) + init_blit_depth_pixels(ctx); + + /* maybe change tex format here */ + newTex = alloc_texture(tex, srcW, srcH, GL_DEPTH_COMPONENT); + + _mesa_ReadPixels(srcX, srcY, srcW, srcH, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, tmp); + + setup_drawpix_texture(tex, newTex, GL_DEPTH_COMPONENT, srcW, srcH, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, tmp); + + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, blit->DepthFP); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE); + _mesa_DepthFunc(GL_ALWAYS); + _mesa_DepthMask(GL_TRUE); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + mask &= ~GL_DEPTH_BUFFER_BIT; + + _mesa_free(tmp); + } } + if (mask & GL_STENCIL_BUFFER_BIT) { /* XXX can't easily do stencil */ } - _mesa_Disable(tex->Target); + _mesa_set_enable(ctx, tex->Target, GL_FALSE); _mesa_meta_end(ctx); - /* XXX, TO-DO: try to handle these cases above! */ - if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) { + if (mask) { _swrast_BlitFramebuffer(ctx, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } @@ -984,9 +1125,16 @@ void _mesa_meta_clear(GLcontext *ctx, GLbitfield buffers) { struct clear_state *clear = &ctx->Meta->Clear; + GLfloat verts[4][7]; /* four verts of X,Y,Z,R,G,B,A */ + /* save all state but scissor, pixel pack/unpack */ + GLbitfield metaSave = META_ALL - META_SCISSOR - META_PIXEL_STORE; - /* only scissor and color mask effects clearing */ - _mesa_meta_begin(ctx, ~(META_SCISSOR | META_COLOR_MASK)); + if (buffers & BUFFER_BITS_COLOR) { + /* if clearing color buffers, don't save/restore colormask */ + metaSave -= META_COLOR_MASK; + } + + _mesa_meta_begin(ctx, metaSave); if (clear->ArrayObj == 0) { /* one-time setup */ @@ -998,12 +1146,13 @@ _mesa_meta_clear(GLcontext *ctx, GLbitfield buffers) /* create vertex array buffer */ _mesa_GenBuffersARB(1, &clear->VBO); _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(clear->verts), - clear->verts, GL_STREAM_DRAW_ARB); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, 7 * sizeof(GLfloat), (void *) 0); - _mesa_ColorPointer(4, GL_FLOAT, 7 * sizeof(GLfloat), + _mesa_VertexPointer(3, GL_FLOAT, sizeof(verts[0]), + (void *) (0 * sizeof(GLfloat))); + _mesa_ColorPointer(4, GL_FLOAT, sizeof(verts[0]), (void *) (3 * sizeof(GLfloat))); _mesa_EnableClientState(GL_VERTEX_ARRAY); _mesa_EnableClientState(GL_COLOR_ARRAY); @@ -1018,6 +1167,7 @@ _mesa_meta_clear(GLcontext *ctx, GLbitfield buffers) /* leave colormask, glDrawBuffer state as-is */ } else { + ASSERT(metaSave & META_COLOR_MASK); _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); } @@ -1053,27 +1203,26 @@ _mesa_meta_clear(GLcontext *ctx, GLbitfield buffers) const GLfloat z = 1.0 - 2.0 * ctx->Depth.Clear; GLuint i; - clear->verts[0][0] = x0; - clear->verts[0][1] = y0; - clear->verts[0][2] = z; - clear->verts[1][0] = x1; - clear->verts[1][1] = y0; - clear->verts[1][2] = z; - clear->verts[2][0] = x1; - clear->verts[2][1] = y1; - clear->verts[2][2] = z; - clear->verts[3][0] = x0; - clear->verts[3][1] = y1; - clear->verts[3][2] = z; + verts[0][0] = x0; + verts[0][1] = y0; + verts[0][2] = z; + verts[1][0] = x1; + verts[1][1] = y0; + verts[1][2] = z; + verts[2][0] = x1; + verts[2][1] = y1; + verts[2][2] = z; + verts[3][0] = x0; + verts[3][1] = y1; + verts[3][2] = z; /* vertex colors */ for (i = 0; i < 4; i++) { - COPY_4FV(&clear->verts[i][3], ctx->Color.ClearColor); + COPY_4FV(&verts[i][3], ctx->Color.ClearColor); } /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, - sizeof(clear->verts), clear->verts); + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); } /* draw quad */ @@ -1094,6 +1243,7 @@ _mesa_meta_copy_pixels(GLcontext *ctx, GLint srcX, GLint srcY, { struct copypix_state *copypix = &ctx->Meta->CopyPix; struct temp_texture *tex = get_temp_texture(ctx); + GLfloat verts[4][5]; /* four verts of X,Y,Z,S,T */ GLboolean newTex; GLenum intFormat = GL_RGBA; @@ -1127,13 +1277,13 @@ _mesa_meta_copy_pixels(GLcontext *ctx, GLint srcX, GLint srcY, /* create vertex array buffer */ _mesa_GenBuffersARB(1, ©pix->VBO); _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, copypix->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(copypix->verts), - copypix->verts, GL_STREAM_DRAW_ARB); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(copypix->verts[0]), - (void*) (0 * sizeof(GLfloat))); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(copypix->verts[0]), + _mesa_VertexPointer(3, GL_FLOAT, sizeof(verts[0]), + (void *) (0 * sizeof(GLfloat))); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(verts[0]), (void *) (3 * sizeof(GLfloat))); _mesa_EnableClientState(GL_VERTEX_ARRAY); _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -1153,42 +1303,41 @@ _mesa_meta_copy_pixels(GLcontext *ctx, GLint srcX, GLint srcY, const GLfloat dstY1 = dstY + height * ctx->Pixel.ZoomY; const GLfloat z = ctx->Current.RasterPos[2]; - copypix->verts[0][0] = dstX0; - copypix->verts[0][1] = dstY0; - copypix->verts[0][2] = z; - copypix->verts[0][3] = 0.0F; - copypix->verts[0][4] = 0.0F; - copypix->verts[1][0] = dstX1; - copypix->verts[1][1] = dstY0; - copypix->verts[1][2] = z; - copypix->verts[1][3] = tex->Sright; - copypix->verts[1][4] = 0.0F; - copypix->verts[2][0] = dstX1; - copypix->verts[2][1] = dstY1; - copypix->verts[2][2] = z; - copypix->verts[2][3] = tex->Sright; - copypix->verts[2][4] = tex->Ttop; - copypix->verts[3][0] = dstX0; - copypix->verts[3][1] = dstY1; - copypix->verts[3][2] = z; - copypix->verts[3][3] = 0.0F; - copypix->verts[3][4] = tex->Ttop; + verts[0][0] = dstX0; + verts[0][1] = dstY0; + verts[0][2] = z; + verts[0][3] = 0.0F; + verts[0][4] = 0.0F; + verts[1][0] = dstX1; + verts[1][1] = dstY0; + verts[1][2] = z; + verts[1][3] = tex->Sright; + verts[1][4] = 0.0F; + verts[2][0] = dstX1; + verts[2][1] = dstY1; + verts[2][2] = z; + verts[2][3] = tex->Sright; + verts[2][4] = tex->Ttop; + verts[3][0] = dstX0; + verts[3][1] = dstY1; + verts[3][2] = z; + verts[3][3] = 0.0F; + verts[3][4] = tex->Ttop; /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, - sizeof(copypix->verts), copypix->verts); + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); } /* Alloc/setup texture */ setup_copypix_texture(tex, newTex, srcX, srcY, width, height, GL_RGBA, GL_NEAREST); - _mesa_Enable(tex->Target); + _mesa_set_enable(ctx, tex->Target, GL_TRUE); /* draw textured quad */ _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - _mesa_Disable(tex->Target); + _mesa_set_enable(ctx, tex->Target, GL_FALSE); _mesa_meta_end(ctx); } @@ -1235,6 +1384,104 @@ tiled_draw_pixels(GLcontext *ctx, /** + * One-time init for drawing stencil pixels. + */ +static void +init_draw_stencil_pixels(GLcontext *ctx) +{ + /* This program is run eight times, once for each stencil bit. + * The stencil values to draw are found in an 8-bit alpha texture. + * We read the texture/stencil value and test if bit 'b' is set. + * If the bit is not set, use KIL to kill the fragment. + * Finally, we use the stencil test to update the stencil buffer. + * + * The basic algorithm for checking if a bit is set is: + * if (is_odd(value / (1 << bit))) + * result is one (or non-zero). + * else + * result is zero. + * The program parameter contains three values: + * parm.x = 255 / (1 << bit) + * parm.y = 0.5 + * parm.z = 0.0 + */ + static const char *program = + "!!ARBfp1.0\n" + "PARAM parm = program.local[0]; \n" + "TEMP t; \n" + "TEX t, fragment.texcoord[0], texture[0], %s; \n" /* NOTE %s here! */ + "# t = t * 255 / bit \n" + "MUL t.x, t.a, parm.x; \n" + "# t = (int) t \n" + "FRC t.y, t.x; \n" + "SUB t.x, t.x, t.y; \n" + "# t = t * 0.5 \n" + "MUL t.x, t.x, parm.y; \n" + "# t = fract(t.x) \n" + "FRC t.x, t.x; # if t.x != 0, then the bit is set \n" + "# t.x = (t.x == 0 ? 1 : 0) \n" + "SGE t.x, -t.x, parm.z; \n" + "KIL -t.x; \n" + "# for debug only \n" + "#MOV result.color, t.x; \n" + "END \n"; + char program2[1000]; + struct drawpix_state *drawpix = &ctx->Meta->DrawPix; + struct temp_texture *tex = get_temp_texture(ctx); + const char *texTarget; + + assert(drawpix->StencilFP == 0); + + /* replace %s with "RECT" or "2D" */ + assert(strlen(program) + 4 < sizeof(program2)); + if (tex->Target == GL_TEXTURE_RECTANGLE) + texTarget = "RECT"; + else + texTarget = "2D"; + _mesa_snprintf(program2, sizeof(program2), program, texTarget); + + _mesa_GenPrograms(1, &drawpix->StencilFP); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program2), (const GLubyte *) program2); +} + + +/** + * One-time init for drawing depth pixels. + */ +static void +init_draw_depth_pixels(GLcontext *ctx) +{ + static const char *program = + "!!ARBfp1.0\n" + "PARAM color = program.local[0]; \n" + "TEX result.depth, fragment.texcoord[0], texture[0], %s; \n" + "MOV result.color, color; \n" + "END \n"; + char program2[200]; + struct drawpix_state *drawpix = &ctx->Meta->DrawPix; + struct temp_texture *tex = get_temp_texture(ctx); + const char *texTarget; + + assert(drawpix->DepthFP == 0); + + /* replace %s with "RECT" or "2D" */ + assert(strlen(program) + 4 < sizeof(program2)); + if (tex->Target == GL_TEXTURE_RECTANGLE) + texTarget = "RECT"; + else + texTarget = "2D"; + _mesa_snprintf(program2, sizeof(program2), program, texTarget); + + _mesa_GenPrograms(1, &drawpix->DepthFP); + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); + _mesa_ProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, + strlen(program2), (const GLubyte *) program2); +} + + +/** * Meta implementation of ctx->Driver.DrawPixels() in terms * of texture mapping and polygon rendering. */ @@ -1248,8 +1495,11 @@ _mesa_meta_draw_pixels(GLcontext *ctx, struct drawpix_state *drawpix = &ctx->Meta->DrawPix; struct temp_texture *tex = get_temp_texture(ctx); const struct gl_pixelstore_attrib unpackSave = ctx->Unpack; + const GLuint origStencilMask = ctx->Stencil.WriteMask[0]; + GLfloat verts[4][5]; /* four verts of X,Y,Z,S,T */ GLenum texIntFormat; GLboolean fallback, newTex; + GLbitfield metaExtraSave = 0x0; /* * Determine if we can do the glDrawPixels with texture mapping. @@ -1261,7 +1511,43 @@ _mesa_meta_draw_pixels(GLcontext *ctx, } if (_mesa_is_color_format(format)) { - texIntFormat = GL_RGBA; + /* use more compact format when possible */ + /* XXX disable special case for GL_LUMINANCE for now to work around + * apparent i965 driver bug (see bug #23670). + */ + if (/*format == GL_LUMINANCE ||*/ format == GL_LUMINANCE_ALPHA) + texIntFormat = format; + else + texIntFormat = GL_RGBA; + } + else if (_mesa_is_stencil_format(format)) { + if (ctx->Extensions.ARB_fragment_program && + ctx->Pixel.IndexShift == 0 && + ctx->Pixel.IndexOffset == 0 && + type == GL_UNSIGNED_BYTE) { + /* We'll store stencil as alpha. This only works for GLubyte + * image data because of how incoming values are mapped to alpha + * in [0,1]. + */ + texIntFormat = GL_ALPHA; + metaExtraSave = (META_COLOR_MASK | + META_DEPTH_TEST | + META_SHADER | + META_STENCIL_TEST); + } + else { + fallback = GL_TRUE; + } + } + else if (_mesa_is_depth_format(format)) { + if (ctx->Extensions.ARB_depth_texture && + ctx->Extensions.ARB_fragment_program) { + texIntFormat = GL_DEPTH_COMPONENT; + metaExtraSave = (META_SHADER); + } + else { + fallback = GL_TRUE; + } } else { fallback = GL_TRUE; @@ -1290,7 +1576,8 @@ _mesa_meta_draw_pixels(GLcontext *ctx, META_TEXTURE | META_TRANSFORM | META_VERTEX | - META_VIEWPORT)); + META_VIEWPORT | + metaExtraSave)); if (drawpix->ArrayObj == 0) { /* one-time setup */ @@ -1302,13 +1589,13 @@ _mesa_meta_draw_pixels(GLcontext *ctx, /* create vertex array buffer */ _mesa_GenBuffersARB(1, &drawpix->VBO); _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, drawpix->VBO); - _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(drawpix->verts), - drawpix->verts, GL_STREAM_DRAW_ARB); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); /* setup vertex arrays */ - _mesa_VertexPointer(3, GL_FLOAT, sizeof(drawpix->verts[0]), - (void*) (0 * sizeof(GLfloat))); - _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(drawpix->verts[0]), + _mesa_VertexPointer(3, GL_FLOAT, sizeof(verts[0]), + (void *) (0 * sizeof(GLfloat))); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(verts[0]), (void *) (3 * sizeof(GLfloat))); _mesa_EnableClientState(GL_VERTEX_ARRAY); _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -1328,47 +1615,415 @@ _mesa_meta_draw_pixels(GLcontext *ctx, const GLfloat y1 = y + height * ctx->Pixel.ZoomY; const GLfloat z = ctx->Current.RasterPos[2]; - drawpix->verts[0][0] = x0; - drawpix->verts[0][1] = y0; - drawpix->verts[0][2] = z; - drawpix->verts[0][3] = 0.0F; - drawpix->verts[0][4] = 0.0F; - drawpix->verts[1][0] = x1; - drawpix->verts[1][1] = y0; - drawpix->verts[1][2] = z; - drawpix->verts[1][3] = tex->Sright; - drawpix->verts[1][4] = 0.0F; - drawpix->verts[2][0] = x1; - drawpix->verts[2][1] = y1; - drawpix->verts[2][2] = z; - drawpix->verts[2][3] = tex->Sright; - drawpix->verts[2][4] = tex->Ttop; - drawpix->verts[3][0] = x0; - drawpix->verts[3][1] = y1; - drawpix->verts[3][2] = z; - drawpix->verts[3][3] = 0.0F; - drawpix->verts[3][4] = tex->Ttop; + verts[0][0] = x0; + verts[0][1] = y0; + verts[0][2] = z; + verts[0][3] = 0.0F; + verts[0][4] = 0.0F; + verts[1][0] = x1; + verts[1][1] = y0; + verts[1][2] = z; + verts[1][3] = tex->Sright; + verts[1][4] = 0.0F; + verts[2][0] = x1; + verts[2][1] = y1; + verts[2][2] = z; + verts[2][3] = tex->Sright; + verts[2][4] = tex->Ttop; + verts[3][0] = x0; + verts[3][1] = y1; + verts[3][2] = z; + verts[3][3] = 0.0F; + verts[3][4] = tex->Ttop; /* upload new vertex data */ - _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, - sizeof(drawpix->verts), drawpix->verts); + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); } /* set given unpack params */ ctx->Unpack = *unpack; - setup_drawpix_texture(tex, newTex, texIntFormat, width, height, - format, type, pixels); + _mesa_set_enable(ctx, tex->Target, GL_TRUE); + + if (_mesa_is_stencil_format(format)) { + /* Drawing stencil */ + GLint bit; + + if (!drawpix->StencilFP) + init_draw_stencil_pixels(ctx); + + setup_drawpix_texture(tex, newTex, texIntFormat, width, height, + GL_ALPHA, type, pixels); + + _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE); + + /* set all stencil bits to 0 */ + _mesa_StencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + _mesa_StencilFunc(GL_ALWAYS, 0, 255); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + /* set stencil bits to 1 where needed */ + _mesa_StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->StencilFP); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + + for (bit = 0; bit < ctx->Visual.stencilBits; bit++) { + const GLuint mask = 1 << bit; + if (mask & origStencilMask) { + _mesa_StencilFunc(GL_ALWAYS, mask, mask); + _mesa_StencilMask(mask); + + _mesa_ProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, + 255.0 / mask, 0.5, 0.0, 0.0); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + } + } + else if (_mesa_is_depth_format(format)) { + /* Drawing depth */ + if (!drawpix->DepthFP) + init_draw_depth_pixels(ctx); + + _mesa_BindProgram(GL_FRAGMENT_PROGRAM_ARB, drawpix->DepthFP); + _mesa_set_enable(ctx, GL_FRAGMENT_PROGRAM_ARB, GL_TRUE); + + /* polygon color = current raster color */ + _mesa_ProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, + ctx->Current.RasterColor); + + setup_drawpix_texture(tex, newTex, texIntFormat, width, height, + format, type, pixels); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + else { + /* Drawing RGBA */ + setup_drawpix_texture(tex, newTex, texIntFormat, width, height, + format, type, pixels); + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + _mesa_set_enable(ctx, tex->Target, GL_FALSE); /* restore unpack params */ ctx->Unpack = unpackSave; - _mesa_Enable(tex->Target); + _mesa_meta_end(ctx); +} - /* draw textured quad */ - _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - _mesa_Disable(tex->Target); +/** + * Do glBitmap with a alpha texture quad. Use the alpha test to + * cull the 'off' bits. If alpha test is already enabled, fall back + * to swrast (should be a rare case). + * A bitmap cache as in the gallium/mesa state tracker would + * improve performance a lot. + */ +void +_mesa_meta_bitmap(GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap1) +{ + struct bitmap_state *bitmap = &ctx->Meta->Bitmap; + struct temp_texture *tex = get_bitmap_temp_texture(ctx); + const GLenum texIntFormat = GL_ALPHA; + const struct gl_pixelstore_attrib unpackSave = *unpack; + GLfloat verts[4][9]; /* four verts of X,Y,Z,S,T,R,G,B,A */ + GLboolean newTex; + GLubyte *bitmap8; + + /* + * Check if swrast fallback is needed. + */ + if (ctx->_ImageTransferState || + ctx->Color.AlphaEnabled || + ctx->Fog.Enabled || + ctx->Texture._EnabledUnits || + width > tex->MaxSize || + height > tex->MaxSize) { + _swrast_Bitmap(ctx, x, y, width, height, unpack, bitmap1); + return; + } + + /* Most GL state applies to glBitmap (like blending, stencil, etc), + * but a there's a few things we need to override: + */ + _mesa_meta_begin(ctx, (META_ALPHA_TEST | + META_PIXEL_STORE | + META_RASTERIZATION | + META_SHADER | + META_TEXTURE | + META_TRANSFORM | + META_VERTEX | + META_VIEWPORT)); + + if (bitmap->ArrayObj == 0) { + /* one-time setup */ + + /* create vertex array object */ + _mesa_GenVertexArraysAPPLE(1, &bitmap->ArrayObj); + _mesa_BindVertexArrayAPPLE(bitmap->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &bitmap->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, bitmap->VBO); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); + + /* setup vertex arrays */ + _mesa_VertexPointer(3, GL_FLOAT, sizeof(verts[0]), + (void *) (0 * sizeof(GLfloat))); + _mesa_TexCoordPointer(2, GL_FLOAT, sizeof(verts[0]), + (void *) (3 * sizeof(GLfloat))); + _mesa_ColorPointer(4, GL_FLOAT, sizeof(verts[0]), + (void *) (5 * sizeof(GLfloat))); + + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + _mesa_EnableClientState(GL_COLOR_ARRAY); + } + else { + _mesa_BindVertexArray(bitmap->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, bitmap->VBO); + } + + newTex = alloc_texture(tex, width, height, texIntFormat); + + /* vertex positions, texcoords, colors (after texture allocation!) */ + { + const GLfloat x0 = (GLfloat) x; + const GLfloat y0 = (GLfloat) y; + const GLfloat x1 = (GLfloat) (x + width); + const GLfloat y1 = (GLfloat) (y + height); + const GLfloat z = ctx->Current.RasterPos[2]; + GLuint i; + + verts[0][0] = x0; + verts[0][1] = y0; + verts[0][2] = z; + verts[0][3] = 0.0F; + verts[0][4] = 0.0F; + verts[1][0] = x1; + verts[1][1] = y0; + verts[1][2] = z; + verts[1][3] = tex->Sright; + verts[1][4] = 0.0F; + verts[2][0] = x1; + verts[2][1] = y1; + verts[2][2] = z; + verts[2][3] = tex->Sright; + verts[2][4] = tex->Ttop; + verts[3][0] = x0; + verts[3][1] = y1; + verts[3][2] = z; + verts[3][3] = 0.0F; + verts[3][4] = tex->Ttop; + + for (i = 0; i < 4; i++) { + verts[i][5] = ctx->Current.RasterColor[0]; + verts[i][6] = ctx->Current.RasterColor[1]; + verts[i][7] = ctx->Current.RasterColor[2]; + verts[i][8] = ctx->Current.RasterColor[3]; + } + + /* upload new vertex data */ + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + bitmap1 = _mesa_map_pbo_source(ctx, &unpackSave, bitmap1); + if (!bitmap1) + return; + + bitmap8 = (GLubyte *) _mesa_calloc(width * height); + if (bitmap8) { + _mesa_expand_bitmap(width, height, &unpackSave, bitmap1, + bitmap8, width, 0xff); + + _mesa_set_enable(ctx, tex->Target, GL_TRUE); + + _mesa_set_enable(ctx, GL_ALPHA_TEST, GL_TRUE); + _mesa_AlphaFunc(GL_GREATER, 0.0); + + setup_drawpix_texture(tex, newTex, texIntFormat, width, height, + GL_ALPHA, GL_UNSIGNED_BYTE, bitmap8); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + _mesa_set_enable(ctx, tex->Target, GL_FALSE); + + _mesa_free(bitmap8); + } + + _mesa_unmap_pbo_source(ctx, &unpackSave); _mesa_meta_end(ctx); } + + +void +_mesa_meta_generate_mipmap(GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; + struct { GLfloat x, y, s, t, r; } verts[4]; + const GLuint baseLevel = texObj->BaseLevel; + const GLuint maxLevel = texObj->MaxLevel; + const GLenum minFilterSave = texObj->MinFilter; + const GLenum magFilterSave = texObj->MagFilter; + const GLuint fboSave = ctx->DrawBuffer->Name; + GLenum faceTarget; + GLuint level; + GLuint border = 0; + + /* check for fallbacks */ + if (!ctx->Extensions.EXT_framebuffer_object) { + _mesa_generate_mipmap(ctx, target, texObj); + return; + } + + if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && + target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { + faceTarget = target; + target = GL_TEXTURE_CUBE_MAP; + } + else { + faceTarget = target; + } + + _mesa_meta_begin(ctx, META_ALL); + + if (mipmap->ArrayObj == 0) { + /* one-time setup */ + + /* create vertex array object */ + _mesa_GenVertexArraysAPPLE(1, &mipmap->ArrayObj); + _mesa_BindVertexArrayAPPLE(mipmap->ArrayObj); + + /* create vertex array buffer */ + _mesa_GenBuffersARB(1, &mipmap->VBO); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); + _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), + NULL, GL_DYNAMIC_DRAW_ARB); + + /* setup vertex arrays */ + _mesa_VertexPointer(2, GL_FLOAT, sizeof(verts[0]), + (void *) (0 * sizeof(GLfloat))); + _mesa_TexCoordPointer(3, GL_FLOAT, sizeof(verts[0]), + (void *) (2 * sizeof(GLfloat))); + + _mesa_EnableClientState(GL_VERTEX_ARRAY); + _mesa_EnableClientState(GL_TEXTURE_COORD_ARRAY); + } + else { + _mesa_BindVertexArray(mipmap->ArrayObj); + _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, mipmap->VBO); + } + + if (!mipmap->FBO) { + /* Bind the new renderbuffer to the color attachment point. */ + _mesa_GenFramebuffersEXT(1, &mipmap->FBO); + } + + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mipmap->FBO); + + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + _mesa_set_enable(ctx, target, GL_TRUE); + + /* setup texcoords once (XXX what about border?) */ + switch (faceTarget) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + break; + case GL_TEXTURE_2D: + verts[0].s = 0.0F; + verts[0].t = 0.0F; + verts[0].r = 0.0F; + verts[1].s = 1.0F; + verts[1].t = 0.0F; + verts[1].r = 0.0F; + verts[2].s = 1.0F; + verts[2].t = 1.0F; + verts[2].r = 0.0F; + verts[3].s = 0.0F; + verts[3].t = 1.0F; + verts[3].r = 0.0F; + break; + } + + + for (level = baseLevel + 1; level <= maxLevel; level++) { + const struct gl_texture_image *srcImage; + const GLuint srcLevel = level - 1; + GLsizei srcWidth, srcHeight; + GLsizei newWidth, newHeight; + GLenum status; + + srcImage = _mesa_select_tex_image(ctx, texObj, target, srcLevel); + assert(srcImage->Border == 0); /* XXX we can fix this */ + + srcWidth = srcImage->Width - 2 * border; + srcHeight = srcImage->Height - 2 * border; + + newWidth = MAX2(1, srcWidth / 2) + 2 * border; + newHeight = MAX2(1, srcHeight / 2) + 2 * border; + + if (newWidth == srcImage->Width && newHeight == srcImage->Height) { + break; + } + + /* Create empty image */ + _mesa_TexImage2D(GL_TEXTURE_2D, level, srcImage->InternalFormat, + newWidth, newHeight, border, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + /* vertex positions */ + { + verts[0].x = 0.0F; + verts[0].y = 0.0F; + verts[1].x = (GLfloat) newWidth; + verts[1].y = 0.0F; + verts[2].x = (GLfloat) newWidth; + verts[2].y = (GLfloat) newHeight; + verts[3].x = 0.0F; + verts[3].y = (GLfloat) newHeight; + + /* upload new vertex data */ + _mesa_BufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts); + } + + /* limit sampling to src level */ + _mesa_TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, srcLevel); + _mesa_TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, srcLevel); + + /* Set to draw into the current level */ + _mesa_FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + target, + texObj->Name, + level); + + /* Choose to render to the color attachment. */ + _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + status = _mesa_CheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + abort(); + break; + } + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + _mesa_meta_end(ctx); + + _mesa_TexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilterSave); + _mesa_TexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilterSave); + + /* restore (XXX add to meta_begin/end()? */ + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboSave); +} |