X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fdrawpix.c;h=63e5870e6870eec243741fa29529aee21d0f9bdf;hb=f10f5b88224ba82310fc71f9a73ae118bf28be2d;hp=13cfa0e756e28d2573c6c3e5c71530731fd47f5a;hpb=205e0e3e38b99c2fb0298755d99a38f111f0b96f;p=mesa.git diff --git a/src/mesa/main/drawpix.c b/src/mesa/main/drawpix.c index 13cfa0e756e..63e5870e687 100644 --- a/src/mesa/main/drawpix.c +++ b/src/mesa/main/drawpix.c @@ -1,6 +1,5 @@ /* * Mesa 3-D graphics library - * Version: 7.1 * * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. * @@ -17,9 +16,10 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ #include "glheader.h" @@ -27,15 +27,17 @@ #include "bufferobj.h" #include "context.h" #include "drawpix.h" +#include "enums.h" #include "feedback.h" #include "framebuffer.h" #include "image.h" -#include "readpix.h" +#include "pbo.h" #include "state.h" +#include "dispatch.h" +#include "glformats.h" +#include "fbobject.h" -#if _HAVE_FULL_GL - /* * Execute glDrawPixels */ @@ -43,77 +45,144 @@ void GLAPIENTRY _mesa_DrawPixels( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) { + GLenum err; GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (width < 0 || height < 0) { - _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0" ); - return; - } + FLUSH_VERTICES(ctx, 0); - if (ctx->NewState) { - _mesa_update_state(ctx); - } + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glDrawPixels(%d, %d, %s, %s, %p) // to %s at %d, %d\n", + width, height, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type), + pixels, + _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), + IROUND(ctx->Current.RasterPos[0]), + IROUND(ctx->Current.RasterPos[1])); - if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawPixels (invalid fragment program)"); + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0)" ); return; } - if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { - /* found an error */ - return; + /* We're not using the current vertex program, and the driver may install + * its own. Note: this may dirty some state. + */ + _mesa_set_vp_override(ctx, GL_TRUE); + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glDrawPixels")) { + goto end; /* the error code was recorded */ + } + + /* GL 3.0 introduced a new restriction on glDrawPixels() over what was in + * GL_EXT_texture_integer. From section 3.7.4 ("Rasterization of Pixel + * Rectangles) on page 151 of the GL 3.0 specification: + * + * "If format contains integer components, as shown in table 3.6, an + * INVALID OPERATION error is generated." + * + * Since DrawPixels rendering would be merely undefined if not an error (due + * to a lack of defined mapping from integer data to gl_Color fragment shader + * input), NVIDIA's implementation also just returns this error despite + * exposing GL_EXT_texture_integer, just return an error regardless. + */ + if (_mesa_is_enum_format_integer(format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(integer format)"); + goto end; + } + + err = _mesa_error_check_format_and_type(ctx, format, type); + if (err != GL_NO_ERROR) { + _mesa_error(ctx, err, "glDrawPixels(invalid format %s and/or type %s)", + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type)); + goto end; + } + + /* do special format-related checks */ + switch (format) { + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL_EXT: + /* these buffers must exist */ + if (!_mesa_dest_buffer_exists(ctx, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(missing deest buffer)"); + goto end; + } + break; + case GL_COLOR_INDEX: + if (ctx->PixelMaps.ItoR.Size == 0 || + ctx->PixelMaps.ItoG.Size == 0 || + ctx->PixelMaps.ItoB.Size == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(drawing color index pixels into RGB buffer)"); + goto end; + } + break; + default: + /* for color formats it's not an error if the destination color + * buffer doesn't exist. + */ + break; } - if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glDrawPixels(incomplete framebuffer)" ); - return; + if (ctx->RasterDiscard) { + goto end; } if (!ctx->Current.RasterPosValid) { - return; + goto end; /* no-op, not an error */ } if (ctx->RenderMode == GL_RENDER) { - /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ - GLint x = IROUND(ctx->Current.RasterPos[0]); - GLint y = IROUND(ctx->Current.RasterPos[1]); - - if (ctx->Unpack.BufferObj->Name) { - /* unpack from PBO */ - if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, - format, type, pixels)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawPixels(invalid PBO access)"); - return; + if (width > 0 && height > 0) { + /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ + GLint x = IROUND(ctx->Current.RasterPos[0]); + GLint y = IROUND(ctx->Current.RasterPos[1]); + + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + /* unpack from PBO */ + if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, + 1, format, type, INT_MAX, pixels)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(invalid PBO access)"); + goto end; + } + if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDrawPixels(PBO is mapped)"); + goto end; + } } - if (ctx->Unpack.BufferObj->Pointer) { - /* buffer is mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawPixels(PBO is mapped)"); - return; - } - } - ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, - &ctx->Unpack, pixels); + ctx->Driver.DrawPixels(ctx, x, y, width, height, format, type, + &ctx->Unpack, pixels); + } } else if (ctx->RenderMode == GL_FEEDBACK) { /* Feedback the current raster pos info */ FLUSH_CURRENT( ctx, 0 ); - FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); _mesa_feedback_vertex( ctx, ctx->Current.RasterPos, ctx->Current.RasterColor, - ctx->Current.RasterIndex, ctx->Current.RasterTexCoords[0] ); } else { ASSERT(ctx->RenderMode == GL_SELECT); /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ } + +end: + _mesa_set_vp_override(ctx, GL_FALSE); + + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { + _mesa_flush(ctx); + } } @@ -122,65 +191,105 @@ _mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLenum type ) { GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - if (ctx->NewState) { - _mesa_update_state(ctx); - } + FLUSH_VERTICES(ctx, 0); - if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyPixels (invalid fragment program)"); - return; - } + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glCopyPixels(%d, %d, %d, %d, %s) // from %s to %s at %d, %d\n", + srcx, srcy, width, height, + _mesa_lookup_enum_by_nr(type), + _mesa_lookup_enum_by_nr(ctx->ReadBuffer->ColorReadBuffer), + _mesa_lookup_enum_by_nr(ctx->DrawBuffer->ColorDrawBuffer[0]), + IROUND(ctx->Current.RasterPos[0]), + IROUND(ctx->Current.RasterPos[1])); if (width < 0 || height < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyPixels(width or height < 0)"); return; } - if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || - ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { + /* Note: more detailed 'type' checking is done by the + * _mesa_source/dest_buffer_exists() calls below. That's where we + * check if the stencil buffer exists, etc. + */ + if (type != GL_COLOR && + type != GL_DEPTH && + type != GL_STENCIL && + type != GL_DEPTH_STENCIL) { + _mesa_error(ctx, GL_INVALID_ENUM, "glCopyPixels(type=%s)", + _mesa_lookup_enum_by_nr(type)); + return; + } + + /* We're not using the current vertex program, and the driver may install + * it's own. Note: this may dirty some state. + */ + _mesa_set_vp_override(ctx, GL_TRUE); + + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glCopyPixels")) { + goto end; /* the error code was recorded */ + } + + /* Check read buffer's status (draw buffer was already checked) */ + if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glCopyPixels(incomplete framebuffer)" ); - return; + goto end; + } + + if (_mesa_is_user_fbo(ctx->ReadBuffer) && + ctx->ReadBuffer->Visual.samples > 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyPixels(multisample FBO)"); + goto end; } if (!_mesa_source_buffer_exists(ctx, type) || !_mesa_dest_buffer_exists(ctx, type)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyPixels(missing source or dest buffer)"); - return; + goto end; } - if (!ctx->Current.RasterPosValid || width ==0 || height == 0) { - return; + if (ctx->RasterDiscard) { + goto end; + } + + if (!ctx->Current.RasterPosValid || width == 0 || height == 0) { + goto end; /* no-op, not an error */ } if (ctx->RenderMode == GL_RENDER) { /* Round to satisfy conformance tests (matches SGI's OpenGL) */ - GLint destx = IROUND(ctx->Current.RasterPos[0]); - GLint desty = IROUND(ctx->Current.RasterPos[1]); - ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, - type ); + if (width > 0 && height > 0) { + GLint destx = IROUND(ctx->Current.RasterPos[0]); + GLint desty = IROUND(ctx->Current.RasterPos[1]); + ctx->Driver.CopyPixels( ctx, srcx, srcy, width, height, destx, desty, + type ); + } } else if (ctx->RenderMode == GL_FEEDBACK) { FLUSH_CURRENT( ctx, 0 ); - FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); _mesa_feedback_vertex( ctx, ctx->Current.RasterPos, ctx->Current.RasterColor, - ctx->Current.RasterIndex, ctx->Current.RasterTexCoords[0] ); } else { ASSERT(ctx->RenderMode == GL_SELECT); /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ } -} -#endif /* _HAVE_FULL_GL */ +end: + _mesa_set_vp_override(ctx, GL_FALSE); + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { + _mesa_flush(ctx); + } +} void GLAPIENTRY @@ -189,7 +298,8 @@ _mesa_Bitmap( GLsizei width, GLsizei height, const GLubyte *bitmap ) { GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + FLUSH_VERTICES(ctx, 0); if (width < 0 || height < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); @@ -200,128 +310,60 @@ _mesa_Bitmap( GLsizei width, GLsizei height, return; /* do nothing */ } - if (ctx->NewState) { - _mesa_update_state(ctx); - } - - if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBitmap (invalid fragment program)"); + /* Note: this call does state validation */ + if (!_mesa_valid_to_render(ctx, "glBitmap")) { + /* the error code was recorded */ return; } - if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glBitmap(incomplete framebuffer)"); + if (ctx->RasterDiscard) return; - } if (ctx->RenderMode == GL_RENDER) { /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ - const GLfloat epsilon = 0.0001F; - GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); - GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); - - if (ctx->Unpack.BufferObj->Name) { - /* unpack from PBO */ - if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1, - GL_COLOR_INDEX, GL_BITMAP, - (GLvoid *) bitmap)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBitmap(invalid PBO access)"); - return; - } - if (ctx->Unpack.BufferObj->Pointer) { - /* buffer is mapped - that's an error */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)"); - return; + if (width > 0 && height > 0) { + const GLfloat epsilon = 0.0001F; + GLint x = IFLOOR(ctx->Current.RasterPos[0] + epsilon - xorig); + GLint y = IFLOOR(ctx->Current.RasterPos[1] + epsilon - yorig); + + if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { + /* unpack from PBO */ + if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, + 1, GL_COLOR_INDEX, GL_BITMAP, + INT_MAX, (const GLvoid *) bitmap)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBitmap(invalid PBO access)"); + return; + } + if (_mesa_check_disallowed_mapping(ctx->Unpack.BufferObj)) { + /* buffer is mapped - that's an error */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBitmap(PBO is mapped)"); + return; + } } - } - ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); + ctx->Driver.Bitmap( ctx, x, y, width, height, &ctx->Unpack, bitmap ); + } } -#if _HAVE_FULL_GL else if (ctx->RenderMode == GL_FEEDBACK) { FLUSH_CURRENT(ctx, 0); - FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); + _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); _mesa_feedback_vertex( ctx, ctx->Current.RasterPos, ctx->Current.RasterColor, - ctx->Current.RasterIndex, ctx->Current.RasterTexCoords[0] ); } else { ASSERT(ctx->RenderMode == GL_SELECT); /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ } -#endif /* update raster position */ ctx->Current.RasterPos[0] += xmove; ctx->Current.RasterPos[1] += ymove; -} - - - -#if 0 /* experimental */ -/* - * Execute glDrawDepthPixelsMESA(). This function accepts both a color - * image and depth (Z) image. Rasterization produces fragments with - * color and Z taken from these images. This function is intended for - * Z-compositing. Normally, this operation requires two glDrawPixels - * calls with stencil testing. - */ -void GLAPIENTRY -_mesa_DrawDepthPixelsMESA( GLsizei width, GLsizei height, - GLenum colorFormat, GLenum colorType, - const GLvoid *colors, - GLenum depthType, const GLvoid *depths ) -{ - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); - - if (width < 0 || height < 0) { - _mesa_error( ctx, GL_INVALID_VALUE, - "glDrawDepthPixelsMESA(width or height < 0" ); - return; - } - - if (!ctx->Current.RasterPosValid) { - return; - } - - if (ctx->NewState) { - _mesa_update_state(ctx); - } - if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { - _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glDrawDepthPixelsMESA(incomplete framebuffer)"); - return; - } - - if (ctx->RenderMode == GL_RENDER) { - /* Round, to satisfy conformance tests (matches SGI's OpenGL) */ - GLint x = IROUND(ctx->Current.RasterPos[0]); - GLint y = IROUND(ctx->Current.RasterPos[1]); - ctx->Driver.DrawDepthPixelsMESA(ctx, x, y, width, height, - colorFormat, colorType, colors, - depthType, depths, &ctx->Unpack); - } - else if (ctx->RenderMode == GL_FEEDBACK) { - /* Feedback the current raster pos info */ - FLUSH_CURRENT( ctx, 0 ); - FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); - _mesa_feedback_vertex( ctx, - ctx->Current.RasterPos, - ctx->Current.RasterColor, - ctx->Current.RasterIndex, - ctx->Current.RasterTexCoords[0] ); - } - else { - ASSERT(ctx->RenderMode == GL_SELECT); - /* Do nothing. See OpenGL Spec, Appendix B, Corollary 6. */ + if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { + _mesa_flush(ctx); } } - -#endif