/**************************************************************************
*
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
+#include <stdio.h>
+
#include "st_context.h"
#include "st_format.h"
-#include "st_public.h"
#include "st_texture.h"
#include "st_cb_fbo.h"
-#include "st_inlines.h"
#include "main/enums.h"
-#include "main/texfetch.h"
-#include "main/teximage.h"
-#include "main/texobj.h"
-
-#undef Elements /* fix re-defined macro warning */
#include "pipe/p_state.h"
#include "pipe/p_context.h"
#include "util/u_format.h"
#include "util/u_rect.h"
#include "util/u_math.h"
+#include "util/u_memory.h"
#define DBG if(0) printf
-#if 0
-static GLenum
-target_to_target(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
- return GL_TEXTURE_CUBE_MAP_ARB;
- default:
- return target;
- }
-}
-#endif
-
/**
- * Allocate a new pipe_texture object
+ * Allocate a new pipe_resource object
* width0, height0, depth0 are the dimensions of the level 0 image
* (the highest resolution). last_level indicates how many mipmap levels
* to allocate storage for. For non-mipmapped textures, this will be zero.
*/
-struct pipe_texture *
+struct pipe_resource *
st_texture_create(struct st_context *st,
enum pipe_texture_target target,
enum pipe_format format,
GLuint width0,
GLuint height0,
GLuint depth0,
- GLuint usage )
+ GLuint layers,
+ GLuint nr_samples,
+ GLuint bind )
{
- struct pipe_texture pt, *newtex;
+ struct pipe_resource pt, *newtex;
struct pipe_screen *screen = st->pipe->screen;
- assert(target <= PIPE_TEXTURE_CUBE);
+ assert(target < PIPE_MAX_TEXTURE_TYPES);
+ assert(width0 > 0);
+ assert(height0 > 0);
+ assert(depth0 > 0);
+ if (target == PIPE_TEXTURE_CUBE)
+ assert(layers == 6);
- DBG("%s target %s format %s last_level %d\n", __FUNCTION__,
- _mesa_lookup_enum_by_nr(target),
- _mesa_lookup_enum_by_nr(format), last_level);
+ DBG("%s target %d format %s last_level %d\n", __FUNCTION__,
+ (int) target, util_format_name(format), last_level);
assert(format);
- assert(screen->is_format_supported(screen, format, target,
- PIPE_TEXTURE_USAGE_SAMPLER, 0));
+ assert(screen->is_format_supported(screen, format, target, 0,
+ PIPE_BIND_SAMPLER_VIEW));
memset(&pt, 0, sizeof(pt));
pt.target = target;
pt.width0 = width0;
pt.height0 = height0;
pt.depth0 = depth0;
- pt.tex_usage = usage;
+ pt.array_size = (target == PIPE_TEXTURE_CUBE ? 6 : layers);
+ pt.usage = PIPE_USAGE_DEFAULT;
+ pt.bind = bind;
+ pt.flags = 0;
+ pt.nr_samples = nr_samples;
- newtex = screen->texture_create(screen, &pt);
+ newtex = screen->resource_create(screen, &pt);
assert(!newtex || pipe_is_referenced(&newtex->reference));
}
+/**
+ * In OpenGL the number of 1D array texture layers is the "height" and
+ * the number of 2D array texture layers is the "depth". In Gallium the
+ * number of layers in an array texture is a separate 'array_size' field.
+ * This function converts dimensions from the former to the later.
+ */
+void
+st_gl_texture_dims_to_pipe_dims(GLenum texture,
+ GLuint widthIn,
+ GLuint heightIn,
+ GLuint depthIn,
+ GLuint *widthOut,
+ GLuint *heightOut,
+ GLuint *depthOut,
+ GLuint *layersOut)
+{
+ switch (texture) {
+ case GL_TEXTURE_1D:
+ case GL_PROXY_TEXTURE_1D:
+ assert(heightIn == 1);
+ assert(depthIn == 1);
+ *widthOut = widthIn;
+ *heightOut = 1;
+ *depthOut = 1;
+ *layersOut = 1;
+ break;
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_PROXY_TEXTURE_1D_ARRAY:
+ assert(depthIn == 1);
+ *widthOut = widthIn;
+ *heightOut = 1;
+ *depthOut = 1;
+ *layersOut = heightIn;
+ break;
+ case GL_TEXTURE_2D:
+ case GL_PROXY_TEXTURE_2D:
+ case GL_TEXTURE_RECTANGLE:
+ case GL_PROXY_TEXTURE_RECTANGLE:
+ case GL_TEXTURE_EXTERNAL_OES:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ assert(depthIn == 1);
+ *widthOut = widthIn;
+ *heightOut = heightIn;
+ *depthOut = 1;
+ *layersOut = 1;
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ case GL_PROXY_TEXTURE_CUBE_MAP:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ assert(depthIn == 1);
+ *widthOut = widthIn;
+ *heightOut = heightIn;
+ *depthOut = 1;
+ *layersOut = 6;
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_2D_ARRAY:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ *widthOut = widthIn;
+ *heightOut = heightIn;
+ *depthOut = 1;
+ *layersOut = depthIn;
+ break;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ *widthOut = widthIn;
+ *heightOut = heightIn;
+ *depthOut = 1;
+ *layersOut = depthIn;
+ break;
+ default:
+ assert(0 && "Unexpected texture in st_gl_texture_dims_to_pipe_dims()");
+ /* fall-through */
+ case GL_TEXTURE_3D:
+ case GL_PROXY_TEXTURE_3D:
+ *widthOut = widthIn;
+ *heightOut = heightIn;
+ *depthOut = depthIn;
+ *layersOut = 1;
+ break;
+ }
+}
+
+
/**
* Check if a texture image can be pulled into a unified mipmap texture.
*/
GLboolean
-st_texture_match_image(const struct pipe_texture *pt,
- const struct gl_texture_image *image,
- GLuint face, GLuint level)
+st_texture_match_image(const struct pipe_resource *pt,
+ const struct gl_texture_image *image)
{
+ GLuint ptWidth, ptHeight, ptDepth, ptLayers;
+
/* Images with borders are never pulled into mipmap textures.
*/
if (image->Border)
if (st_mesa_format_to_pipe_format(image->TexFormat) != pt->format)
return GL_FALSE;
+ st_gl_texture_dims_to_pipe_dims(image->TexObject->Target,
+ image->Width, image->Height, image->Depth,
+ &ptWidth, &ptHeight, &ptDepth, &ptLayers);
+
/* Test if this image's size matches what's expected in the
* established texture.
*/
- if (image->Width != u_minify(pt->width0, level) ||
- image->Height != u_minify(pt->height0, level) ||
- image->Depth != u_minify(pt->depth0, level))
+ if (ptWidth != u_minify(pt->width0, image->Level) ||
+ ptHeight != u_minify(pt->height0, image->Level) ||
+ ptDepth != u_minify(pt->depth0, image->Level) ||
+ ptLayers != pt->array_size)
return GL_FALSE;
return GL_TRUE;
}
-#if 000
-/* Although we use the image_offset[] array to store relative offsets
- * to cube faces, Mesa doesn't know anything about this and expects
- * each cube face to be treated as a separate image.
- *
- * These functions present that view to mesa:
- */
-const GLuint *
-st_texture_depth_offsets(struct pipe_texture *pt, GLuint level)
-{
- static const GLuint zero = 0;
-
- if (pt->target != PIPE_TEXTURE_3D || pt->level[level].nr_images == 1)
- return &zero;
- else
- return pt->level[level].image_offset;
-}
-
-
/**
- * Return the offset to the given mipmap texture image within the
- * texture memory buffer, in bytes.
- */
-GLuint
-st_texture_image_offset(const struct pipe_texture * pt,
- GLuint face, GLuint level)
-{
- if (pt->target == PIPE_TEXTURE_CUBE)
- return (pt->level[level].level_offset +
- pt->level[level].image_offset[face] * pt->cpp);
- else
- return pt->level[level].level_offset;
-}
-#endif
-
-
-/**
- * Map a teximage in a mipmap texture.
- * \param row_stride returns row stride in bytes
- * \param image_stride returns image stride in bytes (for 3D textures).
- * \return address of mapping
+ * Map a texture image and return the address for a particular 2D face/slice/
+ * layer. The stImage indicates the cube face and mipmap level. The slice
+ * of the 3D texture is passed in 'zoffset'.
+ * \param usage one of the PIPE_TRANSFER_x values
+ * \param x, y, w, h the region of interest of the 2D image.
+ * \return address of mapping or NULL if any error
*/
GLubyte *
st_texture_image_map(struct st_context *st, struct st_texture_image *stImage,
- GLuint zoffset, enum pipe_transfer_usage usage,
- GLuint x, GLuint y, GLuint w, GLuint h)
+ enum pipe_transfer_usage usage,
+ GLuint x, GLuint y, GLuint z,
+ GLuint w, GLuint h, GLuint d)
{
- struct pipe_context *pipe = st->pipe;
- struct pipe_texture *pt = stImage->pt;
+ struct st_texture_object *stObj =
+ st_texture_object(stImage->base.TexObject);
+ GLuint level;
DBG("%s \n", __FUNCTION__);
- stImage->transfer = st_no_flush_get_tex_transfer(st, pt, stImage->face,
- stImage->level, zoffset,
- usage, x, y, w, h);
+ if (!stImage->pt)
+ return NULL;
- if (stImage->transfer)
- return pipe->transfer_map(pipe, stImage->transfer);
+ if (stObj->pt != stImage->pt)
+ level = 0;
else
- return NULL;
+ level = stImage->base.Level;
+
+ return pipe_transfer_map_3d(st->pipe, stImage->pt, level, usage,
+ x, y, z + stImage->base.Face,
+ w, h, d, &stImage->transfer);
}
DBG("%s\n", __FUNCTION__);
- pipe->transfer_unmap(pipe, stImage->transfer);
-
- pipe->tex_transfer_destroy(pipe, stImage->transfer);
-}
-
-
-
-/**
- * Upload data to a rectangular sub-region. Lots of choices how to do this:
- *
- * - memcpy by span to current destination
- * - upload data as new buffer and blit
- *
- * Currently always memcpy.
- */
-static void
-st_surface_data(struct pipe_context *pipe,
- struct pipe_transfer *dst,
- unsigned dstx, unsigned dsty,
- const void *src, unsigned src_stride,
- unsigned srcx, unsigned srcy, unsigned width, unsigned height)
-{
- void *map = pipe->transfer_map(pipe, dst);
-
- assert(dst->texture);
- util_copy_rect(map,
- dst->texture->format,
- dst->stride,
- dstx, dsty,
- width, height,
- src, src_stride,
- srcx, srcy);
-
- pipe->transfer_unmap(pipe, dst);
+ pipe_transfer_unmap(pipe, stImage->transfer);
+ stImage->transfer = NULL;
}
*/
void
st_texture_image_data(struct st_context *st,
- struct pipe_texture *dst,
+ struct pipe_resource *dst,
GLuint face,
GLuint level,
void *src,
GLuint src_row_stride, GLuint src_image_stride)
{
struct pipe_context *pipe = st->pipe;
- GLuint depth = u_minify(dst->depth0, level);
GLuint i;
const GLubyte *srcUB = src;
- struct pipe_transfer *dst_transfer;
+ GLuint layers;
- DBG("%s\n", __FUNCTION__);
+ if (dst->target == PIPE_TEXTURE_1D_ARRAY ||
+ dst->target == PIPE_TEXTURE_2D_ARRAY ||
+ dst->target == PIPE_TEXTURE_CUBE_ARRAY)
+ layers = dst->array_size;
+ else
+ layers = u_minify(dst->depth0, level);
- for (i = 0; i < depth; i++) {
- dst_transfer = st_no_flush_get_tex_transfer(st, dst, face, level, i,
- PIPE_TRANSFER_WRITE, 0, 0,
- u_minify(dst->width0, level),
- u_minify(dst->height0, level));
+ DBG("%s\n", __FUNCTION__);
- st_surface_data(pipe, dst_transfer,
- 0, 0, /* dstx, dsty */
- srcUB,
- src_row_stride,
- 0, 0, /* source x, y */
- u_minify(dst->width0, level),
- u_minify(dst->height0, level)); /* width, height */
+ for (i = 0; i < layers; i++) {
+ struct pipe_box box;
+ u_box_2d_zslice(0, 0, face + i,
+ u_minify(dst->width0, level),
+ u_minify(dst->height0, level),
+ &box);
- pipe->tex_transfer_destroy(pipe, dst_transfer);
+ pipe->transfer_inline_write(pipe, dst, level, PIPE_TRANSFER_WRITE,
+ &box, srcUB, src_row_stride, 0);
srcUB += src_image_stride;
}
}
-/* Copy mipmap image between textures
+/**
+ * For debug only: get/print center pixel in the src resource.
*/
-void
-st_texture_image_copy(struct pipe_context *pipe,
- struct pipe_texture *dst, GLuint dstLevel,
- struct pipe_texture *src,
- GLuint face)
+static void
+print_center_pixel(struct pipe_context *pipe, struct pipe_resource *src)
{
- struct pipe_screen *screen = pipe->screen;
- GLuint width = u_minify(dst->width0, dstLevel);
- GLuint height = u_minify(dst->height0, dstLevel);
- GLuint depth = u_minify(dst->depth0, dstLevel);
- struct pipe_surface *src_surface;
- struct pipe_surface *dst_surface;
- GLuint i;
-
- for (i = 0; i < depth; i++) {
- GLuint srcLevel;
-
- /* find src texture level of needed size */
- for (srcLevel = 0; srcLevel <= src->last_level; srcLevel++) {
- if (u_minify(src->width0, srcLevel) == width &&
- u_minify(src->height0, srcLevel) == height) {
- break;
- }
- }
- assert(u_minify(src->width0, srcLevel) == width);
- assert(u_minify(src->height0, srcLevel) == height);
-
-#if 0
- {
- src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
- PIPE_BUFFER_USAGE_CPU_READ);
- ubyte *map = screen->surface_map(screen, src_surface, PIPE_BUFFER_USAGE_CPU_READ);
- map += src_surface->width * src_surface->height * 4 / 2;
- printf("%s center pixel: %d %d %d %d (pt %p[%d] -> %p[%d])\n",
- __FUNCTION__,
- map[0], map[1], map[2], map[3],
- src, srcLevel, dst, dstLevel);
-
- screen->surface_unmap(screen, src_surface);
- pipe_surface_reference(&src_surface, NULL);
- }
-#endif
+ struct pipe_transfer *xfer;
+ struct pipe_box region;
+ ubyte *map;
- dst_surface = screen->get_tex_surface(screen, dst, face, dstLevel, i,
- PIPE_BUFFER_USAGE_GPU_WRITE);
+ region.x = src->width0 / 2;
+ region.y = src->height0 / 2;
+ region.z = 0;
+ region.width = 1;
+ region.height = 1;
+ region.depth = 1;
- src_surface = screen->get_tex_surface(screen, src, face, srcLevel, i,
- PIPE_BUFFER_USAGE_GPU_READ);
+ map = pipe->transfer_map(pipe, src, 0, PIPE_TRANSFER_READ, ®ion, &xfer);
- if (pipe->surface_copy) {
- pipe->surface_copy(pipe,
- dst_surface,
- 0, 0, /* destX, Y */
- src_surface,
- 0, 0, /* srcX, Y */
- width, height);
- } else {
- util_surface_copy(pipe, FALSE,
- dst_surface,
- 0, 0, /* destX, Y */
- src_surface,
- 0, 0, /* srcX, Y */
- width, height);
- }
+ printf("center pixel: %d %d %d %d\n", map[0], map[1], map[2], map[3]);
- pipe_surface_reference(&src_surface, NULL);
- pipe_surface_reference(&dst_surface, NULL);
- }
+ pipe->transfer_unmap(pipe, xfer);
}
/**
- * Bind a pipe surface to a texture object. After the call,
- * the texture object is marked dirty and will be (re-)validated.
- *
- * If this is the first surface bound, the texture object is said to
- * switch from normal to surface based. It will be cleared first in
- * this case.
- *
- * \param ps pipe surface to be unbound
- * \param target texture target
- * \param level image level
- * \param format internal format of the texture
+ * Copy the image at level=0 in 'src' to the 'dst' resource at 'dstLevel'.
+ * This is used to copy mipmap images from one texture buffer to another.
+ * This typically happens when our initial guess at the total texture size
+ * is incorrect (see the guess_and_alloc_texture() function).
*/
-int
-st_bind_texture_surface(struct pipe_surface *ps, int target, int level,
- enum pipe_format format)
+void
+st_texture_image_copy(struct pipe_context *pipe,
+ struct pipe_resource *dst, GLuint dstLevel,
+ struct pipe_resource *src, GLuint srcLevel,
+ GLuint face)
{
- GET_CURRENT_CONTEXT(ctx);
- const GLuint unit = ctx->Texture.CurrentUnit;
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- struct st_texture_object *stObj;
- struct st_texture_image *stImage;
- GLenum internalFormat;
-
- switch (target) {
- case ST_TEXTURE_2D:
- target = GL_TEXTURE_2D;
- break;
- case ST_TEXTURE_RECT:
- target = GL_TEXTURE_RECTANGLE_ARB;
- break;
- default:
- return 0;
- }
+ GLuint width = u_minify(dst->width0, dstLevel);
+ GLuint height = u_minify(dst->height0, dstLevel);
+ GLuint depth = u_minify(dst->depth0, dstLevel);
+ struct pipe_box src_box;
+ GLuint i;
- /* map pipe format to base format for now */
- if (util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0)
- internalFormat = GL_RGBA;
- else
- internalFormat = GL_RGB;
+ if (u_minify(src->width0, srcLevel) != width ||
+ u_minify(src->height0, srcLevel) != height ||
+ u_minify(src->depth0, srcLevel) != depth) {
+ /* The source image size doesn't match the destination image size.
+ * This can happen in some degenerate situations such as rendering to a
+ * cube map face which was set up with mismatched texture sizes.
+ */
+ return;
+ }
- texObj = _mesa_select_tex_object(ctx, texUnit, target);
- _mesa_lock_texture(ctx, texObj);
+ src_box.x = 0;
+ src_box.y = 0;
+ src_box.width = width;
+ src_box.height = height;
+ src_box.depth = 1;
+ /* Loop over 3D image slices */
+ /* could (and probably should) use "true" 3d box here -
+ but drivers can't quite handle it yet */
+ for (i = face; i < face + depth; i++) {
+ src_box.z = i;
+
+ if (0) {
+ print_center_pixel(pipe, src);
+ }
- stObj = st_texture_object(texObj);
- /* switch to surface based */
- if (!stObj->surface_based) {
- _mesa_clear_texture_object(ctx, texObj);
- stObj->surface_based = GL_TRUE;
+ pipe->resource_copy_region(pipe,
+ dst,
+ dstLevel,
+ 0, 0, i,/* destX, Y, Z */
+ src,
+ srcLevel,
+ &src_box);
}
+}
- texImage = _mesa_get_tex_image(ctx, texObj, target, level);
- stImage = st_texture_image(texImage);
-
- _mesa_init_teximage_fields(ctx, target, texImage,
- ps->width, ps->height, 1, 0, internalFormat);
- texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat,
- GL_RGBA, GL_UNSIGNED_BYTE);
- _mesa_set_fetch_functions(texImage, 2);
- pipe_texture_reference(&stImage->pt, ps->texture);
- _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
- _mesa_unlock_texture(ctx, texObj);
-
- return 1;
+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;
}
-
/**
- * Unbind a pipe surface from a texture object. After the call,
- * the texture object is marked dirty and will be (re-)validated.
- *
- * \param ps pipe surface to be unbound
- * \param target texture target
- * \param level image level
+ * Try to find a matching sampler view for the given context.
+ * If none is found an empty slot is initialized with a
+ * template and returned instead.
*/
-int
-st_unbind_texture_surface(struct pipe_surface *ps, int target, int level)
+struct pipe_sampler_view **
+st_texture_get_sampler_view(struct st_context *st,
+ struct st_texture_object *stObj)
{
- GET_CURRENT_CONTEXT(ctx);
- const GLuint unit = ctx->Texture.CurrentUnit;
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- struct st_texture_object *stObj;
- struct st_texture_image *stImage;
-
- switch (target) {
- case ST_TEXTURE_2D:
- target = GL_TEXTURE_2D;
- break;
- case ST_TEXTURE_RECT:
- target = GL_TEXTURE_RECTANGLE_ARB;
- break;
- default:
- return 0;
- }
-
- texObj = _mesa_select_tex_object(ctx, texUnit, target);
-
- _mesa_lock_texture(ctx, texObj);
-
- texImage = _mesa_get_tex_image(ctx, texObj, target, level);
- stObj = st_texture_object(texObj);
- stImage = st_texture_image(texImage);
+ struct pipe_sampler_view **used = NULL, **free = NULL;
+ GLuint i;
- /* Make sure the pipe surface is still bound. The texture object is still
- * considered surface based even if this is the last bound surface. */
- if (stImage->pt == ps->texture) {
- pipe_texture_reference(&stImage->pt, NULL);
- _mesa_clear_texture_image(ctx, texImage);
+ for (i = 0; i < stObj->num_sampler_views; ++i) {
+ struct pipe_sampler_view **sv = &stObj->sampler_views[i];
+ /* Is the array entry used ? */
+ if (*sv) {
+ /* Yes, check if it's the right one */
+ if ((*sv)->context == st->pipe)
+ return sv;
- _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
+ /* Wasn't the right one, but remember it as template */
+ used = sv;
+ } else {
+ /* Found a free slot, remember that */
+ free = sv;
+ }
}
- _mesa_unlock_texture(ctx, texObj);
-
- return 1;
-}
-
+ /* Couldn't find a slot for our context, create a new one */
-/** Redirect rendering into stfb's surface to a texture image */
-int
-st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex,
- int target, int format, int level)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct st_context *st = ctx->st;
- struct pipe_context *pipe = st->pipe;
- struct pipe_screen *screen = pipe->screen;
- const GLuint unit = ctx->Texture.CurrentUnit;
- struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImage;
- struct st_texture_image *stImage;
- struct st_renderbuffer *strb;
- GLint face = 0, slice = 0;
-
- assert(surfIndex <= ST_SURFACE_DEPTH);
-
- strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
-
- if (strb->texture_save || strb->surface_save) {
- /* Error! */
- return 0;
+ if (!free) {
+ /* Haven't even found a free one, resize the array */
+ GLuint old_size = stObj->num_sampler_views * sizeof(void *);
+ GLuint new_size = old_size + sizeof(void *);
+ stObj->sampler_views = REALLOC(stObj->sampler_views, old_size, new_size);
+ free = &stObj->sampler_views[stObj->num_sampler_views++];
+ *free = NULL;
}
- if (target == ST_TEXTURE_2D) {
- texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX];
- texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level);
- stImage = st_texture_image(texImage);
- }
- else {
- /* unsupported target */
- return 0;
- }
-
- st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
-
- /* save the renderbuffer's surface/texture info */
- pipe_texture_reference(&strb->texture_save, strb->texture);
- pipe_surface_reference(&strb->surface_save, strb->surface);
-
- /* plug in new surface/texture info */
- pipe_texture_reference(&strb->texture, stImage->pt);
- strb->surface = screen->get_tex_surface(screen, strb->texture,
- face, level, slice,
- (PIPE_BUFFER_USAGE_GPU_READ |
- PIPE_BUFFER_USAGE_GPU_WRITE));
+ /* Add just any sampler view to be used as a template */
+ if (used)
+ pipe_sampler_view_reference(free, *used);
- st->dirty.st |= ST_NEW_FRAMEBUFFER;
-
- return 1;
+ return free;
}
-
-/** Undo surface-to-texture binding */
-int
-st_release_teximage(struct st_framebuffer *stfb, uint surfIndex,
- int target, int format, int level)
+void
+st_texture_release_sampler_view(struct st_context *st,
+ struct st_texture_object *stObj)
{
- GET_CURRENT_CONTEXT(ctx);
- struct st_context *st = ctx->st;
- struct st_renderbuffer *strb;
-
- assert(surfIndex <= ST_SURFACE_DEPTH);
+ GLuint i;
- strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer);
+ for (i = 0; i < stObj->num_sampler_views; ++i) {
+ struct pipe_sampler_view **sv = &stObj->sampler_views[i];
- if (!strb->texture_save || !strb->surface_save) {
- /* Error! */
- return 0;
+ if (*sv && (*sv)->context == st->pipe) {
+ pipe_sampler_view_reference(sv, NULL);
+ break;
+ }
}
+}
- st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
-
- /* free tex surface, restore original */
- pipe_surface_reference(&strb->surface, strb->surface_save);
- pipe_texture_reference(&strb->texture, strb->texture_save);
-
- pipe_surface_reference(&strb->surface_save, NULL);
- pipe_texture_reference(&strb->texture_save, NULL);
-
- st->dirty.st |= ST_NEW_FRAMEBUFFER;
+void
+st_texture_release_all_sampler_views(struct st_texture_object *stObj)
+{
+ GLuint i;
- return 1;
+ for (i = 0; i < stObj->num_sampler_views; ++i)
+ pipe_sampler_view_reference(&stObj->sampler_views[i], NULL);
}
+
void
-st_teximage_flush_before_map(struct st_context *st,
- struct pipe_texture *pt,
- unsigned int face,
- unsigned int level,
- enum pipe_transfer_usage usage)
+st_texture_free_sampler_views(struct st_texture_object *stObj)
{
- struct pipe_context *pipe = st->pipe;
- unsigned referenced =
- pipe->is_texture_referenced(pipe, pt, face, level);
-
- if (referenced && ((referenced & PIPE_REFERENCED_FOR_WRITE) ||
- (usage & PIPE_TRANSFER_WRITE)))
- st->pipe->flush(st->pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
+ /* NOTE:
+ * We use FREE() here to match REALLOC() above. Both come from
+ * u_memory.h, not imports.h. If we mis-match MALLOC/FREE from
+ * those two headers we can trash the heap.
+ */
+ FREE(stObj->sampler_views);
}