static void reset_cache(struct st_context *st) { struct pipe_context *pipe = st->pipe; struct bitmap_cache *cache = st->bitmap.cache; /*memset(cache->buffer, 0xff, sizeof(cache->buffer));*/ cache->empty = GL_TRUE; cache->xmin = 1000000; cache->xmax = -1000000; cache->ymin = 1000000; cache->ymax = -1000000; if (cache->trans) { pipe->transfer_destroy(pipe, cache->trans); cache->trans = NULL; } assert(!cache->texture); /* allocate a new texture */ cache->texture = st_texture_create(st, PIPE_TEXTURE_2D, st->bitmap.tex_format, 0, BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, 1, 1, PIPE_BIND_SAMPLER_VIEW); }
/** * Create a temporary texture to hold an image of the given size. * If width, height are not POT and the driver only handles POT textures, * allocate the next larger size of texture that is POT. */ static struct pipe_resource * alloc_texture(struct st_context *st, GLsizei width, GLsizei height, enum pipe_format texFormat) { struct pipe_resource *pt; pt = st_texture_create(st, st->internal_target, texFormat, 0, width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); return pt; }
/** * Called via ctx->Driver.AllocTextureStorage() to allocate texture memory * for a whole mipmap stack. */ static GLboolean st_AllocTextureStorage(struct gl_context *ctx, struct gl_texture_object *texObj, GLsizei levels, GLsizei width, GLsizei height, GLsizei depth) { const GLuint numFaces = _mesa_num_tex_faces(texObj->Target); struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); GLuint ptWidth, ptHeight, ptDepth, ptLayers, bindings; enum pipe_format fmt; GLint level; assert(levels > 0); /* Save the level=0 dimensions */ stObj->width0 = width; stObj->height0 = height; stObj->depth0 = depth; stObj->lastLevel = levels - 1; fmt = st_mesa_format_to_pipe_format(texObj->Image[0][0]->TexFormat); bindings = default_bindings(st, fmt); st_gl_texture_dims_to_pipe_dims(texObj->Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); stObj->pt = st_texture_create(st, gl_target_to_pipe(texObj->Target), fmt, levels, ptWidth, ptHeight, ptDepth, ptLayers, bindings); if (!stObj->pt) return GL_FALSE; /* Set image resource pointers */ for (level = 0; level < levels; level++) { GLuint face; for (face = 0; face < numFaces; face++) { struct st_texture_image *stImage = st_texture_image(texObj->Image[face][level]); pipe_resource_reference(&stImage->pt, stObj->pt); } } return GL_TRUE; }
static struct pipe_texture * create_color_map_texture(GLcontext *ctx) { struct pipe_context *pipe = ctx->st->pipe; struct pipe_texture *pt; enum pipe_format format; const uint texSize = 256; /* simple, and usually perfect */ /* find an RGBA texture format */ format = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D, PIPE_TEXTURE_USAGE_SAMPLER); /* create texture for color map/table */ pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, 0, texSize, texSize, 1, PIPE_TEXTURE_USAGE_SAMPLER); return pt; }
/** * 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; }
struct pipe_resource * st_create_color_map_texture(struct gl_context *ctx) { struct st_context *st = st_context(ctx); struct pipe_resource *pt; enum pipe_format format; const uint texSize = 256; /* simple, and usually perfect */ /* find an RGBA texture format */ format = st_choose_format(st, GL_RGBA, GL_NONE, GL_NONE, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW, FALSE); /* create texture for color map/table */ pt = st_texture_create(st, PIPE_TEXTURE_2D, format, 0, texSize, texSize, 1, 1, 0, PIPE_BIND_SAMPLER_VIEW); return pt; }
static void reset_cache(struct st_context *st) { struct bitmap_cache *cache = st->bitmap.cache; /*memset(cache->buffer, 0xff, sizeof(cache->buffer));*/ cache->empty = GL_TRUE; cache->xmin = 1000000; cache->xmax = -1000000; cache->ymin = 1000000; cache->ymax = -1000000; assert(!cache->texture); /* allocate a new texture */ cache->texture = st_texture_create(st, st->internal_target, st->bitmap.tex_format, 0, BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, 1, 1, 0, PIPE_BIND_SAMPLER_VIEW); }
/** * Called via ctx->Driver.GenerateMipmap(). */ void st_generate_mipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct pipe_resource *pt = st_get_texobj_resource(texObj); const uint baseLevel = texObj->BaseLevel; uint lastLevel, first_layer, last_layer; uint dstLevel; if (!pt) return; /* not sure if this ultimately actually should work, but we're not supporting multisampled textures yet. */ assert(pt->nr_samples < 2); /* find expected last mipmap level to generate*/ lastLevel = compute_num_levels(ctx, texObj, target) - 1; if (lastLevel == 0) return; /* The texture isn't in a "complete" state yet so set the expected * lastLevel here, since it won't get done in st_finalize_texture(). */ stObj->lastLevel = lastLevel; if (pt->last_level < lastLevel) { /* The current gallium texture doesn't have space for all the * mipmap levels we need to generate. So allocate a new texture. */ struct pipe_resource *oldTex = stObj->pt; /* create new texture with space for more levels */ stObj->pt = st_texture_create(st, oldTex->target, oldTex->format, lastLevel, oldTex->width0, oldTex->height0, oldTex->depth0, oldTex->array_size, 0, oldTex->bind); /* This will copy the old texture's base image into the new texture * which we just allocated. */ st_finalize_texture(ctx, st->pipe, texObj); /* release the old tex (will likely be freed too) */ pipe_resource_reference(&oldTex, NULL); st_texture_release_all_sampler_views(stObj); } else { /* Make sure that the base texture image data is present in the * texture buffer. */ st_finalize_texture(ctx, st->pipe, texObj); } pt = stObj->pt; assert(pt->last_level >= lastLevel); if (pt->target == PIPE_TEXTURE_CUBE) { first_layer = last_layer = _mesa_tex_target_to_face(target); } else { first_layer = 0; last_layer = util_max_layer(pt, baseLevel); } /* Try to generate the mipmap by rendering/texturing. If that fails, * use the software fallback. */ if (!util_gen_mipmap(st->pipe, pt, pt->format, baseLevel, lastLevel, first_layer, last_layer, PIPE_TEX_FILTER_LINEAR)) { _mesa_generate_mipmap(ctx, target, texObj); } /* Fill in the Mesa gl_texture_image fields */ for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { const uint srcLevel = dstLevel - 1; const struct gl_texture_image *srcImage = _mesa_get_tex_image(ctx, texObj, target, srcLevel); struct gl_texture_image *dstImage; struct st_texture_image *stImage; uint border = srcImage->Border; uint dstWidth, dstHeight, dstDepth; dstWidth = u_minify(pt->width0, dstLevel); if (texObj->Target == GL_TEXTURE_1D_ARRAY) { dstHeight = pt->array_size; } else { dstHeight = u_minify(pt->height0, dstLevel); } if (texObj->Target == GL_TEXTURE_2D_ARRAY || texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) { dstDepth = pt->array_size; } else { dstDepth = u_minify(pt->depth0, dstLevel); } dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel); if (!dstImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); return; } /* Free old image data */ ctx->Driver.FreeTextureImageBuffer(ctx, dstImage); /* initialize new image */ _mesa_init_teximage_fields(ctx, dstImage, dstWidth, dstHeight, dstDepth, border, srcImage->InternalFormat, srcImage->TexFormat); stImage = st_texture_image(dstImage); pipe_resource_reference(&stImage->pt, pt); } }
/** * Called via ctx->Driver.AllocTextureImageBuffer(). * If the texture object/buffer already has space for the indicated image, * we're done. Otherwise, allocate memory for the new texture image. */ static GLboolean st_AllocTextureImageBuffer(struct gl_context *ctx, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); const GLuint level = texImage->Level; GLuint width = texImage->Width; GLuint height = texImage->Height; GLuint depth = texImage->Depth; DBG("%s\n", __FUNCTION__); assert(!stImage->TexData); assert(!stImage->pt); /* xxx this might be wrong */ /* Look if the parent texture object has space for this image */ if (stObj->pt && level <= stObj->pt->last_level && st_texture_match_image(stObj->pt, texImage)) { /* this image will fit in the existing texture object's memory */ pipe_resource_reference(&stImage->pt, stObj->pt); return GL_TRUE; } /* The parent texture object does not have space for this image */ pipe_resource_reference(&stObj->pt, NULL); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); if (!guess_and_alloc_texture(st, stObj, stImage)) { /* Probably out of memory. * Try flushing any pending rendering, then retry. */ st_finish(st); if (!guess_and_alloc_texture(st, stObj, stImage)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return GL_FALSE; } } if (stObj->pt && st_texture_match_image(stObj->pt, texImage)) { /* The image will live in the object's mipmap memory */ pipe_resource_reference(&stImage->pt, stObj->pt); assert(stImage->pt); return GL_TRUE; } else { /* Create a new, temporary texture/resource/buffer to hold this * one texture image. Note that when we later access this image * (either for mapping or copying) we'll want to always specify * mipmap level=0, even if the image represents some other mipmap * level. */ enum pipe_format format = st_mesa_format_to_pipe_format(texImage->TexFormat); GLuint bindings = default_bindings(st, format); GLuint ptWidth, ptHeight, ptDepth, ptLayers; st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); stImage->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), format, 0, /* lastLevel */ ptWidth, ptHeight, ptDepth, ptLayers, bindings); return stImage->pt != NULL; } }
/** * Try to allocate a pipe_resource object for the given st_texture_object. * * We use the given st_texture_image as a clue to determine the size of the * mipmap image at level=0. * * \return GL_TRUE for success, GL_FALSE if out of memory. */ static GLboolean guess_and_alloc_texture(struct st_context *st, struct st_texture_object *stObj, const struct st_texture_image *stImage) { GLuint lastLevel, width, height, depth; GLuint bindings; GLuint ptWidth, ptHeight, ptDepth, ptLayers; enum pipe_format fmt; DBG("%s\n", __FUNCTION__); assert(!stObj->pt); if (!guess_base_level_size(stObj->base.Target, stImage->base.Width2, stImage->base.Height2, stImage->base.Depth2, stImage->base.Level, &width, &height, &depth)) { /* we can't determine the image size at level=0 */ stObj->width0 = stObj->height0 = stObj->depth0 = 0; /* this is not an out of memory error */ return GL_TRUE; } /* At this point, (width x height x depth) is the expected size of * the level=0 mipmap image. */ /* Guess a reasonable value for lastLevel. With OpenGL we have no * idea how many mipmap levels will be in a texture until we start * to render with it. Make an educated guess here but be prepared * to re-allocating a texture buffer with space for more (or fewer) * mipmap levels later. */ if ((stObj->base.Sampler.MinFilter == GL_NEAREST || stObj->base.Sampler.MinFilter == GL_LINEAR || (stObj->base.BaseLevel == 0 && stObj->base.MaxLevel == 0) || stImage->base._BaseFormat == GL_DEPTH_COMPONENT || stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) && !stObj->base.GenerateMipmap && stImage->base.Level == 0) { /* only alloc space for a single mipmap level */ lastLevel = 0; } else { /* alloc space for a full mipmap */ lastLevel = _mesa_get_tex_max_num_levels(stObj->base.Target, width, height, depth) - 1; } /* Save the level=0 dimensions */ stObj->width0 = width; stObj->height0 = height; stObj->depth0 = depth; fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat); bindings = default_bindings(st, fmt); st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); stObj->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), fmt, lastLevel, ptWidth, ptHeight, ptDepth, ptLayers, bindings); stObj->lastLevel = lastLevel; DBG("%s returning %d\n", __FUNCTION__, (stObj->pt != NULL)); return stObj->pt != NULL; }
/** * Called during state validation. When this function is finished, * the texture object should be ready for rendering. * \return GL_TRUE for success, GL_FALSE for failure (out of mem) */ GLboolean st_finalize_texture(struct gl_context *ctx, struct pipe_context *pipe, struct gl_texture_object *tObj) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(tObj); const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; GLuint face; struct st_texture_image *firstImage; enum pipe_format firstImageFormat; GLuint ptWidth, ptHeight, ptDepth, ptLayers; if (_mesa_is_texture_complete(tObj, &tObj->Sampler)) { /* The texture is complete and we know exactly how many mipmap levels * are present/needed. This is conditional because we may be called * from the st_generate_mipmap() function when the texture object is * incomplete. In that case, we'll have set stObj->lastLevel before * we get here. */ if (stObj->base.Sampler.MinFilter == GL_LINEAR || stObj->base.Sampler.MinFilter == GL_NEAREST) stObj->lastLevel = stObj->base.BaseLevel; else stObj->lastLevel = stObj->base._MaxLevel; } firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); assert(firstImage); /* If both firstImage and stObj point to a texture which can contain * all active images, favour firstImage. Note that because of the * completeness requirement, we know that the image dimensions * will match. */ if (firstImage->pt && firstImage->pt != stObj->pt && (!stObj->pt || firstImage->pt->last_level >= stObj->pt->last_level)) { pipe_resource_reference(&stObj->pt, firstImage->pt); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); } /* Find gallium format for the Mesa texture */ firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat); /* Find size of level=0 Gallium mipmap image, plus number of texture layers */ { GLuint width, height, depth; if (!guess_base_level_size(stObj->base.Target, firstImage->base.Width2, firstImage->base.Height2, firstImage->base.Depth2, firstImage->base.Level, &width, &height, &depth)) { width = stObj->width0; height = stObj->height0; depth = stObj->depth0; } /* convert GL dims to Gallium dims */ st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); } /* If we already have a gallium texture, check that it matches the texture * object's format, target, size, num_levels, etc. */ if (stObj->pt) { if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) || !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) || stObj->pt->last_level < stObj->lastLevel || stObj->pt->width0 != ptWidth || stObj->pt->height0 != ptHeight || stObj->pt->depth0 != ptDepth || stObj->pt->array_size != ptLayers) { /* The gallium texture does not match the Mesa texture so delete the * gallium texture now. We'll make a new one below. */ pipe_resource_reference(&stObj->pt, NULL); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); st->dirty.st |= ST_NEW_FRAMEBUFFER; } } /* May need to create a new gallium texture: */ if (!stObj->pt) { GLuint bindings = default_bindings(st, firstImageFormat); stObj->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), firstImageFormat, stObj->lastLevel, ptWidth, ptHeight, ptDepth, ptLayers, bindings); if (!stObj->pt) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return GL_FALSE; } } /* Pull in any images not in the object's texture: */ for (face = 0; face < nr_faces; face++) { GLuint level; for (level = stObj->base.BaseLevel; level <= stObj->lastLevel; level++) { struct st_texture_image *stImage = st_texture_image(stObj->base.Image[face][level]); /* Need to import images in main memory or held in other textures. */ if (stImage && stObj->pt != stImage->pt) { if (level == 0 || (stImage->base.Width == u_minify(stObj->width0, level) && stImage->base.Height == u_minify(stObj->height0, level) && stImage->base.Depth == u_minify(stObj->depth0, level))) { /* src image fits expected dest mipmap level size */ copy_image_data_to_texture(st, stObj, level, stImage); } } } } return GL_TRUE; }
static void st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct st_context *st = ctx->st; struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct st_renderbuffer *rbRead; struct st_vertex_program *stvp; struct st_fragment_program *stfp; struct pipe_texture *pt; GLfloat *color; enum pipe_format srcFormat, texFormat; pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); st_validate_state(st); if (srcx < 0) { width -= -srcx; dstx += -srcx; srcx = 0; } if (srcy < 0) { height -= -srcy; dsty += -srcy; srcy = 0; } if (dstx < 0) { width -= -dstx; srcx += -dstx; dstx = 0; } if (dsty < 0) { height -= -dsty; srcy += -dsty; dsty = 0; } if (width < 0 || height < 0) return; if (type == GL_STENCIL) { /* can't use texturing to do stencil */ copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); return; } if (type == GL_COLOR) { rbRead = st_get_color_read_renderbuffer(ctx); color = NULL; stfp = combined_drawpix_fragment_program(ctx); stvp = st_make_passthrough_vertex_shader(ctx->st, GL_FALSE); } else { assert(type == GL_DEPTH); rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; stfp = make_fragment_shader_z(ctx->st); stvp = st_make_passthrough_vertex_shader(ctx->st, GL_TRUE); } srcFormat = rbRead->texture->format; if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D, PIPE_TEXTURE_USAGE_SAMPLER, 0)) { texFormat = srcFormat; } else { /* srcFormat can't be used as a texture format */ if (type == GL_DEPTH) { texFormat = st_choose_format(pipe, GL_DEPTH_COMPONENT, PIPE_TEXTURE_2D, PIPE_TEXTURE_USAGE_DEPTH_STENCIL); assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */ } else { /* default color format */ texFormat = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE_2D, PIPE_TEXTURE_USAGE_SAMPLER); assert(texFormat != PIPE_FORMAT_NONE); } } if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { srcy = ctx->DrawBuffer->Height - srcy - height; if (srcy < 0) { height -= -srcy; srcy = 0; } if (height < 0) return; } pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0, width, height, 1, PIPE_TEXTURE_USAGE_SAMPLER); if (!pt) return; if (srcFormat == texFormat) { /* copy source framebuffer surface into mipmap/texture */ struct pipe_surface *psRead = screen->get_tex_surface(screen, rbRead->texture, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_READ); struct pipe_surface *psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, PIPE_BUFFER_USAGE_GPU_WRITE ); pipe->surface_copy(pipe, psTex, /* dest */ 0, 0, /* destx/y */ psRead, srcx, srcy, width, height); pipe_surface_reference(&psRead, NULL); pipe_surface_reference(&psTex, NULL); } else { /* CPU-based fallback/conversion */ struct pipe_transfer *ptRead = st_cond_flush_get_tex_transfer(st, rbRead->texture, 0, 0, 0, PIPE_TRANSFER_READ, srcx, srcy, width, height); struct pipe_transfer *ptTex; enum pipe_transfer_usage transfer_usage; if (type == GL_DEPTH && pf_is_depth_and_stencil(pt->format)) transfer_usage = PIPE_TRANSFER_READ_WRITE; else transfer_usage = PIPE_TRANSFER_WRITE; ptTex = st_cond_flush_get_tex_transfer(st, pt, 0, 0, 0, transfer_usage, 0, 0, width, height); if (type == GL_COLOR) { /* alternate path using get/put_tile() */ GLfloat *buf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); pipe_get_tile_rgba(ptRead, 0, 0, width, height, buf); pipe_put_tile_rgba(ptTex, 0, 0, width, height, buf); _mesa_free(buf); } else { /* GL_DEPTH */ GLuint *buf = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint)); pipe_get_tile_z(ptRead, 0, 0, width, height, buf); pipe_put_tile_z(ptTex, 0, 0, width, height, buf); _mesa_free(buf); } screen->tex_transfer_destroy(ptRead); screen->tex_transfer_destroy(ptTex); } /* draw textured quad */ draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, pt, stvp, stfp, color, GL_TRUE); pipe_texture_reference(&pt, NULL); }
/** * Make texture containing an image for glDrawPixels image. * If 'pixels' is NULL, leave the texture image data undefined. */ static struct pipe_texture * make_texture(struct st_context *st, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { GLcontext *ctx = st->ctx; struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; const struct gl_texture_format *mformat; struct pipe_texture *pt; enum pipe_format pipeFormat; GLuint cpp; GLenum baseFormat; baseFormat = _mesa_base_format(format); mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type); assert(mformat); pipeFormat = st_mesa_format_to_pipe_format(mformat->MesaFormat); assert(pipeFormat); cpp = st_sizeof_format(pipeFormat); pixels = _mesa_map_drawpix_pbo(ctx, unpack, pixels); if (!pixels) return NULL; pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height, 1, PIPE_TEXTURE_USAGE_SAMPLER); if (!pt) { _mesa_unmap_drawpix_pbo(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 = st_no_flush_get_tex_transfer(st, pt, 0, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, width, height); /* map texture transfer */ dest = screen->transfer_map(screen, 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 = mformat->StoreImage(ctx, 2, /* dims */ baseFormat, /* baseInternalFormat */ mformat, /* gl_texture_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 */ screen->transfer_unmap(screen, transfer); screen->tex_transfer_destroy(transfer); assert(success); /* restore */ ctx->_ImageTransferState = imageTransferStateSave; } _mesa_unmap_drawpix_pbo(ctx, unpack); return pt; }