/** * Called by glPolygonStipple. */ void GLAPIENTRY _mesa_PolygonStipple(const GLubyte *pattern) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glPolygonStipple\n"); FLUSH_VERTICES(ctx, _NEW_POLYGONSTIPPLE); pattern = _mesa_map_validate_pbo_source(ctx, 2, &ctx->Unpack, 32, 32, 1, GL_COLOR_INDEX, GL_BITMAP, INT_MAX, pattern, "glPolygonStipple"); if (!pattern) return; _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); _mesa_unmap_pbo_source(ctx, &ctx->Unpack); if (ctx->Driver.PolygonStipple) ctx->Driver.PolygonStipple(ctx, pattern); }
/** * Create a texture which represents a bitmap image. */ static struct pipe_resource * make_bitmap_texture(struct gl_context *ctx, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_transfer *transfer; ubyte *dest; struct pipe_resource *pt; /* PBO source... */ bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap); if (!bitmap) { return NULL; } /** * Create texture to hold bitmap pattern. */ pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format, 0, width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); if (!pt) { _mesa_unmap_pbo_source(ctx, unpack); return NULL; } transfer = pipe_get_transfer(st->pipe, pt, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, width, height); dest = pipe_transfer_map(pipe, transfer); /* Put image into texture transfer */ memset(dest, 0xff, height * transfer->stride); unpack_bitmap(st, 0, 0, width, height, unpack, bitmap, dest, transfer->stride); _mesa_unmap_pbo_source(ctx, unpack); /* Release transfer */ pipe_transfer_unmap(pipe, transfer); pipe->transfer_destroy(pipe, transfer); return pt; }
static 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 (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, GL_INTENSITY, GL_UNSIGNED_SHORT, INT_MAX, values)) { return; } values = (const GLushort *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); if (!values) { if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapusv(PBO is mapped)"); } 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] ); } } _mesa_unmap_pbo_source(ctx, &ctx->Unpack); store_pixelmap(ctx, map, mapsize, fvalues); }
/** * This routine updates the ctx->Polygon.Stipple state. * If we're getting the stipple data from a PBO, we map the buffer * in order to access the data. * In any case, we obey the current pixel unpacking parameters when fetching * the stipple data. * * In the future, this routine should be used as a fallback, called via * ctx->Driver.PolygonStipple(). We'll have to update all the DRI drivers * too. */ void _mesa_polygon_stipple(GLcontext *ctx, const GLubyte *pattern) { pattern = _mesa_map_validate_pbo_source(ctx, 2, &ctx->Unpack, 32, 32, 1, GL_COLOR_INDEX, GL_BITMAP, pattern, "glPolygonStipple"); if (!pattern) return; _mesa_unpack_polygon_stipple(pattern, ctx->PolygonStipple, &ctx->Unpack); _mesa_unmap_pbo_source(ctx, &ctx->Unpack); }
static 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_is_pow_two(mapsize)) { _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" ); return; } } FLUSH_VERTICES(ctx, _NEW_PIXEL); if (!validate_pbo_access(ctx, &ctx->Unpack, mapsize, GL_INTENSITY, GL_FLOAT, INT_MAX, values)) { return; } values = (const GLfloat *) _mesa_map_pbo_source(ctx, &ctx->Unpack, values); if (!values) { if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glPixelMapfv(PBO is mapped)"); } return; } store_pixelmap(ctx, map, mapsize, values); _mesa_unmap_pbo_source(ctx, &ctx->Unpack); }
/** * 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) { data = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack, count, 1, 1, format, type, data, "glColor[Sub]Table"); if (!data) return; { /* 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]); } } _mesa_unmap_pbo_source(ctx, &ctx->Unpack); }
/** * Try to accumulate this glBitmap call in the bitmap cache. * \return GL_TRUE for success, GL_FALSE if bitmap is too large, etc. */ static GLboolean accum_bitmap(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { struct st_context *st = ctx->st; struct bitmap_cache *cache = st->bitmap.cache; int px = -999, py = -999; const GLfloat z = ctx->Current.RasterPos[2]; if (width > BITMAP_CACHE_WIDTH || height > BITMAP_CACHE_HEIGHT) return GL_FALSE; /* too big to cache */ if (!cache->empty) { px = x - cache->xpos; /* pos in buffer */ py = y - cache->ypos; if (px < 0 || px + width > BITMAP_CACHE_WIDTH || py < 0 || py + height > BITMAP_CACHE_HEIGHT || !TEST_EQ_4V(ctx->Current.RasterColor, cache->color) || ((fabs(z - cache->zpos) > Z_EPSILON))) { /* This bitmap would extend beyond cache bounds, or the bitmap * color is changing * so flush and continue. */ st_flush_bitmap_cache(st); } } if (cache->empty) { /* Initialize. Center bitmap vertically in the buffer. */ px = 0; py = (BITMAP_CACHE_HEIGHT - height) / 2; cache->xpos = x; cache->ypos = y - py; cache->zpos = z; cache->empty = GL_FALSE; COPY_4FV(cache->color, ctx->Current.RasterColor); } assert(px != -999); assert(py != -999); if (x < cache->xmin) cache->xmin = x; if (y < cache->ymin) cache->ymin = y; if (x + width > cache->xmax) cache->xmax = x + width; if (y + height > cache->ymax) cache->ymax = y + height; /* create the transfer if needed */ create_cache_trans(st); /* PBO source... */ bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap); if (!bitmap) { return FALSE; } unpack_bitmap(st, px, py, width, height, unpack, bitmap, cache->buffer, BITMAP_CACHE_WIDTH); _mesa_unmap_pbo_source(ctx, unpack); return GL_TRUE; /* accumulated */ }
/** * Render a bitmap. * Called via ctx->Driver.Bitmap() * All parameter error checking will have been done before this is called. */ void _swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) { GLint row, col; GLuint count = 0; SWspan span; ASSERT(ctx->RenderMode == GL_RENDER); if (!_mesa_check_conditional_render(ctx)) return; /* don't draw */ bitmap = (const GLubyte *) _mesa_map_pbo_source(ctx, unpack, bitmap); if (!bitmap) return; swrast_render_start(ctx); if (SWRAST_CONTEXT(ctx)->NewState) _swrast_validate_derived( ctx ); INIT_SPAN(span, GL_BITMAP); span.end = width; span.arrayMask = SPAN_XY; _swrast_span_default_attribs(ctx, &span); for (row = 0; row < height; row++) { const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack, bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0); if (unpack->LsbFirst) { /* Lsb first */ GLubyte mask = 1U << (unpack->SkipPixels & 0x7); for (col = 0; col < width; col++) { if (*src & mask) { span.array->x[count] = px + col; span.array->y[count] = py + row; count++; } if (mask == 128U) { src++; mask = 1U; } else { mask = mask << 1; } } /* get ready for next row */ if (mask != 1) src++; } else { /* Msb first */ GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); for (col = 0; col < width; col++) { if (*src & mask) { span.array->x[count] = px + col; span.array->y[count] = py + row; count++; } if (mask == 1U) { src++; mask = 128U; } else { mask = mask >> 1; } } /* get ready for next row */ if (mask != 128) src++; } if (count + width >= SWRAST_MAX_WIDTH || row + 1 == height) { /* flush the span */ span.end = count; _swrast_write_rgba_span(ctx, &span); span.end = 0; count = 0; } } swrast_render_finish(ctx); _mesa_unmap_pbo_source(ctx, unpack); }
/** * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we * can't use a fragment shader to write stencil values. */ static void draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_renderbuffer *strb; enum pipe_transfer_usage usage; struct pipe_transfer *pt; const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; GLint skipPixels; ubyte *stmap; struct gl_pixelstore_attrib clippedUnpack = *unpack; if (!zoom) { if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, &clippedUnpack)) { /* totally clipped */ return; } } strb = st_renderbuffer(ctx->DrawBuffer-> Attachment[BUFFER_STENCIL].Renderbuffer); if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { y = ctx->DrawBuffer->Height - y - height; } if(format != GL_DEPTH_STENCIL && util_format_get_component_bits(strb->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) usage = PIPE_TRANSFER_READ_WRITE; else usage = PIPE_TRANSFER_WRITE; pt = pipe_get_transfer(pipe, strb->texture, strb->rtt_level, strb->rtt_face + strb->rtt_slice, usage, x, y, width, height); stmap = pipe_transfer_map(pipe, pt); pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); assert(pixels); /* if width > MAX_WIDTH, have to process image in chunks */ skipPixels = 0; while (skipPixels < width) { const GLint spanX = skipPixels; const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); GLint row; for (row = 0; row < height; row++) { GLubyte sValues[MAX_WIDTH]; GLuint zValues[MAX_WIDTH]; GLenum destType = GL_UNSIGNED_BYTE; const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, width, height, format, type, row, skipPixels); _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, type, source, &clippedUnpack, ctx->_ImageTransferState); if (format == GL_DEPTH_STENCIL) { _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, zValues, (1 << 24) - 1, type, source, &clippedUnpack); } if (zoom) { _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " "zoom not complete"); } { GLint spanY; if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { spanY = height - row - 1; } else { spanY = row; } /* now pack the stencil (and Z) values in the dest format */ switch (pt->resource->format) { case PIPE_FORMAT_S8_USCALED: { ubyte *dest = stmap + spanY * pt->stride + spanX; assert(usage == PIPE_TRANSFER_WRITE); memcpy(dest, sValues, spanWidth); } break; case PIPE_FORMAT_Z24_UNORM_S8_USCALED: if (format == GL_DEPTH_STENCIL) { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = zValues[k] | (sValues[k] << 24); } } else { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_READ_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); } } break; case PIPE_FORMAT_S8_USCALED_Z24_UNORM: if (format == GL_DEPTH_STENCIL) { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); } } else { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; assert(usage == PIPE_TRANSFER_READ_WRITE); for (k = 0; k < spanWidth; k++) { dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); } } break; default: assert(0); } } } skipPixels += spanWidth; } _mesa_unmap_pbo_source(ctx, &clippedUnpack); /* unmap the stencil buffer */ pipe_transfer_unmap(pipe, pt); pipe->transfer_destroy(pipe, pt); }
/** * Make texture containing an image for glDrawPixels image. * If 'pixels' is NULL, leave the texture image data undefined. */ static struct pipe_resource * make_texture(struct st_context *st, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { struct gl_context *ctx = st->ctx; struct pipe_context *pipe = st->pipe; gl_format mformat; struct pipe_resource *pt; enum pipe_format pipeFormat; GLenum baseInternalFormat, intFormat; intFormat = internal_format(ctx, format, type); baseInternalFormat = _mesa_base_tex_format(ctx, intFormat); mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, format, type, GL_FALSE); assert(mformat); pipeFormat = st_mesa_format_to_pipe_format(mformat); assert(pipeFormat); pixels = _mesa_map_pbo_source(ctx, unpack, pixels); if (!pixels) return NULL; /* alloc temporary texture */ pt = alloc_texture(st, width, height, pipeFormat); if (!pt) { _mesa_unmap_pbo_source(ctx, unpack); return NULL; } { struct pipe_transfer *transfer; static const GLuint dstImageOffsets = 0; GLboolean success; GLubyte *dest; const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; /* we'll do pixel transfer in a fragment shader */ ctx->_ImageTransferState = 0x0; transfer = pipe_get_transfer(st->pipe, pt, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, width, height); /* map texture transfer */ dest = pipe_transfer_map(pipe, transfer); /* Put image into texture transfer. * Note that the image is actually going to be upside down in * the texture. We deal with that with texcoords. */ success = _mesa_texstore(ctx, 2, /* dims */ baseInternalFormat, /* baseInternalFormat */ mformat, /* gl_format */ dest, /* dest */ 0, 0, 0, /* dstX/Y/Zoffset */ transfer->stride, /* dstRowStride, bytes */ &dstImageOffsets, /* dstImageOffsets */ width, height, 1, /* size */ format, type, /* src format/type */ pixels, /* data source */ unpack); /* unmap */ pipe_transfer_unmap(pipe, transfer); pipe->transfer_destroy(pipe, transfer); assert(success); /* restore */ ctx->_ImageTransferState = imageTransferStateSave; } _mesa_unmap_pbo_source(ctx, unpack); return pt; }