X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fintel%2Fintel_pixel_draw.c;h=8ebbc95a1d0ba1c0e5e9e32eb103238464ed49d3;hb=9053bb0d405db0b1a2a917317c7ec41e63b54f09;hp=0ddc3aa30d8be11c516c6bc298bada9b2a89ad0b;hpb=f85ea6837da434cdec011de431e62db20ee39df2;p=mesa.git diff --git a/src/mesa/drivers/dri/intel/intel_pixel_draw.c b/src/mesa/drivers/dri/intel/intel_pixel_draw.c index 0ddc3aa30d8..a6b6824164a 100644 --- a/src/mesa/drivers/dri/intel/intel_pixel_draw.c +++ b/src/mesa/drivers/dri/intel/intel_pixel_draw.c @@ -32,12 +32,20 @@ #include "main/macros.h" #include "main/bufferobj.h" #include "main/teximage.h" +#include "main/texenv.h" #include "main/texobj.h" #include "main/texstate.h" -#include "main/matrix.h" +#include "main/texparam.h" #include "main/varray.h" #include "main/attrib.h" #include "main/enable.h" +#include "main/buffers.h" +#include "main/fbobject.h" +#include "main/renderbuffer.h" +#include "main/depth.h" +#include "main/hash.h" +#include "main/blend.h" +#include "main/viewport.h" #include "glapi/dispatch.h" #include "swrast/swrast.h" @@ -49,8 +57,7 @@ #include "intel_regions.h" #include "intel_pixel.h" #include "intel_buffer_objects.h" -#include "intel_tris.h" - +#include "intel_fbo.h" static GLboolean intel_texture_drawpixels(GLcontext * ctx, @@ -61,47 +68,74 @@ intel_texture_drawpixels(GLcontext * ctx, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { + struct intel_context *intel = intel_context(ctx); GLuint texname; GLfloat vertices[4][4]; - GLfloat texcoords[4][2]; + GLfloat z; + GLint old_active_texture; + GLenum internalFormat; /* 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 (ctx->Texture._EnabledUnits != 0) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "glDrawPixels() 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) - return GL_FALSE; - - /* Don't even want to think about it */ - if (format == GL_COLOR_INDEX) + if (ctx->FragmentProgram.Enabled) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "glDrawPixels() fallback: fragment program enabled\n"); return GL_FALSE; + } - /* We don't have a way to generate fragments with stencil values which * + /* We don't have a way to generate fragments with stencil values which * will set the resulting stencil value. */ - if (format == GL_STENCIL_INDEX) + if (format == GL_STENCIL_INDEX || format == GL_DEPTH_STENCIL) 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, "glDrawPixels() fallback: bitmap too large (%dx%d)\n", + width, height); + return GL_FALSE; + } + /* To do DEPTH_COMPONENT, we would need to change our setup to not draw to * the color buffer, and sample the texture values into the fragment depth * in a program. */ - if (format == GL_DEPTH_COMPONENT) + if (format == GL_DEPTH_COMPONENT) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, + "glDrawPixels() fallback: format == GL_DEPTH_COMPONENT\n"); + return GL_FALSE; + } + + if (!ctx->Extensions.ARB_texture_non_power_of_two && + (!is_power_of_two(width) || !is_power_of_two(height))) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, + "glDrawPixels() fallback: NPOT texture\n"); return GL_FALSE; + } - _mesa_PushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_TEXTURE_BIT | - GL_CURRENT_BIT); + _mesa_PushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | + GL_CURRENT_BIT | GL_VIEWPORT_BIT); _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); /* XXX: pixel store stuff */ _mesa_Disable(GL_POLYGON_STIPPLE); + old_active_texture = ctx->Texture.CurrentUnit; _mesa_ActiveTextureARB(GL_TEXTURE0_ARB); _mesa_Enable(GL_TEXTURE_2D); _mesa_GenTextures(1, &texname); @@ -109,58 +143,53 @@ intel_texture_drawpixels(GLcontext * ctx, _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); _mesa_TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); _mesa_TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - /* - _mesa_TexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - _mesa_TexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - */ - _mesa_TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, + if (type == GL_ALPHA) + internalFormat = GL_ALPHA; + else + internalFormat = GL_RGBA; + _mesa_TexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, pixels); - _mesa_MatrixMode(GL_PROJECTION); - _mesa_PushMatrix(); - _mesa_LoadIdentity(); - _mesa_Ortho(0, ctx->DrawBuffer->Width, 0, ctx->DrawBuffer->Height, 1, -1); + meta_set_passthrough_transform(&intel->meta); + + /* convert rasterpos Z from [0,1] to NDC coord in [-1,1] */ + z = -1.0 + 2.0 * ctx->Current.RasterPos[2]; - _mesa_MatrixMode(GL_MODELVIEW); - _mesa_PushMatrix(); - _mesa_LoadIdentity(); + /* RasterPos[2] already takes into account the DepthRange mapping. */ + _mesa_DepthRange(0.0, 1.0); + /* Create the vertex buffer based on the current raster pos. The x and y + * we're handed are ctx->Current.RasterPos[0,1] rounded to integers. + * We also apply the depth. However, the W component is already multiplied + * into ctx->Current.RasterPos[0,1,2] and we can ignore it at this point. + */ vertices[0][0] = x; vertices[0][1] = y; - vertices[0][2] = ctx->Current.RasterPos[2]; - vertices[0][3] = ctx->Current.RasterPos[3]; + vertices[0][2] = z; + vertices[0][3] = 1.0; vertices[1][0] = x + width * ctx->Pixel.ZoomX; vertices[1][1] = y; - vertices[1][2] = ctx->Current.RasterPos[2]; - vertices[1][3] = ctx->Current.RasterPos[3]; + vertices[1][2] = z; + vertices[1][3] = 1.0; vertices[2][0] = x + width * ctx->Pixel.ZoomX; vertices[2][1] = y + height * ctx->Pixel.ZoomY; - vertices[2][2] = ctx->Current.RasterPos[2]; - vertices[2][3] = ctx->Current.RasterPos[3]; + vertices[2][2] = z; + vertices[2][3] = 1.0; vertices[3][0] = x; vertices[3][1] = y + height * ctx->Pixel.ZoomY; - vertices[3][2] = ctx->Current.RasterPos[2]; - vertices[3][3] = ctx->Current.RasterPos[3]; - - 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; + vertices[3][2] = z; + vertices[3][3] = 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)); + meta_set_default_texrect(&intel->meta); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); - _mesa_MatrixMode(GL_PROJECTION); - _mesa_PopMatrix(); - _mesa_MatrixMode(GL_MODELVIEW); - _mesa_PopMatrix(); + meta_restore_texcoords(&intel->meta); + meta_restore_transform(&intel->meta); + + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture); _mesa_PopClientAttrib(); _mesa_PopAttrib(); @@ -169,6 +198,203 @@ intel_texture_drawpixels(GLcontext * ctx, return GL_TRUE; } +static GLboolean +intel_stencil_drawpixels(GLcontext * ctx, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, + GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct intel_context *intel = intel_context(ctx); + GLuint texname, rb_name, fb_name, old_fb_name; + GLfloat vertices[4][2]; + struct intel_renderbuffer *irb; + struct intel_renderbuffer *depth_irb; + struct gl_renderbuffer *rb; + struct gl_pixelstore_attrib old_unpack; + GLstencil *stencil_pixels; + int row, y1, y2; + GLint old_active_texture; + GLboolean rendering_to_fbo = ctx->DrawBuffer->Name != 0; + + if (format != GL_STENCIL_INDEX) + return GL_FALSE; + + /* If there's nothing to write, we're done. */ + if (ctx->Stencil.WriteMask[0] == 0) + return GL_TRUE; + + /* Can't do a per-bit writemask while treating stencil as rgba data. */ + if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "glDrawPixels(STENCIL_INDEX) fallback: " + "stencil mask enabled\n"); + return GL_FALSE; + } + + /* We don't support stencil testing/ops here */ + if (ctx->Stencil._Enabled) + return GL_FALSE; + + /* We use FBOs for our wrapping of the depthbuffer into a color + * destination. + */ + if (!ctx->Extensions.EXT_framebuffer_object) + 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, "glDrawPixels(STENCIL_INDEX) 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, "glDrawPixels(STENCIL_INDEX) fallback: " + "fragment 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, "glDrawPixels(STENCIL_INDEX) fallback: " + "bitmap too large (%dx%d)\n", + width, height); + return GL_FALSE; + } + + if (!ctx->Extensions.ARB_texture_non_power_of_two && + (!is_power_of_two(width) || !is_power_of_two(height))) { + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, + "glDrawPixels(GL_STENCIL_INDEX) fallback: NPOT texture\n"); + return GL_FALSE; + } + + _mesa_PushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | + GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + _mesa_PushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); + old_fb_name = ctx->DrawBuffer->Name; + old_active_texture = ctx->Texture.CurrentUnit; + + _mesa_Disable(GL_POLYGON_STIPPLE); + _mesa_Disable(GL_DEPTH_TEST); + _mesa_Disable(GL_STENCIL_TEST); + + /* Unpack the supplied stencil values into a ubyte buffer. */ + assert(sizeof(GLstencil) == sizeof(GLubyte)); + stencil_pixels = _mesa_malloc(width * height * sizeof(GLstencil)); + for (row = 0; row < height; row++) { + GLvoid *source = _mesa_image_address2d(unpack, pixels, + width, height, + GL_COLOR_INDEX, type, + row, 0); + _mesa_unpack_stencil_span(ctx, width, GL_UNSIGNED_BYTE, + stencil_pixels + + row * width * sizeof(GLstencil), + type, source, unpack, ctx->_ImageTransferState); + } + + /* Take the current depth/stencil renderbuffer, and make a new one wrapping + * it which will be treated as GL_RGBA8 so we can render to it as a color + * buffer. + */ + depth_irb = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_DEPTH); + irb = intel_create_renderbuffer(GL_RGBA8); + rb = &irb->Base; + irb->Base.Width = depth_irb->Base.Width; + irb->Base.Height = depth_irb->Base.Height; + intel_renderbuffer_set_region(irb, depth_irb->region); + + /* Create a name for our renderbuffer, which lets us use other mesa + * rb functions for convenience. + */ + _mesa_GenRenderbuffersEXT(1, &rb_name); + irb->Base.RefCount++; + _mesa_HashInsert(ctx->Shared->RenderBuffers, rb_name, &irb->Base); + + /* Bind the new renderbuffer to the color attachment point. */ + _mesa_GenFramebuffersEXT(1, &fb_name); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb_name); + _mesa_FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, + rb_name); + /* Choose to render to the color attachment. */ + _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + _mesa_DepthMask(GL_FALSE); + _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); + + _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_TexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + old_unpack = ctx->Unpack; + ctx->Unpack = ctx->DefaultPacking; + _mesa_TexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, width, height, 0, + GL_RED, GL_UNSIGNED_BYTE, stencil_pixels); + ctx->Unpack = old_unpack; + _mesa_free(stencil_pixels); + + meta_set_passthrough_transform(&intel->meta); + + /* Since we're rendering to the framebuffer as if it was an FBO, + * if it's the window system we have to flip the coordinates. + */ + if (rendering_to_fbo) { + y1 = y; + y2 = y + height * ctx->Pixel.ZoomY; + } else { + y1 = irb->Base.Height - (y + height * ctx->Pixel.ZoomY); + y2 = irb->Base.Height - y; + } + vertices[0][0] = x; + vertices[0][1] = y1; + vertices[1][0] = x + width * ctx->Pixel.ZoomX; + vertices[1][1] = y1; + vertices[2][0] = x + width * ctx->Pixel.ZoomX; + vertices[2][1] = y2; + vertices[3][0] = x; + vertices[3][1] = y2; + + _mesa_VertexPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), &vertices); + _mesa_Enable(GL_VERTEX_ARRAY); + meta_set_default_texrect(&intel->meta); + + _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4); + + meta_restore_texcoords(&intel->meta); + meta_restore_transform(&intel->meta); + + _mesa_ActiveTextureARB(GL_TEXTURE0_ARB + old_active_texture); + _mesa_BindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fb_name); + + _mesa_PopClientAttrib(); + _mesa_PopAttrib(); + + _mesa_DeleteTextures(1, &texname); + _mesa_DeleteFramebuffersEXT(1, &fb_name); + _mesa_DeleteRenderbuffersEXT(1, &rb_name); + + return GL_TRUE; +} + void intelDrawPixels(GLcontext * ctx, GLint x, GLint y, @@ -182,30 +408,13 @@ intelDrawPixels(GLcontext * ctx, unpack, pixels)) return; + if (intel_stencil_drawpixels(ctx, x, y, width, height, format, type, + unpack, pixels)) + return; + if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s: fallback to swrast\n", __FUNCTION__); - if (ctx->FragmentProgram._Current == ctx->FragmentProgram._TexEnvProgram) { - /* - * We don't want the i915 texenv program to be applied to DrawPixels. - * This is really just a performance optimization (mesa will other- - * wise happily run the fragment program on each pixel in the image). - */ - struct gl_fragment_program *fpSave = ctx->FragmentProgram._Current; - /* can't just set current frag prog to 0 here as on buffer resize - we'll get new state checks which will segfault. Remains a hack. */ - ctx->FragmentProgram._Current = NULL; - ctx->FragmentProgram._UseTexEnvProgram = GL_FALSE; - ctx->FragmentProgram._Active = GL_FALSE; - _swrast_DrawPixels( ctx, x, y, width, height, format, type, - unpack, pixels ); - ctx->FragmentProgram._Current = fpSave; - ctx->FragmentProgram._UseTexEnvProgram = GL_TRUE; - ctx->FragmentProgram._Active = GL_TRUE; - _swrast_InvalidateState(ctx, _NEW_PROGRAM); - } - else { - _swrast_DrawPixels( ctx, x, y, width, height, format, type, - unpack, pixels ); - } + _swrast_DrawPixels(ctx, x, y, width, height, format, type, + unpack, pixels); }