/* * Read R, G, B, A, RGB, L, or LA pixels. */ static void read_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing ) { GLbitfield transferOps = ctx->_ImageTransferState; struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->_ColorReadBuffer; if (!rb) return; if ((ctx->Color._ClampReadColor == GL_TRUE || type != GL_FLOAT) && !_mesa_is_integer_format(format)) { transferOps |= IMAGE_CLAMP_BIT; } if (!transferOps) { /* Try the optimized paths first. */ if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height, format, type, pixels, packing, transferOps)) { return; } } slow_read_rgba_pixels(ctx, x, y, width, height, format, type, pixels, packing, transferOps); }
static void slow_read_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels, const struct gl_pixelstore_attrib *packing, GLbitfield transferOps ) { struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer; const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format); void *rgba; GLubyte *dst, *map; int dstStride, stride, j; dstStride = _mesa_image_row_stride(packing, width, format, type); dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height, format, type, 0, 0); ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT, &map, &stride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); return; } rgba = malloc(width * MAX_PIXEL_BYTES); if (!rgba) goto done; for (j = 0; j < height; j++) { if (_mesa_is_integer_format(format)) { _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba); _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format, type, dst); } else { _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dst, packing, transferOps); } dst += dstStride; map += stride; } free(rgba); done: ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/* * 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_integer_format(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); }
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); }
/** * Return a texture internalFormat for drawing/copying an image * of the given format and type. */ static GLenum internal_format(struct gl_context *ctx, GLenum format, GLenum type) { switch (format) { case GL_DEPTH_COMPONENT: return GL_DEPTH_COMPONENT; case GL_DEPTH_STENCIL: return GL_DEPTH_STENCIL; case GL_STENCIL_INDEX: return GL_STENCIL_INDEX; default: if (_mesa_is_integer_format(format)) { switch (type) { case GL_BYTE: return GL_RGBA8I; case GL_UNSIGNED_BYTE: return GL_RGBA8UI; case GL_SHORT: return GL_RGBA16I; case GL_UNSIGNED_SHORT: return GL_RGBA16UI; case GL_INT: return GL_RGBA32I; case GL_UNSIGNED_INT: return GL_RGBA32UI; default: assert(0 && "Unexpected type in internal_format()"); return GL_RGBA_INTEGER; } } else { switch (type) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_INT_8_8_8_8: case GL_UNSIGNED_INT_8_8_8_8_REV: default: return GL_RGBA8; case GL_UNSIGNED_BYTE_3_3_2: case GL_UNSIGNED_BYTE_2_3_3_REV: case GL_UNSIGNED_SHORT_4_4_4_4: case GL_UNSIGNED_SHORT_4_4_4_4_REV: return GL_RGBA4; case GL_UNSIGNED_SHORT_5_6_5: case GL_UNSIGNED_SHORT_5_6_5_REV: case GL_UNSIGNED_SHORT_5_5_5_1: case GL_UNSIGNED_SHORT_1_5_5_5_REV: return GL_RGB5_A1; case GL_UNSIGNED_INT_10_10_10_2: case GL_UNSIGNED_INT_2_10_10_10_REV: return GL_RGB10_A2; case GL_UNSIGNED_SHORT: case GL_UNSIGNED_INT: return GL_RGBA16; case GL_BYTE: return ctx->Extensions.EXT_texture_snorm ? GL_RGBA8_SNORM : GL_RGBA8; case GL_SHORT: case GL_INT: return ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; case GL_HALF_FLOAT_ARB: return ctx->Extensions.ARB_texture_float ? GL_RGBA16F : ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; case GL_FLOAT: case GL_DOUBLE: return ctx->Extensions.ARB_texture_float ? GL_RGBA32F : ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; case GL_UNSIGNED_INT_5_9_9_9_REV: assert(ctx->Extensions.EXT_texture_shared_exponent); return GL_RGB9_E5; case GL_UNSIGNED_INT_10F_11F_11F_REV: assert(ctx->Extensions.EXT_packed_float); return GL_R11F_G11F_B10F; } } } }