Пример #1
0
/**
 * 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;
}
Пример #2
0
static struct pipe_sampler_view *
st_get_texture_sampler_view_from_stobj(struct st_context *st,
                                       struct st_texture_object *stObj,
                                       enum pipe_format format,
                                       unsigned glsl_version)
{
    struct pipe_sampler_view **sv;
    const struct st_texture_image *firstImage;
    if (!stObj || !stObj->pt) {
        return NULL;
    }

    sv = st_texture_get_sampler_view(st, stObj);

    if (util_format_is_depth_and_stencil(format)) {
        if (stObj->base.StencilSampling)
            format = util_format_stencil_only(format);
        else {
            firstImage = st_texture_image_const(_mesa_base_tex_image(&stObj->base));
            if (firstImage->base._BaseFormat == GL_STENCIL_INDEX)
                format = util_format_stencil_only(format);
        }
    }

    /* if sampler view has changed dereference it */
    if (*sv) {
        if (check_sampler_swizzle(stObj, *sv, glsl_version) ||
                (format != (*sv)->format) ||
                gl_target_to_pipe(stObj->base.Target) != (*sv)->target ||
                stObj->base.MinLevel + stObj->base.BaseLevel != (*sv)->u.tex.first_level ||
                last_level(stObj) != (*sv)->u.tex.last_level ||
                stObj->base.MinLayer != (*sv)->u.tex.first_layer ||
                last_layer(stObj) != (*sv)->u.tex.last_layer) {
            pipe_sampler_view_reference(sv, NULL);
        }
    }

    if (!*sv) {
        *sv = st_create_texture_sampler_view_from_stobj(st->pipe, stObj,
                format, glsl_version);

    } else if ((*sv)->context != st->pipe) {
        /* Recreate view in correct context, use existing view as template */
        struct pipe_sampler_view *new_sv =
            st->pipe->create_sampler_view(st->pipe, stObj->pt, *sv);
        pipe_sampler_view_reference(sv, NULL);
        *sv = new_sv;
    }

    return *sv;
}
Пример #3
0
struct pipe_sampler_view *
st_get_texture_sampler_view_from_stobj(struct st_context *st,
                                       struct st_texture_object *stObj,
                                       const struct gl_sampler_object *samp,
                                       unsigned glsl_version)
{
   struct pipe_sampler_view **sv;

   if (!stObj || !stObj->pt) {
      return NULL;
   }

   sv = st_texture_get_sampler_view(st, stObj);

   if (*sv) {
      /* Debug check: make sure that the sampler view's parameters are
       * what they're supposed to be.
       */
      MAYBE_UNUSED struct pipe_sampler_view *view = *sv;
      assert(!check_sampler_swizzle(st, stObj, view, glsl_version));
      assert(get_sampler_view_format(st, stObj, samp) == view->format);
      assert(gl_target_to_pipe(stObj->base.Target) == view->target);
      if (stObj->base.Target == GL_TEXTURE_BUFFER) {
         unsigned base = stObj->base.BufferOffset;
         MAYBE_UNUSED unsigned size = MIN2(stObj->pt->width0 - base,
                              (unsigned) stObj->base.BufferSize);
         assert(view->u.buf.offset == base);
         assert(view->u.buf.size == size);
      }
      else {
         assert(stObj->base.MinLevel + stObj->base.BaseLevel ==
                view->u.tex.first_level);
         assert(last_level(stObj) == view->u.tex.last_level);
         assert(stObj->layer_override || stObj->base.MinLayer == view->u.tex.first_layer);
         assert(stObj->layer_override || last_layer(stObj) == view->u.tex.last_layer);
         assert(!stObj->layer_override ||
                (stObj->layer_override == view->u.tex.first_layer &&
                 stObj->layer_override == view->u.tex.last_layer));
      }
   }
   else {
      /* create new sampler view */
      enum pipe_format format = get_sampler_view_format(st, stObj, samp);

      *sv = st_create_texture_sampler_view_from_stobj(st, stObj,
                                                      format, glsl_version);

   }

   return *sv;
}
Пример #4
0
static GLboolean
st_TestProxyTexImage(struct gl_context *ctx, GLenum target,
                     GLint level, gl_format format,
                     GLint width, GLint height,
                     GLint depth, GLint border)
{
   struct st_context *st = st_context(ctx);
   struct pipe_context *pipe = st->pipe;

   if (width == 0 || height == 0 || depth == 0) {
      /* zero-sized images are legal, and always fit! */
      return GL_TRUE;
   }

   if (pipe->screen->can_create_resource) {
      /* Ask the gallium driver if the texture is too large */
      struct gl_texture_object *texObj =
         _mesa_get_current_tex_object(ctx, target);
      struct pipe_resource pt;

      /* Setup the pipe_resource object
       */
      memset(&pt, 0, sizeof(pt));

      pt.target = gl_target_to_pipe(target);
      pt.format = st_mesa_format_to_pipe_format(format);

      st_gl_texture_dims_to_pipe_dims(target,
                                      width, height, depth,
                                      &pt.width0, &pt.height0,
                                      &pt.depth0, &pt.array_size);

      if (level == 0 && (texObj->Sampler.MinFilter == GL_LINEAR ||
                         texObj->Sampler.MinFilter == GL_NEAREST)) {
         /* assume just one mipmap level */
         pt.last_level = 0;
      }
      else {
         /* assume a full set of mipmaps */
         pt.last_level = _mesa_logbase2(MAX3(width, height, depth));
      }

      return pipe->screen->can_create_resource(pipe->screen, &pt);
   }
   else {
      /* Use core Mesa fallback */
      return _mesa_test_proxy_teximage(ctx, target, level, format,
                                       width, height, depth, border);
   }
}
Пример #5
0
static struct pipe_sampler_view *
st_create_texture_sampler_view_from_stobj(struct pipe_context *pipe,
					  struct st_texture_object *stObj,
                                          const struct gl_sampler_object *samp,
					  enum pipe_format format)
{
   struct pipe_sampler_view templ;
   unsigned swizzle = get_texture_format_swizzle(stObj);

