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); }
/** * glGetTexImagefor sRGB pixels; */ static void get_tex_srgb(GLcontext *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, const struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; const GLbitfield transferOps = 0x0; GLint img, row; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); GLfloat rgba[MAX_WIDTH][4]; GLint col; /* convert row to RGBA format */ for (col = 0; col < width; col++) { texImage->FetchTexelf(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_RGB || texImage->_BaseFormat == GL_RGBA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } } }
static void GLAPIENTRY _mesa_GetColorTable( GLenum target, GLenum format, GLenum type, GLvoid *data ) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); 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_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: /* try texture targets */ { struct gl_texture_object *texobj = _mesa_select_tex_object(ctx, texUnit, target); if (texobj && !_mesa_is_proxy_texture(target)) { table = &texobj->Palette; } else { _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; } data = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack, table->Size, 1, 1, format, type, data, "glGetColorTable"); if (!data) return; _mesa_pack_rgba_span_float(ctx, table->Size, rgba, format, type, data, &ctx->Pack, 0x0); _mesa_unmap_pbo_dest(ctx, &ctx->Pack); }
static void GLAPIENTRY _mesa_GetnColorTableARB( GLenum target, GLenum format, GLenum type, GLsizei bufSize, GLvoid *data ) { GET_CURRENT_CONTEXT(ctx); struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); struct gl_color_table *table = NULL; GLfloat rgba[MAX_COLOR_TABLE_SIZE][4]; GLbitfield transferOps = 0; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (ctx->NewState) { _mesa_update_state(ctx); } switch (target) { case GL_SHARED_TEXTURE_PALETTE_EXT: table = &ctx->Texture.Palette; break; default: /* try texture targets */ { struct gl_texture_object *texobj = _mesa_select_tex_object(ctx, texUnit, target); if (texobj && !_mesa_is_proxy_texture(target)) { table = &texobj->Palette; } else { _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: memcpy(rgba, table->TableF, 4 * table->Size * sizeof(GLfloat)); break; default: _mesa_problem(ctx, "bad table format in glGetColorTable"); return; } data = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack, table->Size, 1, 1, format, type, bufSize, data, "glGetColorTable"); if (!data) return; /* TODO: is this correct? */ if(ctx->Color._ClampReadColor) transferOps |= IMAGE_CLAMP_BIT; _mesa_pack_rgba_span_float(ctx, table->Size, rgba, format, type, data, &ctx->Pack, transferOps); _mesa_unmap_pbo_dest(ctx, &ctx->Pack); }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_resource *dst_texture; struct pipe_blit_info blit; unsigned bind = (PIPE_BIND_RENDER_TARGET | PIPE_BIND_TRANSFER_READ); struct pipe_transfer *tex_xfer; ubyte *map; /* create temp / dest surface */ if (!util_create_rgba_texture(pipe, width, height, bind, &dst_texture)) { _mesa_problem(ctx, "util_create_rgba_texture() failed " "in decompress_with_blit()"); return; } blit.src.resource = stObj->pt; blit.src.level = texImage->Level; blit.src.format = util_format_linear(stObj->pt->format); blit.dst.resource = dst_texture; blit.dst.level = 0; blit.dst.format = dst_texture->format; blit.src.box.x = blit.dst.box.x = 0; blit.src.box.y = blit.dst.box.y = 0; blit.src.box.z = 0; /* XXX compressed array textures? */ blit.dst.box.z = 0; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = 1; blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; /* blit/render/decompress */ st->pipe->blit(st->pipe, &blit); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); map = pipe_transfer_map(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height, &tex_xfer); if (!map) { goto end; } /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); /* map the dst_surface so we can read from it */ GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: if (map) pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe_resource_reference(&dst_texture, NULL); }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); struct pipe_sampler_view *src_view; const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_surface *dst_surface; struct pipe_resource *dst_texture; struct pipe_transfer *tex_xfer; unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */ PIPE_BIND_TRANSFER_READ); /* create temp / dest surface */ if (!util_create_rgba_surface(pipe, width, height, bind, &dst_texture, &dst_surface)) { _mesa_problem(ctx, "util_create_rgba_surface() failed " "in decompress_with_blit()"); return; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } /* Create sampler view that limits fetches to the source mipmap level */ { struct pipe_sampler_view sv_temp; u_sampler_view_default_template(&sv_temp, stObj->pt, stObj->pt->format); sv_temp.format = util_format_linear(sv_temp.format); sv_temp.u.tex.first_level = sv_temp.u.tex.last_level = texImage->Level; src_view = pipe->create_sampler_view(pipe, stObj->pt, &sv_temp); if (!src_view) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); return; } } /* blit/render/decompress */ util_blit_pixels_tex(st->blit, src_view, /* pipe_resource (src) */ 0, 0, /* src x0, y0 */ width, height, /* src x1, y1 */ dst_surface, /* pipe_surface (dst) */ 0, 0, /* dst x0, y0 */ width, height, /* dst x1, y1 */ 0.0, /* z */ PIPE_TEX_MIPFILTER_NEAREST); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } /* map the dst_surface so we can read from it */ tex_xfer = pipe_get_transfer(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); ubyte *map = pipe_transfer_map(pipe, tex_xfer); GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe->transfer_destroy(pipe, tex_xfer); /* destroy the temp / dest surface */ util_destroy_rgba_surface(dst_texture, dst_surface); pipe_sampler_view_release(pipe, &src_view); }
static void GLAPIENTRY _mesa_GetMinmax(GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) { GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); if (!ctx->Extensions.EXT_histogram && !ctx->Extensions.ARB_imaging) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetMinmax"); return; } if (target != GL_MINMAX) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetMinmax(target)"); return; } if (format != GL_RED && format != GL_GREEN && format != GL_BLUE && format != GL_ALPHA && format != GL_RGB && format != GL_BGR && format != GL_RGBA && format != GL_BGRA && format != GL_ABGR_EXT && format != GL_LUMINANCE && format != GL_LUMINANCE_ALPHA) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetMinMax(format)"); } if (!_mesa_is_legal_format_and_type(ctx, format, type)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetMinmax(format or type)"); return; } values = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack, 2, 1, 1, format, type, values, "glGetMinmax"); if (!values) return; { GLfloat minmax[2][4]; minmax[0][RCOMP] = CLAMP(ctx->MinMax.Min[RCOMP], 0.0F, 1.0F); minmax[0][GCOMP] = CLAMP(ctx->MinMax.Min[GCOMP], 0.0F, 1.0F); minmax[0][BCOMP] = CLAMP(ctx->MinMax.Min[BCOMP], 0.0F, 1.0F); minmax[0][ACOMP] = CLAMP(ctx->MinMax.Min[ACOMP], 0.0F, 1.0F); minmax[1][RCOMP] = CLAMP(ctx->MinMax.Max[RCOMP], 0.0F, 1.0F); minmax[1][GCOMP] = CLAMP(ctx->MinMax.Max[GCOMP], 0.0F, 1.0F); minmax[1][BCOMP] = CLAMP(ctx->MinMax.Max[BCOMP], 0.0F, 1.0F); minmax[1][ACOMP] = CLAMP(ctx->MinMax.Max[ACOMP], 0.0F, 1.0F); _mesa_pack_rgba_span_float(ctx, 2, minmax, format, type, values, &ctx->Pack, 0x0); } _mesa_unmap_pbo_dest(ctx, &ctx->Pack); if (reset) { _mesa_ResetMinmax(GL_MINMAX); } }
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); } }
/** * Get an uncompressed color texture image. */ static void get_tex_rgba_uncompressed(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage, GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ const gl_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); const GLuint width = texImage->Width; const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); GLenum rebaseFormat = GL_NONE; GLuint height = texImage->Height; GLuint depth = texImage->Depth; GLuint img, row; GLfloat (*rgba)[4]; GLuint (*rgba_uint)[4]; GLboolean tex_is_integer = _mesa_is_format_integer_color(texImage->TexFormat); GLboolean tex_is_uint = _mesa_is_format_unsigned(texImage->TexFormat); /* Allocate buffer for one row of texels */ rgba = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); rgba_uint = (GLuint (*)[4]) rgba; if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); return; } if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { depth = height; height = 1; } if (texImage->_BaseFormat == GL_LUMINANCE || texImage->_BaseFormat == GL_INTENSITY || texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { /* If a luminance (or intensity) texture is read back as RGB(A), the * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat * here to get G=B=0. */ rebaseFormat = texImage->_BaseFormat; } else if ((texImage->_BaseFormat == GL_RGBA || texImage->_BaseFormat == GL_RGB || texImage->_BaseFormat == GL_RG) && (destBaseFormat == GL_LUMINANCE || destBaseFormat == GL_LUMINANCE_ALPHA || destBaseFormat == GL_LUMINANCE_INTEGER_EXT || destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { /* If we're reading back an RGB(A) texture as luminance then we need * to return L=tex(R). Note, that's different from glReadPixels which * returns L=R+G+B. */ rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ } for (img = 0; img < depth; img++) { GLubyte *srcMap; GLint rowstride; /* map src texture buffer */ ctx->Driver.MapTextureImage(ctx, texImage, img, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &rowstride); if (srcMap) { for (row = 0; row < height; row++) { const GLubyte *src = srcMap + row * rowstride; void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); if (tex_is_integer) { _mesa_unpack_uint_rgba_row(texFormat, width, src, rgba_uint); if (rebaseFormat) _mesa_rebase_rgba_uint(width, rgba_uint, rebaseFormat); if (tex_is_uint) { _mesa_pack_rgba_span_from_uints(ctx, width, (GLuint (*)[4]) rgba_uint, format, type, dest); } else { _mesa_pack_rgba_span_from_ints(ctx, width, (GLint (*)[4]) rgba_uint, format, type, dest); } } else { _mesa_unpack_rgba_row(texFormat, width, src, rgba); if (rebaseFormat) _mesa_rebase_rgba_float(width, rgba, rebaseFormat); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } } /* Unmap the src texture buffer */ ctx->Driver.UnmapTextureImage(ctx, texImage, img); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); break; } } free(rgba); }
/** * Get a color texture image with decompression. */ static void get_tex_rgba_compressed(struct gl_context *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage, GLbitfield transferOps) { /* don't want to apply sRGB -> RGB conversion here so override the format */ const gl_format texFormat = _mesa_get_srgb_format_linear(texImage->TexFormat); const GLenum baseFormat = _mesa_get_format_base_format(texFormat); const GLenum destBaseFormat = _mesa_base_tex_format(ctx, format); GLenum rebaseFormat = GL_NONE; const GLuint width = texImage->Width; const GLuint height = texImage->Height; const GLuint depth = texImage->Depth; GLfloat *tempImage, *srcRow; GLuint row; /* Decompress into temp float buffer, then pack into user buffer */ tempImage = (GLfloat *) malloc(width * height * depth * 4 * sizeof(GLfloat)); if (!tempImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); return; } /* Decompress the texture image - results in 'tempImage' */ { GLubyte *srcMap; GLint srcRowStride; ctx->Driver.MapTextureImage(ctx, texImage, 0, 0, 0, width, height, GL_MAP_READ_BIT, &srcMap, &srcRowStride); if (srcMap) { _mesa_decompress_image(texFormat, width, height, srcMap, srcRowStride, tempImage); ctx->Driver.UnmapTextureImage(ctx, texImage, 0); } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); free(tempImage); return; } } if (baseFormat == GL_LUMINANCE || baseFormat == GL_INTENSITY || baseFormat == GL_LUMINANCE_ALPHA) { /* If a luminance (or intensity) texture is read back as RGB(A), the * returned value should be (L,0,0,1), not (L,L,L,1). Set rebaseFormat * here to get G=B=0. */ rebaseFormat = texImage->_BaseFormat; } else if ((baseFormat == GL_RGBA || baseFormat == GL_RGB || baseFormat == GL_RG) && (destBaseFormat == GL_LUMINANCE || destBaseFormat == GL_LUMINANCE_ALPHA || destBaseFormat == GL_LUMINANCE_INTEGER_EXT || destBaseFormat == GL_LUMINANCE_ALPHA_INTEGER_EXT)) { /* If we're reading back an RGB(A) texture as luminance then we need * to return L=tex(R). Note, that's different from glReadPixels which * returns L=R+G+B. */ rebaseFormat = GL_LUMINANCE_ALPHA; /* this covers GL_LUMINANCE too */ } if (rebaseFormat) { _mesa_rebase_rgba_float(width * height, (GLfloat (*)[4]) tempImage, rebaseFormat); } srcRow = tempImage; for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, 0, row, 0); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) srcRow, format, type, dest, &ctx->Pack, transferOps); srcRow += width * 4; } free(tempImage); }
/** * glGetTexImagefor RGBA, Luminance, etc. pixels. * This is the slow way since we use texture sampling. */ static void get_tex_rgba(GLcontext *ctx, GLuint dimensions, GLenum format, GLenum type, GLvoid *pixels, const struct gl_texture_image *texImage) { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; /* Normally, no pixel transfer ops are performed during glGetTexImage. * The only possible exception is component clamping to [0,1]. */ GLbitfield transferOps = 0x0; GLint img, row; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); GLfloat rgba[MAX_WIDTH][4]; GLint col; GLenum dataType = _mesa_get_format_datatype(texImage->TexFormat); /* clamp does not apply to GetTexImage (final conversion)? * Looks like we need clamp though when going from format * containing negative values to unsigned format. */ if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) { transferOps |= IMAGE_CLAMP_BIT; } else if (!type_with_negative_values(type) && (dataType == GL_FLOAT || dataType == GL_SIGNED_NORMALIZED)) { transferOps |= IMAGE_CLAMP_BIT; } for (col = 0; col < width; col++) { texImage->FetchTexelf(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_ALPHA) { rgba[col][RCOMP] = 0.0F; rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; } else if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; rgba[col][ACOMP] = 1.0F; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; } else if (texImage->_BaseFormat == GL_INTENSITY) { rgba[col][GCOMP] = 0.0F; rgba[col][BCOMP] = 0.0F; rgba[col][ACOMP] = 1.0F; } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } } }
/** * This is the software fallback for Driver.GetTexImage(). * All error checking will have been done before this routine is called. */ void _mesa_get_teximage(GLcontext *ctx, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_object *texObj, struct gl_texture_image *texImage) { const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2; if (ctx->Pack.BufferObj->Name) { /* Packing texture image into a PBO. * Map the (potentially) VRAM-based buffer into our process space so * we can write into it with the code below. * A hardware driver might use a sophisticated blit to move the * texture data to the PBO if the PBO is in VRAM along with the texture. */ GLubyte *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,"glGetTexImage(PBO is mapped)"); return; } /* <pixels> was an offset into the PBO. * Now make it a real, client-side pointer inside the mapped region. */ pixels = ADD_POINTERS(buf, pixels); } else if (!pixels) { /* not an error */ return; } { const GLint width = texImage->Width; const GLint height = texImage->Height; const GLint depth = texImage->Depth; GLint img, row; for (img = 0; img < depth; img++) { for (row = 0; row < height; row++) { /* compute destination address in client memory */ GLvoid *dest = _mesa_image_address( dimensions, &ctx->Pack, pixels, width, height, format, type, img, row, 0); assert(dest); if (format == GL_COLOR_INDEX) { GLuint indexRow[MAX_WIDTH]; GLint col; /* Can't use FetchTexel here because that returns RGBA */ if (texImage->TexFormat->IndexBits == 8) { const GLubyte *src = (const GLubyte *) texImage->Data; src += width * (img * texImage->Height + row); for (col = 0; col < width; col++) { indexRow[col] = src[col]; } } else if (texImage->TexFormat->IndexBits == 16) { const GLushort *src = (const GLushort *) texImage->Data; src += width * (img * texImage->Height + row); for (col = 0; col < width; col++) { indexRow[col] = src[col]; } } else { _mesa_problem(ctx, "Color index problem in _mesa_GetTexImage"); } _mesa_pack_index_span(ctx, width, type, dest, indexRow, &ctx->Pack, 0 /* no image transfer */); } else if (format == GL_DEPTH_COMPONENT) { GLfloat depthRow[MAX_WIDTH]; GLint col; for (col = 0; col < width; col++) { (*texImage->FetchTexelf)(texImage, col, row, img, depthRow + col); } _mesa_pack_depth_span(ctx, width, dest, type, depthRow, &ctx->Pack); } else if (format == GL_DEPTH_STENCIL_EXT) { /* XXX Note: we're bypassing texImage->FetchTexel()! */ const GLuint *src = (const GLuint *) texImage->Data; src += width * row + width * height * img; _mesa_memcpy(dest, src, width * sizeof(GLuint)); if (ctx->Pack.SwapBytes) { _mesa_swap4((GLuint *) dest, width); } } else if (format == GL_YCBCR_MESA) { /* No pixel transfer */ const GLint rowstride = texImage->RowStride; MEMCPY(dest, (const GLushort *) texImage->Data + row * rowstride, width * sizeof(GLushort)); /* check for byte swapping */ if ((texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR && type == GL_UNSIGNED_SHORT_8_8_REV_MESA) || (texImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV && type == GL_UNSIGNED_SHORT_8_8_MESA)) { if (!ctx->Pack.SwapBytes) _mesa_swap2((GLushort *) dest, width); } else if (ctx->Pack.SwapBytes) { _mesa_swap2((GLushort *) dest, width); } } #if FEATURE_EXT_texture_sRGB else if (is_srgb_teximage(texImage)) { /* special case this since need to backconvert values */ /* convert row to RGBA format */ GLfloat rgba[MAX_WIDTH][4]; GLint col; GLbitfield transferOps = 0x0; for (col = 0; col < width; col++) { (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_RGB || texImage->_BaseFormat == GL_RGBA) { rgba[col][RCOMP] = linear_to_nonlinear(rgba[col][RCOMP]); rgba[col][GCOMP] = linear_to_nonlinear(rgba[col][GCOMP]); rgba[col][BCOMP] = linear_to_nonlinear(rgba[col][BCOMP]); } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } #endif /* FEATURE_EXT_texture_sRGB */ else { /* general case: convert row to RGBA format */ GLfloat rgba[MAX_WIDTH][4]; GLint col; GLbitfield transferOps = 0x0; /* clamp does not apply to GetTexImage (final conversion)? * Looks like we need clamp though when going from format * containing negative values to unsigned format. */ if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA) transferOps |= IMAGE_CLAMP_BIT; else if (!type_with_negative_values(type) && (texImage->TexFormat->DataType == GL_FLOAT || texImage->TexFormat->DataType == GL_SIGNED_NORMALIZED)) transferOps |= IMAGE_CLAMP_BIT; for (col = 0; col < width; col++) { (*texImage->FetchTexelf)(texImage, col, row, img, rgba[col]); if (texImage->_BaseFormat == GL_ALPHA) { rgba[col][RCOMP] = 0.0; rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_LUMINANCE) { rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; rgba[col][ACOMP] = 1.0; } else if (texImage->_BaseFormat == GL_LUMINANCE_ALPHA) { rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; } else if (texImage->_BaseFormat == GL_INTENSITY) { rgba[col][GCOMP] = 0.0; rgba[col][BCOMP] = 0.0; rgba[col][ACOMP] = 1.0; } } _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } /* format */ } /* row */ } /* img */ } if (ctx->Pack.BufferObj->Name) { ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, ctx->Pack.BufferObj); } }