/** * Free up everything allocated during split/replay. */ static void replay_finish( struct copy_context *copy ) { struct gl_context *ctx = copy->ctx; GLuint i; /* Free our vertex and index buffers: */ free(copy->translated_elt_buf); free(copy->dstbuf); free(copy->dstelt); /* Unmap VBO's */ for (i = 0; i < copy->nr_varying; i++) { struct gl_buffer_object *vbo = copy->varying[i].array->BufferObj; if (_mesa_is_bufferobj(vbo) && _mesa_bufferobj_mapped(vbo, MAP_INTERNAL)) ctx->Driver.UnmapBuffer(ctx, vbo, MAP_INTERNAL); } /* Unmap index buffer: */ if (_mesa_is_bufferobj(copy->ib->obj) && _mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) { ctx->Driver.UnmapBuffer(ctx, copy->ib->obj, MAP_INTERNAL); } }
void vbo_exec_vtx_destroy( struct vbo_exec_context *exec ) { /* using a real VBO for vertex data */ struct gl_context *ctx = exec->ctx; unsigned i; /* True VBOs should already be unmapped */ if (exec->vtx.buffer_map) { assert(exec->vtx.bufferobj->Name == 0 || exec->vtx.bufferobj->Name == IMM_BUFFER_NAME); if (exec->vtx.bufferobj->Name == 0) { _mesa_align_free(exec->vtx.buffer_map); exec->vtx.buffer_map = NULL; exec->vtx.buffer_ptr = NULL; } } /* Drop any outstanding reference to the vertex buffer */ for (i = 0; i < ARRAY_SIZE(exec->vtx.arrays); i++) { _mesa_reference_buffer_object(ctx, &exec->vtx.arrays[i].BufferObj, NULL); } /* Free the vertex buffer. Unmap first if needed. */ if (_mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) { ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL); } _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL); }
/** * Delete a set of buffer objects. * * \param n Number of buffer objects to delete. * \param ids Array of \c n buffer object IDs. */ void GLAPIENTRY _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) { GET_CURRENT_CONTEXT(ctx); GLsizei i; ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, 0); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); return; } _glthread_LOCK_MUTEX(ctx->Shared->Mutex); for (i = 0; i < n; i++) { struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); if (bufObj) { GLuint j; ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); if (_mesa_bufferobj_mapped(bufObj)) { /* if mapped, unmap it now */ ctx->Driver.UnmapBuffer(ctx, bufObj); bufObj->AccessFlags = default_access_mode(ctx); bufObj->Pointer = NULL; } /* unbind any vertex pointers bound to this buffer */ for (j = 0; j < Elements(ctx->Array.VertexAttrib); j++) { unbind(ctx, &ctx->Array.VertexAttrib[j].BufferObj, bufObj); } if (ctx->Array.ElementArrayBufferObj == bufObj) { _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); } /* The ID is immediately freed for re-use */ _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]); /* Make sure we do not run into the classic ABA problem on bind. * We don't want to allow re-binding a buffer object that's been * "deleted" by glDeleteBuffers(). * * The explicit rebinding to the default object in the current context * prevents the above in the current context, but another context * sharing the same objects might suffer from this problem. * The alternative would be to do the hash lookup in any case on bind * which would introduce more runtime overhead than this. */ bufObj->DeletePending = GL_TRUE; _mesa_reference_buffer_object(ctx, &bufObj, NULL); } } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Unmap the buffer object referenced by given array, if mapped. */ static void unmap_array_buffer(struct gl_context *ctx, struct gl_client_array *array) { if (array->Enabled && _mesa_is_bufferobj(array->BufferObj) && _mesa_bufferobj_mapped(array->BufferObj)) { ctx->Driver.UnmapBuffer(ctx, array->BufferObj); } }
/** * A debug function that may be called from other parts of Mesa as * needed during debugging. */ void vbo_check_buffers_are_unmapped(struct gl_context *ctx) { struct vbo_context *vbo = vbo_context(ctx); struct vbo_exec_context *exec = &vbo->exec; /* check the current vertex arrays */ check_buffers_are_unmapped(exec->array.inputs); /* check the current glBegin/glVertex/glEnd-style VBO */ assert(!_mesa_bufferobj_mapped(exec->vtx.bufferobj)); }
/** * See GL_ARB_map_buffer_range spec */ void GLAPIENTRY _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; ASSERT_OUTSIDE_BEGIN_END(ctx); if (!ctx->Extensions.ARB_map_buffer_range) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFlushMappedBufferRange(extension not supported)"); return; } if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glFlushMappedBufferRange(offset = %ld)", (long)offset); return; } if (length < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glFlushMappedBufferRange(length = %ld)", (long)length); return; } bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target); if (!bufObj) return; if (!_mesa_bufferobj_mapped(bufObj)) { /* buffer is not mapped */ _mesa_error(ctx, GL_INVALID_OPERATION, "glFlushMappedBufferRange(buffer is not mapped)"); return; } if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); return; } if (offset + length > bufObj->Length) { _mesa_error(ctx, GL_INVALID_VALUE, "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)", (long)offset, (long)length, (long)bufObj->Length); return; } ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); if (ctx->Driver.FlushMappedBufferRange) ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj); }
/* Translate indices to GLuints and store in VB->Elts. */ static void bind_indices( struct gl_context *ctx, const struct _mesa_index_buffer *ib, struct gl_buffer_object **bo, GLuint *nr_bo) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; GLuint i; const void *ptr; if (!ib) { VB->Elts = NULL; return; } if (_mesa_is_bufferobj(ib->obj) && !_mesa_bufferobj_mapped(ib->obj, MAP_INTERNAL)) { /* if the buffer object isn't mapped yet, map it now */ bo[*nr_bo] = ib->obj; (*nr_bo)++; ptr = ctx->Driver.MapBufferRange(ctx, (GLsizeiptr) ib->ptr, ib->count * vbo_sizeof_ib_type(ib->type), GL_MAP_READ_BIT, ib->obj, MAP_INTERNAL); assert(ib->obj->Mappings[MAP_INTERNAL].Pointer); } else { /* user-space elements, or buffer already mapped */ ptr = ADD_POINTERS(ib->obj->Mappings[MAP_INTERNAL].Pointer, ib->ptr); } if (ib->type == GL_UNSIGNED_INT && VB->Primitive[0].basevertex == 0) { VB->Elts = (GLuint *) ptr; } else { GLuint *elts = (GLuint *)get_space(ctx, ib->count * sizeof(GLuint)); VB->Elts = elts; if (ib->type == GL_UNSIGNED_INT) { const GLuint *in = (GLuint *)ptr; for (i = 0; i < ib->count; i++) *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } else if (ib->type == GL_UNSIGNED_SHORT) { const GLushort *in = (GLushort *)ptr; for (i = 0; i < ib->count; i++) *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } else { const GLubyte *in = (GLubyte *)ptr; for (i = 0; i < ib->count; i++) *elts++ = (GLuint)(*in++) + VB->Primitive[0].basevertex; } } }
/** * Check if the given vertex buffer object exists and is not mapped. * If so, add it to the list of buffers we must map before executing * an glArrayElement call. */ static void check_vbo(AEcontext *actx, struct gl_buffer_object *vbo) { if (_mesa_is_bufferobj(vbo) && !_mesa_bufferobj_mapped(vbo)) { GLuint i; for (i = 0; i < actx->nr_vbos; i++) if (actx->vbo[i] == vbo) return; /* already in the list, we're done */ assert(actx->nr_vbos < VERT_ATTRIB_MAX); actx->vbo[actx->nr_vbos++] = vbo; } }
/** * Default fallback for \c dd_function_table::MapBufferRange(). * Called via glMapBufferRange(). */ static void * _mesa_buffer_map_range( struct gl_context *ctx, GLintptr offset, GLsizeiptr length, GLbitfield access, struct gl_buffer_object *bufObj ) { (void) ctx; assert(!_mesa_bufferobj_mapped(bufObj)); /* Just return a direct pointer to the data */ bufObj->Pointer = bufObj->Data + offset; bufObj->Length = length; bufObj->Offset = offset; bufObj->AccessFlags = access; return bufObj->Pointer; }
/** * All vertex buffers should be in an unmapped state when we're about * to draw. This debug function checks that. */ static void check_buffers_are_unmapped(const struct gl_client_array **inputs) { #ifdef DEBUG GLuint i; for (i = 0; i < VERT_ATTRIB_MAX; i++) { if (inputs[i]) { struct gl_buffer_object *obj = inputs[i]->BufferObj; assert(!_mesa_bufferobj_mapped(obj)); (void) obj; } } #endif }
/** * New in GL 3.2 * This is pretty much a duplicate of GetBufferParameteriv() but the * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. */ void GLAPIENTRY _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; ASSERT_OUTSIDE_BEGIN_END(ctx); bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target); if (!bufObj) return; switch (pname) { case GL_BUFFER_SIZE_ARB: *params = bufObj->Size; return; case GL_BUFFER_USAGE_ARB: *params = bufObj->Usage; return; case GL_BUFFER_ACCESS_ARB: *params = simplified_access_mode(bufObj->AccessFlags); return; case GL_BUFFER_ACCESS_FLAGS: if (!ctx->Extensions.ARB_map_buffer_range) goto invalid_pname; *params = bufObj->AccessFlags; return; case GL_BUFFER_MAPPED_ARB: *params = _mesa_bufferobj_mapped(bufObj); return; case GL_BUFFER_MAP_OFFSET: if (!ctx->Extensions.ARB_map_buffer_range) goto invalid_pname; *params = bufObj->Offset; return; case GL_BUFFER_MAP_LENGTH: if (!ctx->Extensions.ARB_map_buffer_range) goto invalid_pname; *params = bufObj->Length; return; default: ; /* fall-through */ } invalid_pname: _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", _mesa_lookup_enum_by_nr(pname)); }
/** * Combine PBO-read validation and mapping. * If any GL errors are detected, they'll be recorded and NULL returned. * \sa _mesa_validate_pbo_access * \sa _mesa_map_pbo_source * A call to this function should have a matching call to * _mesa_unmap_pbo_source(). */ const GLvoid * _mesa_map_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 NULL; } if (!_mesa_is_bufferobj(unpack->BufferObj)) { /* non-PBO access: no further validation to be done */ return ptr; } if (_mesa_bufferobj_mapped(unpack->BufferObj)) { /* buffer is already mapped - that's an error */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); return NULL; } ptr = _mesa_map_pbo_source(ctx, unpack, ptr); return ptr; }
/** * Tests the subdata range parameters and sets the GL error code for * \c glBufferSubDataARB and \c glGetBufferSubDataARB. * * \param ctx GL context. * \param target Buffer object target on which to operate. * \param offset Offset of the first byte of the subdata range. * \param size Size, in bytes, of the subdata range. * \param caller Name of calling function for recording errors. * \return A pointer to the buffer object bound to \c target in the * specified context or \c NULL if any of the parameter or state * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB * are invalid. * * \sa glBufferSubDataARB, glGetBufferSubDataARB */ static struct gl_buffer_object * buffer_object_subdata_range_good( struct gl_context * ctx, GLenum target, GLintptrARB offset, GLsizeiptrARB size, const char *caller ) { struct gl_buffer_object *bufObj; if (size < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); return NULL; } if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); return NULL; } bufObj = get_buffer(ctx, caller, target); if (!bufObj) return NULL; if (offset + size > bufObj->Size) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset %lu + size %lu > buffer size %lu)", caller, (unsigned long) offset, (unsigned long) size, (unsigned long) bufObj->Size); return NULL; } if (_mesa_bufferobj_mapped(bufObj)) { /* Buffer is currently mapped */ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); return NULL; } return bufObj; }
/** * Do error checking for a glGetCompressedTexImage() call. * \return GL_TRUE if any error, GL_FALSE if no errors. */ static GLboolean getcompressedteximage_error_check(GLcontext *ctx, GLenum target, GLint level, GLvoid *img) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLuint maxLevels = _mesa_max_texture_levels(ctx, target); if (maxLevels == 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", target); return GL_TRUE; } if (level < 0 || level >= maxLevels) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(bad level = %d)", level); return GL_TRUE; } if (_mesa_is_proxy_texture(target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(bad target = %s)", _mesa_lookup_enum_by_nr(target)); return GL_TRUE; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); return GL_TRUE; } texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { /* probably invalid mipmap level */ _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)"); return GL_TRUE; } if (!_mesa_is_format_compressed(texImage->TexFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB(texture is not compressed)"); return GL_TRUE; } if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) { GLuint compressedSize; /* make sure PBO is not mapped */ if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImage(PBO is mapped)"); return GL_TRUE; } compressedSize = _mesa_format_image_size(texImage->TexFormat, texImage->Width, texImage->Height, texImage->Depth); /* do bounds checking on PBO write */ if ((const GLubyte *) img + compressedSize > (const GLubyte *) ctx->Pack.BufferObj->Size) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImage(out of bounds PBO write)"); 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(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; }
/* * 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); } }
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); } }
/* * 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); }
GLboolean GLAPIENTRY _mesa_UnmapBufferARB(GLenum target) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; GLboolean status = GL_TRUE; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); bufObj = get_buffer(ctx, "glUnmapBufferARB", target); if (!bufObj) return GL_FALSE; if (!_mesa_bufferobj_mapped(bufObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); return GL_FALSE; } #ifdef BOUNDS_CHECK if (bufObj->Access != GL_READ_ONLY_ARB) { GLubyte *buf = (GLubyte *) bufObj->Pointer; GLuint i; /* check that last 100 bytes are still = magic value */ for (i = 0; i < 100; i++) { GLuint pos = bufObj->Size - i - 1; if (buf[pos] != 123) { _mesa_warning(ctx, "Out of bounds buffer object write detected" " at position %d (value = %u)\n", pos, buf[pos]); } } } #endif #ifdef VBO_DEBUG if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { GLuint i, unchanged = 0; GLubyte *b = (GLubyte *) bufObj->Pointer; GLint pos = -1; /* check which bytes changed */ for (i = 0; i < bufObj->Size - 1; i++) { if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { unchanged++; if (pos == -1) pos = i; } } if (unchanged) { printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", bufObj->Name, unchanged, bufObj->Size, pos); } } #endif status = ctx->Driver.UnmapBuffer( ctx, bufObj ); bufObj->AccessFlags = default_access_mode(ctx); ASSERT(bufObj->Pointer == NULL); ASSERT(bufObj->Offset == 0); ASSERT(bufObj->Length == 0); return status; }
/** * See GL_ARB_map_buffer_range spec */ void * GLAPIENTRY _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; void *map; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); if (!ctx->Extensions.ARB_map_buffer_range) { _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferRange(extension not supported)"); return NULL; } if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(offset = %ld)", (long)offset); return NULL; } if (length < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(length = %ld)", (long)length); return NULL; } if (access & ~(GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT)) { /* generate an error if any undefind bit is set */ _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)"); return NULL; } if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferRange(access indicates neither read or write)"); return NULL; } if ((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT))) { _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferRange(invalid access flags)"); return NULL; } if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && ((access & GL_MAP_WRITE_BIT) == 0)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferRange(invalid access flags)"); return NULL; } bufObj = get_buffer(ctx, "glMapBufferRange", target); if (!bufObj) return NULL; if (offset + length > bufObj->Size) { _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(offset + length > size)"); return NULL; } if (_mesa_bufferobj_mapped(bufObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferRange(buffer already mapped)"); return NULL; } if (!bufObj->Size) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferRange(buffer size = 0)"); return NULL; } /* Mapping zero bytes should return a non-null pointer. */ if (!length) { static long dummy = 0; bufObj->Pointer = &dummy; bufObj->Length = length; bufObj->Offset = offset; bufObj->AccessFlags = access; return bufObj->Pointer; } ASSERT(ctx->Driver.MapBufferRange); map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); } else { /* The driver callback should have set all these fields. * This is important because other modules (like VBO) might call * the driver function directly. */ ASSERT(bufObj->Pointer == map); ASSERT(bufObj->Length == length); ASSERT(bufObj->Offset == offset); ASSERT(bufObj->AccessFlags == access); } return map; }
static void replay_init( struct copy_context *copy ) { struct gl_context *ctx = copy->ctx; GLuint i; GLuint offset; const GLvoid *srcptr; /* Make a list of varying attributes and their vbo's. Also * calculate vertex size. */ copy->vertex_size = 0; for (i = 0; i < VERT_ATTRIB_MAX; i++) { struct gl_buffer_object *vbo = copy->array[i]->BufferObj; if (copy->array[i]->StrideB == 0) { copy->dstarray_ptr[i] = copy->array[i]; } else { GLuint j = copy->nr_varying++; copy->varying[j].attr = i; copy->varying[j].array = copy->array[i]; copy->varying[j].size = attr_size(copy->array[i]); copy->vertex_size += attr_size(copy->array[i]); if (_mesa_is_bufferobj(vbo) && !_mesa_bufferobj_mapped(vbo, MAP_INTERNAL)) ctx->Driver.MapBufferRange(ctx, 0, vbo->Size, GL_MAP_READ_BIT, vbo, MAP_INTERNAL); copy->varying[j].src_ptr = ADD_POINTERS(vbo->Mappings[MAP_INTERNAL].Pointer, copy->array[i]->Ptr); copy->dstarray_ptr[i] = ©->varying[j].dstarray; } } /* There must always be an index buffer. Currently require the * caller convert non-indexed prims to indexed. Could alternately * do it internally. */ if (_mesa_is_bufferobj(copy->ib->obj) && !_mesa_bufferobj_mapped(copy->ib->obj, MAP_INTERNAL)) ctx->Driver.MapBufferRange(ctx, 0, copy->ib->obj->Size, GL_MAP_READ_BIT, copy->ib->obj, MAP_INTERNAL); srcptr = (const GLubyte *) ADD_POINTERS(copy->ib->obj->Mappings[MAP_INTERNAL].Pointer, copy->ib->ptr); switch (copy->ib->type) { case GL_UNSIGNED_BYTE: copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); copy->srcelt = copy->translated_elt_buf; for (i = 0; i < copy->ib->count; i++) copy->translated_elt_buf[i] = ((const GLubyte *)srcptr)[i]; break; case GL_UNSIGNED_SHORT: copy->translated_elt_buf = malloc(sizeof(GLuint) * copy->ib->count); copy->srcelt = copy->translated_elt_buf; for (i = 0; i < copy->ib->count; i++) copy->translated_elt_buf[i] = ((const GLushort *)srcptr)[i]; break; case GL_UNSIGNED_INT: copy->translated_elt_buf = NULL; copy->srcelt = (const GLuint *)srcptr; break; } /* Figure out the maximum allowed vertex buffer size: */ if (copy->vertex_size * copy->limits->max_verts <= copy->limits->max_vb_size) { copy->dstbuf_size = copy->limits->max_verts; } else { copy->dstbuf_size = copy->limits->max_vb_size / copy->vertex_size; } /* Allocate an output vertex buffer: * * XXX: This should be a VBO! */ copy->dstbuf = malloc(copy->dstbuf_size * copy->vertex_size); copy->dstptr = copy->dstbuf; /* Setup new vertex arrays to point into the output buffer: */ for (offset = 0, i = 0; i < copy->nr_varying; i++) { const struct gl_client_array *src = copy->varying[i].array; struct gl_client_array *dst = ©->varying[i].dstarray; dst->Size = src->Size; dst->Type = src->Type; dst->Format = GL_RGBA; dst->Stride = copy->vertex_size; dst->StrideB = copy->vertex_size; dst->Ptr = copy->dstbuf + offset; dst->Enabled = GL_TRUE; dst->Normalized = src->Normalized; dst->Integer = src->Integer; dst->BufferObj = ctx->Shared->NullBufferObj; dst->_ElementSize = src->_ElementSize; offset += copy->varying[i].size; } /* Allocate an output element list: */ copy->dstelt_size = MIN2(65536, copy->ib->count * 2 + 3); copy->dstelt_size = MIN2(copy->dstelt_size, copy->limits->max_indices); copy->dstelt = malloc(sizeof(GLuint) * copy->dstelt_size); copy->dstelt_nr = 0; /* Setup the new index buffer to point to the allocated element * list: */ copy->dstib.count = 0; /* duplicates dstelt_nr */ copy->dstib.type = GL_UNSIGNED_INT; copy->dstib.obj = ctx->Shared->NullBufferObj; copy->dstib.ptr = copy->dstelt; }
void * GLAPIENTRY _mesa_MapBufferARB(GLenum target, GLenum access) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object * bufObj; GLbitfield accessFlags; void *map; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); switch (access) { case GL_READ_ONLY_ARB: accessFlags = GL_MAP_READ_BIT; break; case GL_WRITE_ONLY_ARB: accessFlags = GL_MAP_WRITE_BIT; break; case GL_READ_WRITE_ARB: accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); return NULL; } bufObj = get_buffer(ctx, "glMapBufferARB", target); if (!bufObj) return NULL; if (_mesa_bufferobj_mapped(bufObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); return NULL; } if (!bufObj->Size) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBuffer(buffer size = 0)"); return NULL; } ASSERT(ctx->Driver.MapBufferRange); map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); return NULL; } else { /* The driver callback should have set these fields. * This is important because other modules (like VBO) might call * the driver function directly. */ ASSERT(bufObj->Pointer == map); ASSERT(bufObj->Length == bufObj->Size); ASSERT(bufObj->Offset == 0); bufObj->AccessFlags = accessFlags; } if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) bufObj->Written = GL_TRUE; #ifdef VBO_DEBUG printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", bufObj->Name, bufObj->Size, access); if (access == GL_WRITE_ONLY_ARB) { GLuint i; GLubyte *b = (GLubyte *) bufObj->Pointer; for (i = 0; i < bufObj->Size; i++) b[i] = i & 0xff; } #endif #ifdef BOUNDS_CHECK { GLubyte *buf = (GLubyte *) bufObj->Pointer; GLuint i; /* buffer is 100 bytes larger than requested, fill with magic value */ for (i = 0; i < 100; i++) { buf[bufObj->Size - i - 1] = 123; } } #endif return bufObj->Pointer; }
/** * Do error checking for a glGetCompressedTexImage() call. * \return GL_TRUE if any error, GL_FALSE if no errors. */ static GLboolean getcompressedteximage_error_check(struct gl_context *ctx, GLenum target, GLint level, GLsizei clientMemSize, GLvoid *img) { struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLint maxLevels = _mesa_max_texture_levels(ctx, target); GLuint compressedSize; if (!legal_getteximage_target(ctx, target)) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)", target); return GL_TRUE; } assert(maxLevels != 0); if (level < 0 || level >= maxLevels) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(bad level = %d)", level); return GL_TRUE; } texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)"); return GL_TRUE; } texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { /* probably invalid mipmap level */ _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)"); return GL_TRUE; } if (!_mesa_is_format_compressed(texImage->TexFormat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB(texture is not compressed)"); return GL_TRUE; } compressedSize = _mesa_format_image_size(texImage->TexFormat, texImage->Width, texImage->Height, texImage->Depth); if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) { /* do bounds checking on writing to client memory */ if (clientMemSize < compressedSize) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetnCompressedTexImageARB(out of bounds access:" " bufSize (%d) is too small)", clientMemSize); return GL_TRUE; } } else { /* do bounds checking on PBO write */ if ((const GLubyte *) img + compressedSize > (const GLubyte *) ctx->Pack.BufferObj->Size) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImage(out of bounds PBO access)"); return GL_TRUE; } /* make sure PBO is not mapped */ if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImage(PBO is mapped)"); return GL_TRUE; } } return GL_FALSE; }
void GLAPIENTRY _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n", _mesa_lookup_enum_by_nr(target), (long int) size, data, _mesa_lookup_enum_by_nr(usage)); if (size < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); return; } switch (usage) { case GL_STREAM_DRAW_ARB: case GL_STREAM_READ_ARB: case GL_STREAM_COPY_ARB: case GL_STATIC_DRAW_ARB: case GL_STATIC_READ_ARB: case GL_STATIC_COPY_ARB: case GL_DYNAMIC_DRAW_ARB: case GL_DYNAMIC_READ_ARB: case GL_DYNAMIC_COPY_ARB: /* OK */ break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); return; } bufObj = get_buffer(ctx, "glBufferDataARB", target); if (!bufObj) return; if (_mesa_bufferobj_mapped(bufObj)) { /* Unmap the existing buffer. We'll replace it now. Not an error. */ ctx->Driver.UnmapBuffer(ctx, bufObj); bufObj->AccessFlags = default_access_mode(ctx); ASSERT(bufObj->Pointer == NULL); } FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); bufObj->Written = GL_TRUE; #ifdef VBO_DEBUG printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", bufObj->Name, size, data, usage); #endif #ifdef BOUNDS_CHECK size += 100; #endif ASSERT(ctx->Driver.BufferData); if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); } }
/** * 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; }