   u_sampler_view_default_template(&templ,
                                   stObj->pt,
                                   format);

   if (stObj->pt->target == PIPE_BUFFER) {
      unsigned base, size;
      unsigned f, n;
      const struct util_format_description *desc
         = util_format_description(templ.format);

      base = stObj->base.BufferOffset;
      if (base >= stObj->pt->width0)
         return NULL;
      size = MIN2(stObj->pt->width0 - base, (unsigned)stObj->base.BufferSize);

      f = ((base * 8) / desc->block.bits) * desc->block.width;
      n = ((size * 8) / desc->block.bits) * desc->block.width;
      if (!n)
         return NULL;
      templ.u.buf.first_element = f;
      templ.u.buf.last_element  = f + (n - 1);
   } else {
      templ.u.tex.first_level = stObj->base.MinLevel + stObj->base.BaseLevel;
      templ.u.tex.last_level = last_level(stObj);
      assert(templ.u.tex.first_level <= templ.u.tex.last_level);
      templ.u.tex.first_layer = stObj->base.MinLayer;
      templ.u.tex.last_layer = last_layer(stObj);
      assert(templ.u.tex.first_layer <= templ.u.tex.last_layer);
      templ.target = gl_target_to_pipe(stObj->base.Target);
   }

   if (swizzle != SWIZZLE_NOOP) {
      templ.swizzle_r = GET_SWZ(swizzle, 0);
      templ.swizzle_g = GET_SWZ(swizzle, 1);
      templ.swizzle_b = GET_SWZ(swizzle, 2);
      templ.swizzle_a = GET_SWZ(swizzle, 3);
   }

   return pipe->create_sampler_view(pipe, stObj->pt, &templ);
}
Пример #6
0
static struct pipe_sampler_view *
st_create_texture_sampler_view_from_stobj(struct st_context *st,
					  struct st_texture_object *stObj,
					  enum pipe_format format,
                                          unsigned glsl_version)
{
   struct pipe_sampler_view templ;
   unsigned swizzle = get_texture_format_swizzle(st, stObj, glsl_version);

   u_sampler_view_default_template(&templ, stObj->pt, format);

   if (stObj->pt->target == PIPE_BUFFER) {
      unsigned base, size;

      base = stObj->base.BufferOffset;
      if (base >= stObj->pt->width0)
         return NULL;
      size = MIN2(stObj->pt->width0 - base, (unsigned)stObj->base.BufferSize);
      if (!size)
         return NULL;

      templ.u.buf.offset = base;
      templ.u.buf.size = size;
   } else {
      templ.u.tex.first_level = stObj->base.MinLevel + stObj->base.BaseLevel;
      templ.u.tex.last_level = last_level(stObj);
      assert(templ.u.tex.first_level <= templ.u.tex.last_level);
      if (stObj->layer_override) {
         templ.u.tex.first_layer = templ.u.tex.last_layer = stObj->layer_override;
      } else {
         templ.u.tex.first_layer = stObj->base.MinLayer;
         templ.u.tex.last_layer = last_layer(stObj);
      }
      assert(templ.u.tex.first_layer <= templ.u.tex.last_layer);
      templ.target = gl_target_to_pipe(stObj->base.Target);
   }

   templ.swizzle_r = GET_SWZ(swizzle, 0);
   templ.swizzle_g = GET_SWZ(swizzle, 1);
   templ.swizzle_b = GET_SWZ(swizzle, 2);
   templ.swizzle_a = GET_SWZ(swizzle, 3);

   return st->pipe->create_sampler_view(st->pipe, stObj->pt, &templ);
}
Пример #7
0
/**
 * 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;
   }
}
Пример #8
0
/**
 * 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;
}
Пример #9
0
/**
 * 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;
}