void GLAPIENTRY _mesa_GetPixelMapfv( GLenum map, GLfloat *values ) { GET_CURRENT_CONTEXT(ctx); GLuint mapsize, i; const struct gl_pixelmap *pm; ASSERT_OUTSIDE_BEGIN_END(ctx); pm = get_pixelmap(ctx, map); if (!pm) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapfv(map)"); return; } mapsize = pm->Size; if (ctx->Pack.BufferObj->Name) { /* pack pixelmap into PBO */ GLubyte *buf; /* Note, need to use DefaultPacking and Pack's buffer object */ ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj; if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, GL_INTENSITY, GL_FLOAT, values)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetPixelMapfv(invalid PBO access)"); return; } /* restore */ ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); if (!buf) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetPixelMapfv(PBO is mapped)"); return; } values = (GLfloat *) ADD_POINTERS(buf, values); } else if (!values) { return; } if (map == GL_PIXEL_MAP_S_TO_S) { /* special case */ for (i = 0; i < mapsize; i++) { values[i] = (GLfloat) ctx->PixelMaps.StoS.Map[i]; } } else { MEMCPY(values, pm->Map, mapsize * sizeof(GLfloat)); } if (ctx->Pack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, ctx->Pack.BufferObj); } }
/** * Convenience wrapper for _mesa_validate_pbo_access() for gl[Get]PixelMap(). */ static GLboolean validate_pbo_access(struct gl_context *ctx, struct gl_pixelstore_attrib *pack, GLsizei mapsize, GLenum format, GLenum type, GLsizei clientMemSize, const GLvoid *ptr) { GLboolean ok; /* Note, need to use DefaultPacking and Unpack's buffer object */ _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, pack->BufferObj); ok = _mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, format, type, clientMemSize, ptr); /* restore */ _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, ctx->Shared->NullBufferObj); if (!ok) { if (_mesa_is_bufferobj(pack->BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "gl[Get]PixelMap*v(out of bounds PBO access)"); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetnPixelMap*vARB(out of bounds access:" " bufSize (%d) is too small)", clientMemSize); } } return ok; }
/** * Check if an unpack PBO is active prior to fetching a texture image. * If so, do bounds checking and map the buffer into main memory. * Any errors detected will be recorded. * The caller _must_ call _mesa_unmap_teximage_pbo() too! */ const GLvoid * _mesa_validate_pbo_teximage(struct gl_context *ctx, GLuint dimensions, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels, const struct gl_pixelstore_attrib *unpack, const char *funcName) { GLubyte *buf; if (!_mesa_is_bufferobj(unpack->BufferObj)) { /* no PBO */ return pixels; } if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, format, type, INT_MAX, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(invalid PBO access)", funcName, dimensions); return NULL; } buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, unpack->BufferObj->Size, GL_MAP_READ_BIT, unpack->BufferObj, MAP_INTERNAL); if (!buf) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s%uD(PBO is mapped)", funcName, dimensions); return NULL; } return ADD_POINTERS(buf, pixels); }
/* Unlike the other intel_pixel_* functions, the expectation here is * that the incoming data is not in a PBO. With the XY_TEXT blit * method, there's no benefit haveing it in a PBO, but we could * implement a path based on XY_MONO_SRC_COPY_BLIT which might benefit * PBO bitmaps. I think they are probably pretty rare though - I * wonder if Xgl uses them? */ static const GLubyte *map_pbo( struct gl_context *ctx, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { GLubyte *buf; if (!_mesa_validate_pbo_access(2, 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 NULL; } buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, unpack->BufferObj->Size, GL_MAP_READ_BIT, unpack->BufferObj, MAP_INTERNAL); if (!buf) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)"); return NULL; } return ADD_POINTERS(buf, bitmap); }
/** * Convenience wrapper for _mesa_validate_pbo_access() for gl[Get]PixelMap(). */ static GLboolean validate_pbo_access(GLcontext *ctx, struct gl_pixelstore_attrib *pack, GLsizei mapsize, GLenum format, GLenum type, const GLvoid *ptr) { GLboolean ok; /* Note, need to use DefaultPacking and Unpack's buffer object */ _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, pack->BufferObj); ok = _mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, format, type, ptr); /* restore */ _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, ctx->Shared->NullBufferObj); if (!ok) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMap(invalid PBO access)"); } return ok; }
void GLAPIENTRY _mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); /* XXX someday, test against ctx->Const.MaxPixelMapTableSize */ if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); return; } if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { /* test that mapsize is a power of two */ if (_mesa_bitcount((GLuint) mapsize) != 1) { _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); return; } } FLUSH_VERTICES(ctx, _NEW_PIXEL); if (ctx->Unpack.BufferObj->Name) { /* unpack pixelmap from PBO */ GLubyte *buf; /* Note, need to use DefaultPacking and Unpack's buffer object */ ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj; if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, GL_INTENSITY, GL_FLOAT, values)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapfv(invalid PBO access)"); return; } /* restore */ ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, ctx->Unpack.BufferObj); if (!buf) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapfv(PBO is mapped)"); return; } values = (const GLfloat *) ADD_POINTERS(buf, values); } else if (!values) { return; } store_pixelmap(ctx, map, mapsize, values); if (ctx->Unpack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, ctx->Unpack.BufferObj); } }
void GLAPIENTRY _mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); FLUSH_CURRENT(ctx, 0); if (width < 0 || height < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glReadPixels(width=%d height=%d)", width, height ); return; } if (ctx->NewState) _mesa_update_state(ctx); if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) { /* found an error */ return; } if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glReadPixels(incomplete framebuffer)" ); return; } if (!_mesa_source_buffer_exists(ctx, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); return; } if (ctx->Pack.BufferObj->Name) { if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(invalid PBO access)"); return; } if (ctx->Pack.BufferObj->Pointer) { /* buffer is mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); return; } } ctx->Driver.ReadPixels(ctx, x, y, width, height, format, type, &ctx->Pack, pixels); }
/** * Perform PBO validation for read operations with uncompressed textures. * If any GL errors are detected, false is returned, otherwise returns true. * \sa _mesa_validate_pbo_access */ bool _mesa_validate_pbo_source(struct gl_context *ctx, GLuint dimensions, const struct gl_pixelstore_attrib *unpack, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei clientMemSize, const GLvoid *ptr, const char *where) { assert(dimensions == 1 || dimensions == 2 || dimensions == 3); if (!_mesa_validate_pbo_access(dimensions, unpack, width, height, depth, format, type, clientMemSize, ptr)) { if (_mesa_is_bufferobj(unpack->BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds PBO access)", where); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds access: bufSize (%d) is too small)", where, clientMemSize); } return false; } if (!_mesa_is_bufferobj(unpack->BufferObj)) { /* non-PBO access: no further validation to be done */ return true; } if (_mesa_check_disallowed_mapping(unpack->BufferObj)) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); return false; } return true; }
/* Unlike the other intel_pixel_* functions, the expectation here is * that the incoming data is not in a PBO. With the XY_TEXT blit * method, there's no benefit haveing it in a PBO, but we could * implement a path based on XY_MONO_SRC_COPY_BLIT which might benefit * PBO bitmaps. I think they are probably pretty rare though - I * wonder if Xgl uses them? */ static const GLubyte *map_pbo( GLcontext *ctx, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { GLubyte *buf; if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, GL_COLOR_INDEX, GL_BITMAP, (GLvoid *) bitmap)) { _mesa_error(ctx, GL_INVALID_OPERATION,"glBitmap(invalid PBO access)"); return NULL; } buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, unpack->BufferObj); if (!buf) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)"); return NULL; } return ADD_POINTERS(buf, bitmap); }
/* * Execute glDrawPixels */ static void GLAPIENTRY _mesa_DrawPixels( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) { 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; } /* We're not using the current vertex program, and the driver may install * it's own. */ _mesa_set_vp_override(ctx, GL_TRUE); if (ctx->NewState) { _mesa_update_state(ctx); } if (!valid_fragment_program(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels (invalid fragment program)"); goto end; } if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { /* the error was already recorded */ goto end; } if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glDrawPixels(incomplete framebuffer)" ); goto end; } if (!ctx->Current.RasterPosValid) { goto end; /* no-op, not an error */ } if (ctx->RenderMode == GL_RENDER) { 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 (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)"); goto end; } if (_mesa_bufferobj_mapped(ctx->Unpack.BufferObj)) { /* buffer is mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(PBO is mapped)"); goto end; } } 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 ); _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); }
static void GLAPIENTRY _mesa_Bitmap( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (width < 0 || height < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); return; } if (!ctx->Current.RasterPosValid) { return; /* do nothing */ } if (ctx->NewState) { _mesa_update_state(ctx); } if (!valid_fragment_program(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap (invalid fragment program)"); return; } if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glBitmap(incomplete framebuffer)"); return; } if (ctx->RenderMode == GL_RENDER) { /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 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 (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 (_mesa_bufferobj_mapped(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 ); } } #if _HAVE_FULL_GL else if (ctx->RenderMode == GL_FEEDBACK) { FLUSH_CURRENT(ctx, 0); _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; }
void GLAPIENTRY _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *pixels ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); FLUSH_CURRENT(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", width, height, _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type), pixels); if (width < 0 || height < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glReadPixels(width=%d height=%d)", width, height ); return; } if (ctx->NewState) _mesa_update_state(ctx); if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) { /* found an error */ return; } /* Check that the destination format and source buffer are both * integer-valued or both non-integer-valued. */ if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) { const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format); const GLboolean dstInteger = _mesa_is_integer_format(format); if (dstInteger != srcInteger) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(integer / non-integer format mismatch"); return; } } if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glReadPixels(incomplete framebuffer)" ); return; } if (ctx->ReadBuffer->Name != 0 && ctx->ReadBuffer->Visual.samples > 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)"); return; } if (!_mesa_source_buffer_exists(ctx, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); return; } if (width == 0 || height == 0) return; /* nothing to do */ if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, format, type, bufSize, pixels)) { if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(out of bounds PBO access)"); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadnPixelsARB(out of bounds access:" " bufSize (%d) is too small)", bufSize); } return; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && _mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { /* buffer is mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); return; } ctx->Driver.ReadPixels(ctx, x, y, width, height, format, type, &ctx->Pack, pixels); }
/* * Execute glDrawPixels */ void GLAPIENTRY _mesa_DrawPixels( GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) { 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; } if (ctx->NewState) { _mesa_update_state(ctx); } if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels (invalid fragment program)"); return; } if (_mesa_error_check_format_type(ctx, format, type, GL_TRUE)) { /* found an error */ return; } if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glDrawPixels(incomplete framebuffer)" ); return; } if (!ctx->Current.RasterPosValid) { 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]); 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 (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); } 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. */ } }
/** * Do error checking for a glGetTexImage() call. * \return GL_TRUE if any error, GL_FALSE if no errors. */ static GLboolean getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, GLenum format, GLenum type, GLsizei clientMemSize, GLvoid *pixels ) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLint maxLevels = _mesa_max_texture_levels(ctx, target); const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; GLenum baseFormat, err; if (!legal_getteximage_target(ctx, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); return GL_TRUE; } assert(maxLevels != 0); if (level < 0 || level >= maxLevels) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); return GL_TRUE; } err = _mesa_error_check_format_and_type(ctx, format, type); if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glGetTexImage(format/type)"); return GL_TRUE; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); return GL_TRUE; } texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { /* non-existant texture image */ return GL_TRUE; } baseFormat = _mesa_get_format_base_format(texImage->TexFormat); /* Make sure the requested image format is compatible with the * texture's format. */ if (_mesa_is_color_format(format) && !_mesa_is_color_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_depth_format(format) && !_mesa_is_depth_format(baseFormat) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_ycbcr_format(format) && !_mesa_is_ycbcr_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_depthstencil_format(format) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_dudv_format(format) && !_mesa_is_dudv_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, texImage->Height, texImage->Depth, format, type, clientMemSize, pixels)) { if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(out of bounds PBO access)"); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetnTexImageARB(out of bounds access:" " bufSize (%d) is too small)", clientMemSize); } return GL_TRUE; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* PBO should not be mapped */ if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(PBO is mapped)"); return GL_TRUE; } } return GL_FALSE; }
/** * Do error checking for a glGetTexImage() call. * \return GL_TRUE if any error, GL_FALSE if no errors. */ static GLboolean getteximage_error_check(GLcontext *ctx, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLuint maxLevels = _mesa_max_texture_levels(ctx, target); GLenum baseFormat; if (maxLevels == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target); return GL_TRUE; } if (level < 0 || level >= maxLevels) { _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" ); return GL_TRUE; } if (_mesa_sizeof_packed_type(type) <= 0) { _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" ); return GL_TRUE; } if (_mesa_components_in_format(format) <= 0 || format == GL_STENCIL_INDEX) { _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" ); return GL_TRUE; } if (!ctx->Extensions.EXT_paletted_texture && _mesa_is_index_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.ARB_depth_texture && _mesa_is_depth_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.MESA_ycbcr_texture && _mesa_is_ycbcr_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.EXT_packed_depth_stencil && _mesa_is_depthstencil_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } if (!ctx->Extensions.ATI_envmap_bumpmap && _mesa_is_dudv_format(format)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)"); return GL_TRUE; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj || _mesa_is_proxy_texture(target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)"); return GL_TRUE; } texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { /* out of memory */ return GL_TRUE; } baseFormat = _mesa_get_format_base_format(texImage->TexFormat); /* Make sure the requested image format is compatible with the * texture's format. Note that a color index texture can be converted * to RGBA so that combo is allowed. */ if (_mesa_is_color_format(format) && !_mesa_is_color_format(baseFormat) && !_mesa_is_index_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_index_format(format) && !_mesa_is_index_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_depth_format(format) && !_mesa_is_depth_format(baseFormat) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_ycbcr_format(format) && !_mesa_is_ycbcr_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_depthstencil_format(format) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } else if (_mesa_is_dudv_format(format) && !_mesa_is_dudv_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)"); return GL_TRUE; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* packing texture image into a PBO */ const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, texImage->Height, texImage->Depth, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(out of bounds PBO write)"); return GL_TRUE; } /* PBO should not be mapped */ if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(PBO is mapped)"); return GL_TRUE; } } return GL_FALSE; }
/* * Execute glDrawPixels */ static 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 (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 (width < 0 || height < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glDrawPixels(width or height < 0)" ); 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->RasterDiscard) { goto end; } if (!ctx->Current.RasterPosValid) { goto end; /* no-op, not an error */ } if (ctx->RenderMode == GL_RENDER) { 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_bufferobj_mapped(ctx->Unpack.BufferObj)) { /* buffer is mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels(PBO is mapped)"); goto end; } } 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 ); _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); _mesa_feedback_vertex( ctx, ctx->Current.RasterPos, ctx->Current.RasterColor, 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); } }
/** * Update/replace all or part of a color table. Helper function * used by _mesa_ColorTable() and _mesa_ColorSubTable(). * The table->Table buffer should already be allocated. * \param start first entry to update * \param count number of entries to update * \param format format of user-provided table data * \param type datatype of user-provided table data * \param data user-provided table data * \param [rgba]Scale - RGBA scale factors * \param [rgba]Bias - RGBA bias factors */ static void store_colortable_entries(GLcontext *ctx, struct gl_color_table *table, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data, GLfloat rScale, GLfloat rBias, GLfloat gScale, GLfloat gBias, GLfloat bScale, GLfloat bBias, GLfloat aScale, GLfloat aBias) { if (ctx->Unpack.BufferObj->Name) { /* Get/unpack the color table data from a PBO */ GLubyte *buf; if (!_mesa_validate_pbo_access(1, &ctx->Unpack, count, 1, 1, format, type, data)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glColor[Sub]Table(bad PBO access)"); return; } buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, ctx->Unpack.BufferObj); if (!buf) { _mesa_error(ctx, GL_INVALID_OPERATION, "glColor[Sub]Table(PBO mapped)"); return; } data = ADD_POINTERS(buf, data); } { /* convert user-provided data to GLfloat values */ GLfloat tempTab[MAX_COLOR_TABLE_SIZE * 4]; GLfloat *tableF; GLint i; _mesa_unpack_color_span_float(ctx, count, /* number of pixels */ table->_BaseFormat, /* dest format */ tempTab, /* dest address */ format, type, /* src format/type */ data, /* src data */ &ctx->Unpack, IMAGE_CLAMP_BIT); /* transfer ops */ /* the destination */ tableF = table->TableF; /* Apply scale & bias & clamp now */ switch (table->_BaseFormat) { case GL_INTENSITY: for (i = 0; i < count; i++) { GLuint j = start + i; tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); } break; case GL_LUMINANCE: for (i = 0; i < count; i++) { GLuint j = start + i; tableF[j] = CLAMP(tempTab[i] * rScale + rBias, 0.0F, 1.0F); } break; case GL_ALPHA: for (i = 0; i < count; i++) { GLuint j = start + i; tableF[j] = CLAMP(tempTab[i] * aScale + aBias, 0.0F, 1.0F); } break; case GL_LUMINANCE_ALPHA: for (i = 0; i < count; i++) { GLuint j = start + i; tableF[j*2+0] = CLAMP(tempTab[i*2+0] * rScale + rBias, 0.0F, 1.0F); tableF[j*2+1] = CLAMP(tempTab[i*2+1] * aScale + aBias, 0.0F, 1.0F); } break; case GL_RGB: for (i = 0; i < count; i++) { GLuint j = start + i; tableF[j*3+0] = CLAMP(tempTab[i*3+0] * rScale + rBias, 0.0F, 1.0F); tableF[j*3+1] = CLAMP(tempTab[i*3+1] * gScale + gBias, 0.0F, 1.0F); tableF[j*3+2] = CLAMP(tempTab[i*3+2] * bScale + bBias, 0.0F, 1.0F); } break; case GL_RGBA: for (i = 0; i < count; i++) { GLuint j = start + i; tableF[j*4+0] = CLAMP(tempTab[i*4+0] * rScale + rBias, 0.0F, 1.0F); tableF[j*4+1] = CLAMP(tempTab[i*4+1] * gScale + gBias, 0.0F, 1.0F); tableF[j*4+2] = CLAMP(tempTab[i*4+2] * bScale + bBias, 0.0F, 1.0F); tableF[j*4+3] = CLAMP(tempTab[i*4+3] * aScale + aBias, 0.0F, 1.0F); } break; default: _mesa_problem(ctx, "Bad format in store_colortable_entries"); return; } } /* update the ubyte table */ { const GLint comps = _mesa_components_in_format(table->_BaseFormat); const GLfloat *tableF = table->TableF + start * comps; GLubyte *tableUB = table->TableUB + start * comps; GLint i; for (i = 0; i < count * comps; i++) { CLAMPED_FLOAT_TO_UBYTE(tableUB[i], tableF[i]); } } if (ctx->Unpack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, ctx->Unpack.BufferObj); } }
void GLAPIENTRY _mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values ) { GLfloat fvalues[MAX_PIXEL_MAP_TABLE]; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) { _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" ); return; } if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) { /* test that mapsize is a power of two */ if (!_mesa_is_pow_two(mapsize)) { _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" ); return; } } FLUSH_VERTICES(ctx, _NEW_PIXEL); if (ctx->Unpack.BufferObj->Name) { /* unpack pixelmap from PBO */ GLubyte *buf; /* Note, need to use DefaultPacking and Unpack's buffer object */ ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj; if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapusv(invalid PBO access)"); return; } /* restore */ ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, GL_READ_ONLY_ARB, ctx->Unpack.BufferObj); if (!buf) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapusv(PBO is mapped)"); return; } values = (const GLushort *) ADD_POINTERS(buf, values); } else if (!values) { return; } /* convert to floats */ if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) { GLint i; for (i = 0; i < mapsize; i++) { fvalues[i] = (GLfloat) values[i]; } } else { GLint i; for (i = 0; i < mapsize; i++) { fvalues[i] = USHORT_TO_FLOAT( values[i] ); } } if (ctx->Unpack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, ctx->Unpack.BufferObj); } store_pixelmap(ctx, map, mapsize, fvalues); }
void GLAPIENTRY _mesa_GetColorTable( GLenum target, GLenum format, GLenum type, GLvoid *data ) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_unit *texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; struct gl_color_table *table = NULL; GLfloat rgba[MAX_COLOR_TABLE_SIZE][4]; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (ctx->NewState) { _mesa_update_state(ctx); } switch (target) { case GL_TEXTURE_1D: table = &texUnit->Current1D->Palette; break; case GL_TEXTURE_2D: table = &texUnit->Current2D->Palette; break; case GL_TEXTURE_3D: table = &texUnit->Current3D->Palette; break; case GL_TEXTURE_CUBE_MAP_ARB: if (!ctx->Extensions.ARB_texture_cube_map) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); return; } table = &texUnit->CurrentCubeMap->Palette; break; case GL_SHARED_TEXTURE_PALETTE_EXT: table = &ctx->Texture.Palette; break; case GL_COLOR_TABLE: table = &ctx->ColorTable[COLORTABLE_PRECONVOLUTION]; break; case GL_TEXTURE_COLOR_TABLE_SGI: if (!ctx->Extensions.SGI_texture_color_table) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); return; } table = &(texUnit->ColorTable); break; case GL_POST_CONVOLUTION_COLOR_TABLE: table = &ctx->ColorTable[COLORTABLE_POSTCONVOLUTION]; break; case GL_POST_COLOR_MATRIX_COLOR_TABLE: table = &ctx->ColorTable[COLORTABLE_POSTCOLORMATRIX]; break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetColorTable(target)"); return; } ASSERT(table); if (table->Size <= 0) { return; } switch (table->_BaseFormat) { case GL_ALPHA: { GLuint i; for (i = 0; i < table->Size; i++) { rgba[i][RCOMP] = 0; rgba[i][GCOMP] = 0; rgba[i][BCOMP] = 0; rgba[i][ACOMP] = table->TableF[i]; } } break; case GL_LUMINANCE: { GLuint i; for (i = 0; i < table->Size; i++) { rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = table->TableF[i]; rgba[i][ACOMP] = 1.0F; } } break; case GL_LUMINANCE_ALPHA: { GLuint i; for (i = 0; i < table->Size; i++) { rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = table->TableF[i*2+0]; rgba[i][ACOMP] = table->TableF[i*2+1]; } } break; case GL_INTENSITY: { GLuint i; for (i = 0; i < table->Size; i++) { rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = rgba[i][ACOMP] = table->TableF[i]; } } break; case GL_RGB: { GLuint i; for (i = 0; i < table->Size; i++) { rgba[i][RCOMP] = table->TableF[i*3+0]; rgba[i][GCOMP] = table->TableF[i*3+1]; rgba[i][BCOMP] = table->TableF[i*3+2]; rgba[i][ACOMP] = 1.0F; } } break; case GL_RGBA: _mesa_memcpy(rgba, table->TableF, 4 * table->Size * sizeof(GLfloat)); break; default: _mesa_problem(ctx, "bad table format in glGetColorTable"); return; } if (ctx->Pack.BufferObj->Name) { /* pack color table into PBO */ GLubyte *buf; if (!_mesa_validate_pbo_access(1, &ctx->Pack, table->Size, 1, 1, format, type, data)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetColorTable(invalid PBO access)"); return; } buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); if (!buf) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetColorTable(PBO is mapped)"); return; } data = ADD_POINTERS(buf, data); } _mesa_pack_rgba_span_float(ctx, table->Size, rgba, format, type, data, &ctx->Pack, 0x0); if (ctx->Pack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, ctx->Pack.BufferObj); } }
static void GLAPIENTRY _mesa_Bitmap( GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap ) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (width < 0 || height < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); return; } if (!ctx->Current.RasterPosValid) { return; /* do nothing */ } /* Note: this call does state validation */ if (!_mesa_valid_to_render(ctx, "glBitmap")) { /* the error code was recorded */ return; } if (ctx->RasterDiscard) return; if (ctx->RenderMode == GL_RENDER) { /* Truncate, to satisfy conformance tests (matches SGI's OpenGL). */ 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_bufferobj_mapped(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 ); } } #if _HAVE_FULL_GL else if (ctx->RenderMode == GL_FEEDBACK) { FLUSH_CURRENT(ctx, 0); _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_BITMAP_TOKEN ); _mesa_feedback_vertex( ctx, ctx->Current.RasterPos, ctx->Current.RasterColor, 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 (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) { _mesa_flush(ctx); } }
void GLAPIENTRY _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, GLvoid *pixels ) { GLenum err = GL_NO_ERROR; struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); FLUSH_CURRENT(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n", width, height, _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type), pixels); if (width < 0 || height < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glReadPixels(width=%d height=%d)", width, height ); return; } if (ctx->NewState) _mesa_update_state(ctx); if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "glReadPixels(incomplete framebuffer)" ); return; } rb = _mesa_get_read_renderbuffer_for_format(ctx, format); if (rb == NULL) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(read buffer)"); return; } /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the * combinations of format and type that can be used. * * Technically, only two combinations are actually allowed: * GL_RGBA/GL_UNSIGNED_BYTE, and some implementation-specific internal * preferred combination. This code doesn't know what that preferred * combination is, and Mesa can handle anything valid. Just work instead. */ if (_mesa_is_gles(ctx)) { if (ctx->API == API_OPENGLES2 && _mesa_is_color_format(format) && _mesa_get_color_read_format(ctx) == format && _mesa_get_color_read_type(ctx) == type) { err = GL_NO_ERROR; } else if (ctx->Version < 30) { err = _mesa_es_error_check_format_and_type(format, type, 2); if (err == GL_NO_ERROR) { if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) { err = GL_INVALID_OPERATION; } } } else { err = read_pixels_es3_error_check(format, type, rb); } if (err == GL_NO_ERROR && (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)) { err = GL_INVALID_ENUM; } if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type)); return; } } err = _mesa_error_check_format_and_type(ctx, format, type); if (err != GL_NO_ERROR) { _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)", _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type)); return; } if (_mesa_is_user_fbo(ctx->ReadBuffer) && ctx->ReadBuffer->Visual.samples > 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)"); return; } if (!_mesa_source_buffer_exists(ctx, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)"); return; } /* Check that the destination format and source buffer are both * integer-valued or both non-integer-valued. */ if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) { const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format); const GLboolean dstInteger = _mesa_is_enum_format_integer(format); if (dstInteger != srcInteger) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(integer / non-integer format mismatch"); return; } } if (width == 0 || height == 0) return; /* nothing to do */ if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1, format, type, bufSize, pixels)) { if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(out of bounds PBO access)"); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "glReadnPixelsARB(out of bounds access:" " bufSize (%d) is too small)", bufSize); } return; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && _mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { /* buffer is mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)"); return; } ctx->Driver.ReadPixels(ctx, x, y, width, height, format, type, &ctx->Pack, pixels); }
static GLboolean do_texture_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); struct intel_region *dst = intel_drawbuf_region(intel); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint rowLength = unpack->RowLength ? unpack->RowLength : width; GLuint src_offset; if (INTEL_DEBUG & DEBUG_PIXEL) fprintf(stderr, "%s\n", __FUNCTION__); intelFlush(&intel->ctx); intel->vtbl.render_start(intel); intel->vtbl.emit_state(intel); if (!dst) return GL_FALSE; if (src) { if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); return GL_TRUE; } } else { /* PBO only for now: */ /* _mesa_printf("%s - not PBO\n", __FUNCTION__); */ return GL_FALSE; } /* There are a couple of things we can't do yet, one of which is * set the correct state for pixel operations when GL texturing is * enabled. That's a pretty rare state and probably not worth the * effort. A completely device-independent version of this may do * more. * * Similarly, we make no attempt to merge metaops processing with * an enabled fragment program, though it would certainly be * possible. */ if (!intel_check_meta_tex_fragment_ops(ctx)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad GL fragment state for metaops texture\n", __FUNCTION__); return GL_FALSE; } intel->vtbl.install_meta_state(intel); /* Is this true? Also will need to turn depth testing on according * to state: */ intel->vtbl.meta_no_stencil_write(intel); intel->vtbl.meta_no_depth_write(intel); /* Set the 3d engine to draw into the destination region: */ intel->vtbl.meta_draw_region(intel, dst, intel->intelScreen->depth_region); intel->vtbl.meta_import_pixel_state(intel); src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, format, type, 0, 0, 0); /* Setup the pbo up as a rectangular texture, if possible. * * TODO: This is almost always possible if the i915 fragment * program is adjusted to correctly swizzle the sampled colors. * The major exception is any 24bit texture, like RGB888, for which * there is no hardware support. */ if (!intel->vtbl.meta_tex_rect_source(intel, src->buffer, src_offset, rowLength, height, format, type)) { intel->vtbl.leave_meta_state(intel); return GL_FALSE; } intel->vtbl.meta_texture_blend_replace(intel); LOCK_HARDWARE(intel); if (intel->driDrawable->numClipRects) { __DRIdrawablePrivate *dPriv = intel->driDrawable; GLint srcx, srcy; GLint dstx, dsty; dstx = x; dsty = dPriv->h - (y + height); srcx = 0; /* skiprows/pixels already done */ srcy = 0; if (0) { const GLint orig_x = dstx; const GLint orig_y = dsty; if (!_mesa_clip_to_region(0, 0, dst->pitch, dst->height, &dstx, &dsty, &width, &height)) goto out; srcx += dstx - orig_x; srcy += dsty - orig_y; } if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("draw %d,%d %dx%d\n", dstx, dsty, width, height); /* Must use the regular cliprect mechanism in order to get the * drawing origin set correctly. Otherwise scissor state is in * incorrect coordinate space. Does this even need to hold the * lock??? */ intel_meta_draw_quad(intel, dstx, dstx + width * ctx->Pixel.ZoomX, dPriv->h - (y + height * ctx->Pixel.ZoomY), dPriv->h - (y), -ctx->Current.RasterPos[2] * .5, 0x00ff00ff, srcx, srcx + width, srcy + height, srcy); out: intel->vtbl.leave_meta_state(intel); intel_batchbuffer_flush(intel->batch); } UNLOCK_HARDWARE(intel); return GL_TRUE; }
/** * Do error checking for a glGetTex(ture)Image() call. * \return GL_TRUE if any error, GL_FALSE if no errors. */ static GLboolean getteximage_error_check(struct gl_context *ctx, struct gl_texture_image *texImage, GLenum target, GLint level, GLenum format, GLenum type, GLsizei clientMemSize, GLvoid *pixels, bool dsa) { const GLint maxLevels = _mesa_max_texture_levels(ctx, target); const GLuint dimensions = 2; // const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; GLenum baseFormat; const char *suffix = dsa ? "ture" : ""; assert(texImage); assert(maxLevels != 0); if (level < 0 || level >= maxLevels) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetTex%sImage(level out of range)", suffix); return GL_TRUE; } /* * Format and type checking has been moved up to GetnTexImage and * GetTextureImage so that it happens before getting the texImage object. */ baseFormat = _mesa_get_format_base_format(texImage->TexFormat); /* Make sure the requested image format is compatible with the * texture's format. */ if (_mesa_is_color_format(format) && !_mesa_is_color_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTex%sImage(format mismatch)", suffix); return GL_TRUE; } else if (_mesa_is_depth_format(format) && !_mesa_is_depth_format(baseFormat) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTex%sImage(format mismatch)", suffix); return GL_TRUE; } else if (_mesa_is_stencil_format(format) && !ctx->Extensions.ARB_texture_stencil8) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetTex%sImage(format=GL_STENCIL_INDEX)", suffix); return GL_TRUE; } else if (_mesa_is_ycbcr_format(format) && !_mesa_is_ycbcr_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTex%sImage(format mismatch)", suffix); return GL_TRUE; } else if (_mesa_is_depthstencil_format(format) && !_mesa_is_depthstencil_format(baseFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTex%sImage(format mismatch)", suffix); return GL_TRUE; } else if (!_mesa_is_stencil_format(format) && _mesa_is_enum_format_integer(format) != _mesa_is_format_integer(texImage->TexFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTex%sImage(format mismatch)", suffix); return GL_TRUE; } if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width, texImage->Height, texImage->Depth, format, type, clientMemSize, pixels)) { if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTex%sImage(out of bounds PBO access)", suffix); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds access:" " bufSize (%d) is too small)", dsa ? "glGetTextureImage" : "glGetnTexImageARB", clientMemSize); } return GL_TRUE; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* PBO should not be mapped */ if (_mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTex%sImage(PBO is mapped)", suffix); return GL_TRUE; } } return GL_FALSE; }
void GLAPIENTRY _mesa_GetPixelMapusv( GLenum map, GLushort *values ) { GET_CURRENT_CONTEXT(ctx); GLint mapsize, i; const struct gl_pixelmap *pm; ASSERT_OUTSIDE_BEGIN_END(ctx); pm = get_pixelmap(ctx, map); if (!pm) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapusv(map)"); return; } mapsize = pm ? pm->Size : 0; if (ctx->Pack.BufferObj->Name) { /* pack pixelmap into PBO */ GLubyte *buf; /* Note, need to use DefaultPacking and Pack's buffer object */ ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj; if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1, GL_INTENSITY, GL_UNSIGNED_SHORT, values)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetPixelMapusv(invalid PBO access)"); return; } /* restore */ ctx->DefaultPacking.BufferObj = ctx->Array.NullBufferObj; buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, GL_WRITE_ONLY_ARB, ctx->Pack.BufferObj); if (!buf) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "glGetPixelMapusv(PBO is mapped)"); return; } values = (GLushort *) ADD_POINTERS(buf, values); } else if (!values) { return; } switch (map) { /* special cases */ case GL_PIXEL_MAP_I_TO_I: for (i = 0; i < mapsize; i++) { values[i] = (GLushort) CLAMP(ctx->PixelMaps.ItoI.Map[i], 0.0, 65535.); } break; case GL_PIXEL_MAP_S_TO_S: for (i = 0; i < mapsize; i++) { values[i] = (GLushort) CLAMP(ctx->PixelMaps.StoS.Map[i], 0.0, 65535.); } break; default: for (i = 0; i < mapsize; i++) { CLAMPED_FLOAT_TO_USHORT(values[i], pm->Map[i] ); } } if (ctx->Pack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, ctx->Pack.BufferObj); } }
/* Pros: * - no waiting for idle before updating framebuffer. * * Cons: * - if upload is by memcpy, this may actually be slower than fallback path. * - uploads the whole image even if destination is clipped * * Need to benchmark. * * Given the questions about performance, implement for pbo's only. * This path is definitely a win if the pbo is already in agp. If it * turns out otherwise, we can add the code necessary to upload client * data to agp space before performing the blit. (Though it may turn * out to be better/simpler just to use the texture engine). */ static GLboolean do_blit_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); struct intel_region *dest = intel_drawbuf_region(intel); struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); GLuint src_offset; GLuint rowLength; struct _DriFenceObject *fence = NULL; if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s\n", __FUNCTION__); if (!dest) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - no dest\n", __FUNCTION__); return GL_FALSE; } if (src) { /* This validation should be done by core mesa: */ if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, format, type, pixels)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); return GL_TRUE; } } else { /* PBO only for now: */ if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - not PBO\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_format(dest, format, type)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad format for blit\n", __FUNCTION__); return GL_FALSE; } if (!intel_check_blit_fragment_ops(ctx)) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad GL fragment state for blitter\n", __FUNCTION__); return GL_FALSE; } if (ctx->Pixel.ZoomX != 1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomX for blit\n", __FUNCTION__); return GL_FALSE; } if (unpack->RowLength > 0) rowLength = unpack->RowLength; else rowLength = width; if (ctx->Pixel.ZoomY == -1.0F) { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; /* later */ y -= height; } else if (ctx->Pixel.ZoomY == 1.0F) { rowLength = -rowLength; } else { if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); return GL_FALSE; } src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, format, type, 0, 0, 0); intelFlush(&intel->ctx); LOCK_HARDWARE(intel); if (intel->driDrawable->numClipRects) { __DRIdrawablePrivate *dPriv = intel->driDrawable; int nbox = dPriv->numClipRects; drm_clip_rect_t *box = dPriv->pClipRects; drm_clip_rect_t rect; drm_clip_rect_t dest_rect; struct _DriBufferObject *src_buffer = intel_bufferobj_buffer(intel, src, INTEL_READ); int i; dest_rect.x1 = dPriv->x + x; dest_rect.y1 = dPriv->y + dPriv->h - (y + height); dest_rect.x2 = dest_rect.x1 + width; dest_rect.y2 = dest_rect.y1 + height; for (i = 0; i < nbox; i++) { if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i])) continue; intelEmitCopyBlit(intel, dest->cpp, rowLength, src_buffer, src_offset, dest->pitch, dest->buffer, 0, rect.x1 - dest_rect.x1, rect.y2 - dest_rect.y2, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1, ctx->Color.ColorLogicOpEnabled ? ctx->Color.LogicOp : GL_COPY); } fence = intel_batchbuffer_flush(intel->batch); driFenceReference(fence); } UNLOCK_HARDWARE(intel); if (fence) { driFenceFinish(fence, DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW, GL_FALSE); driFenceUnReference(fence); } if (INTEL_DEBUG & DEBUG_PIXEL) _mesa_printf("%s - DONE\n", __FUNCTION__); return GL_TRUE; }