Beispiel #1
0
/**
 * 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)
{
   /* Images with borders are never pulled into mipmap textures. 
    */
   if (image->Border) 
      return GL_FALSE;

   /* Check if this image's format matches the established texture's format.
    */
   if (st_mesa_format_to_pipe_format(image->TexFormat) != pt->format)
      return GL_FALSE;

   /* Test if this image's size matches what's expected in the
    * established texture.
    */
   if (image->Width != pt->width[level] ||
       image->Height != pt->height[level] ||
       image->Depth != pt->depth[level])
      return GL_FALSE;

   return GL_TRUE;
}
Beispiel #2
0
/**
 * Check if a texture image can be pulled into a unified mipmap texture.
 */
GLboolean
st_texture_match_image(struct st_context *st,
                       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) 
      return GL_FALSE;

   /* Check if this image's format matches the established texture's format.
    */
   if (st_mesa_format_to_pipe_format(st, 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 (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;
}
Beispiel #3
0
static GLboolean
update_single_texture(struct st_context *st,
                      struct pipe_sampler_view **sampler_view,
                      GLuint texUnit)
{
    struct pipe_context *pipe = st->pipe;
    struct gl_context *ctx = st->ctx;
    const struct gl_sampler_object *samp;
    struct gl_texture_object *texObj;
    struct st_texture_object *stObj;
    enum pipe_format view_format;
    GLboolean retval;

    samp = _mesa_get_samplerobj(ctx, texUnit);

    texObj = ctx->Texture.Unit[texUnit]._Current;

    if (!texObj) {
        texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX);
        samp = &texObj->Sampler;
    }
    stObj = st_texture_object(texObj);

    retval = st_finalize_texture(ctx, st->pipe, texObj);
    if (!retval) {
        /* out of mem */
        return GL_FALSE;
    }

    /* Determine the format of the texture sampler view */
    if (texObj->Target == GL_TEXTURE_BUFFER) {
        view_format =
            st_mesa_format_to_pipe_format(stObj->base._BufferObjectFormat);
    }
    else {
        view_format = stObj->pt->format;

        /* If sRGB decoding is off, use the linear format */
        if (samp->sRGBDecode == GL_SKIP_DECODE_EXT) {
            view_format = util_format_linear(view_format);
        }
    }

    /* if sampler view has changed dereference it */
    if (stObj->sampler_view) {
        if (check_sampler_swizzle(stObj->sampler_view,
                                  stObj->base._Swizzle,
                                  stObj->base.DepthMode) ||
                (view_format != stObj->sampler_view->format) ||
                stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) {
            pipe_sampler_view_reference(&stObj->sampler_view, NULL);
        }
    }

    *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe,
                    samp,
                    view_format);
    return GL_TRUE;
}
Beispiel #4
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;
}
Beispiel #5
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);
   }
}
Beispiel #6
0
static GLboolean
update_single_texture(struct st_context *st,
                      struct pipe_sampler_view **sampler_view,
                      GLuint texUnit, unsigned glsl_version)
{
    struct gl_context *ctx = st->ctx;
    const struct gl_sampler_object *samp;
    struct gl_texture_object *texObj;
    struct st_texture_object *stObj;
    enum pipe_format view_format;
    GLboolean retval;

    samp = _mesa_get_samplerobj(ctx, texUnit);

    texObj = ctx->Texture.Unit[texUnit]._Current;

    if (!texObj) {
        texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX);
        samp = &texObj->Sampler;
    }
    stObj = st_texture_object(texObj);

    retval = st_finalize_texture(ctx, st->pipe, texObj);
    if (!retval) {
        /* out of mem */
        return GL_FALSE;
    }

    /* Determine the format of the texture sampler view */
    if (texObj->Target == GL_TEXTURE_BUFFER) {
        view_format =
            st_mesa_format_to_pipe_format(st, stObj->base._BufferObjectFormat);
    }
    else {
        view_format =
            stObj->surface_based ? stObj->surface_format : stObj->pt->format;

        /* If sRGB decoding is off, use the linear format */
        if (samp->sRGBDecode == GL_SKIP_DECODE_EXT) {
            view_format = util_format_linear(view_format);
        }
    }

    *sampler_view =
        st_get_texture_sampler_view_from_stobj(st, stObj, view_format,
                glsl_version);
    return GL_TRUE;
}
Beispiel #7
0
/**
 * Validate a renderbuffer attachment for a particular set of bindings.
 */
static GLboolean
st_validate_attachment(struct gl_context *ctx,
		       struct pipe_screen *screen,
		       const struct gl_renderbuffer_attachment *att,
		       unsigned bindings)
{
   const struct st_texture_object *stObj = st_texture_object(att->Texture);
   enum pipe_format format;
   mesa_format texFormat;
   GLboolean valid;

   /* Sanity check: we must be binding the surface as a (color) render target
    * or depth/stencil target.
    */
   assert(bindings == PIPE_BIND_RENDER_TARGET ||
          bindings == PIPE_BIND_DEPTH_STENCIL);

   /* Only validate texture attachments for now, since
    * st_renderbuffer_alloc_storage makes sure that
    * the format is supported.
    */
   if (att->Type != GL_TEXTURE)
      return GL_TRUE;

   if (!stObj || !stObj->pt)
      return GL_FALSE;

   format = stObj->pt->format;
   texFormat = att->Renderbuffer->TexImage->TexFormat;

   /* If the encoding is sRGB and sRGB rendering cannot be enabled,
    * check for linear format support instead.
    * Later when we create a surface, we change the format to a linear one. */
   if (!ctx->Extensions.EXT_framebuffer_sRGB &&
       _mesa_get_format_color_encoding(texFormat) == GL_SRGB) {
      const mesa_format linearFormat = _mesa_get_srgb_format_linear(texFormat);
      format = st_mesa_format_to_pipe_format(st_context(ctx), linearFormat);
   }

   valid = screen->is_format_supported(screen, format,
                                      PIPE_TEXTURE_2D,
                                      stObj->pt->nr_samples, bindings);
   if (!valid) {
      st_fbo_invalid("Invalid format");
   }

   return valid;
}
Beispiel #8
0
/**
 * Determine the format for the texture sampler view.
 */
static enum pipe_format
get_sampler_view_format(struct st_context *st,
                        const struct st_texture_object *stObj,
                        const struct gl_sampler_object *samp)
{
   enum pipe_format format;

   if (stObj->base.Target == GL_TEXTURE_BUFFER) {
      format =
         st_mesa_format_to_pipe_format(st, stObj->base._BufferObjectFormat);
   }
   else {
      format =
         stObj->surface_based ? stObj->surface_format : stObj->pt->format;

      if (util_format_is_depth_and_stencil(format)) {
         if (stObj->base.StencilSampling) {
            format = util_format_stencil_only(format);
         }
         else {
            GLenum baseFormat = _mesa_texture_base_format(&stObj->base);
            if (baseFormat == GL_STENCIL_INDEX) {
               format = util_format_stencil_only(format);
            }
         }
      }
      else {
         /* If sRGB decoding is off, use the linear format */
         if (samp->sRGBDecode == GL_SKIP_DECODE_EXT) {
            format = util_format_linear(format);
         }

         /* Use R8_UNORM for video formats */
         switch (format) {
         case PIPE_FORMAT_NV12:
         case PIPE_FORMAT_IYUV:
            format = PIPE_FORMAT_R8_UNORM;
            break;
         default:
            break;
         }
      }
   }

   return format;
}
/**
 * Validate a renderbuffer attachment for a particular set of bindings.
 */
static GLboolean
st_validate_attachment(struct gl_context *ctx,
		       struct pipe_screen *screen,
		       const struct gl_renderbuffer_attachment *att,
		       unsigned bindings)
{
   const struct st_texture_object *stObj = st_texture_object(att->Texture);
   enum pipe_format format;
   gl_format texFormat;
   GLboolean valid;

   /* Only validate texture attachments for now, since
    * st_renderbuffer_alloc_storage makes sure that
    * the format is supported.
    */
   if (att->Type != GL_TEXTURE)
      return GL_TRUE;

   if (!stObj)
      return GL_FALSE;

   format = stObj->pt->format;
   texFormat = _mesa_get_attachment_teximage_const(att)->TexFormat;

   /* If the encoding is sRGB and sRGB rendering cannot be enabled,
    * check for linear format support instead.
    * Later when we create a surface, we change the format to a linear one. */
   if (!ctx->Extensions.EXT_framebuffer_sRGB &&
       _mesa_get_format_color_encoding(texFormat) == GL_SRGB) {
      const gl_format linearFormat = _mesa_get_srgb_format_linear(texFormat);
      format = st_mesa_format_to_pipe_format(linearFormat);
   }

   valid = screen->is_format_supported(screen, format,
                                      PIPE_TEXTURE_2D,
                                      stObj->pt->nr_samples, bindings);
   if (!valid) {
      st_fbo_invalid("Invalid format");
   }

   return valid;
}
Beispiel #10
0
static GLboolean
update_single_texture(struct st_context *st,
                      struct pipe_sampler_view **sampler_view,
		      GLuint texUnit)
{
   struct pipe_context *pipe = st->pipe;
   struct gl_context *ctx = st->ctx;
   const struct gl_sampler_object *samp;
   struct gl_texture_object *texObj;
   struct st_texture_object *stObj;
   enum pipe_format st_view_format;
   GLboolean retval;

   samp = _mesa_get_samplerobj(ctx, texUnit);

   texObj = ctx->Texture.Unit[texUnit]._Current;

   if (!texObj) {
      texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX);
      samp = &texObj->Sampler;
   }
   stObj = st_texture_object(texObj);

   retval = st_finalize_texture(ctx, st->pipe, texObj);
   if (!retval) {
      /* out of mem */
      return GL_FALSE;
   }

   /* Determine the format of the texture sampler view */
   st_view_format = stObj->pt->format;
   {
      const struct st_texture_image *firstImage =
	 st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
      const gl_format texFormat = firstImage->base.TexFormat;
      enum pipe_format firstImageFormat =
	 st_mesa_format_to_pipe_format(texFormat);

      if ((samp->sRGBDecode == GL_SKIP_DECODE_EXT) &&
	  (_mesa_get_format_color_encoding(texFormat) == GL_SRGB)) {
         /* Don't do sRGB->RGB conversion.  Interpret the texture data as
          * linear values.
          */
	 const gl_format linearFormat =
	    _mesa_get_srgb_format_linear(texFormat);
	 firstImageFormat = st_mesa_format_to_pipe_format(linearFormat);
      }

      if (firstImageFormat != stObj->pt->format)
	 st_view_format = firstImageFormat;
   }

   /* if sampler view has changed dereference it */
   if (stObj->sampler_view) {
      if (check_sampler_swizzle(stObj->sampler_view,
				stObj->base._Swizzle,
				samp->DepthMode) ||
	  (st_view_format != stObj->sampler_view->format) ||
	  stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) {
	 pipe_sampler_view_reference(&stObj->sampler_view, NULL);
      }
   }

   *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe,
							  samp,
							  st_view_format);
   return GL_TRUE;
}
Beispiel #11
0
/**
 * Convert a gl_image_unit object to a pipe_image_view object.
 */
void
st_convert_image(const struct st_context *st, const struct gl_image_unit *u,
                 struct pipe_image_view *img)
{
   struct st_texture_object *stObj = st_texture_object(u->TexObj);

   img->format = st_mesa_format_to_pipe_format(st, u->_ActualFormat);

   switch (u->Access) {
   case GL_READ_ONLY:
      img->access = PIPE_IMAGE_ACCESS_READ;
      break;
   case GL_WRITE_ONLY:
      img->access = PIPE_IMAGE_ACCESS_WRITE;
      break;
   case GL_READ_WRITE:
      img->access = PIPE_IMAGE_ACCESS_READ_WRITE;
      break;
   default:
      unreachable("bad gl_image_unit::Access");
   }

   if (stObj->base.Target == GL_TEXTURE_BUFFER) {
      struct st_buffer_object *stbuf =
         st_buffer_object(stObj->base.BufferObject);
      unsigned base, size;

      if (!stbuf || !stbuf->buffer) {
         memset(img, 0, sizeof(*img));
         return;
      }
      struct pipe_resource *buf = stbuf->buffer;

      base = stObj->base.BufferOffset;
      assert(base < buf->width0);
      size = MIN2(buf->width0 - base, (unsigned)stObj->base.BufferSize);

      img->resource = stbuf->buffer;
      img->u.buf.offset = base;
      img->u.buf.size = size;
   } else {
      if (!st_finalize_texture(st->ctx, st->pipe, u->TexObj, 0) ||
          !stObj->pt) {
         memset(img, 0, sizeof(*img));
         return;
      }

      img->resource = stObj->pt;
      img->u.tex.level = u->Level + stObj->base.MinLevel;
      if (stObj->pt->target == PIPE_TEXTURE_3D) {
         if (u->Layered) {
            img->u.tex.first_layer = 0;
            img->u.tex.last_layer = u_minify(stObj->pt->depth0, img->u.tex.level) - 1;
         } else {
            img->u.tex.first_layer = u->_Layer;
            img->u.tex.last_layer = u->_Layer;
         }
      } else {
         img->u.tex.first_layer = u->_Layer + stObj->base.MinLayer;
         img->u.tex.last_layer = u->_Layer + stObj->base.MinLayer;
         if (u->Layered && img->resource->array_size > 1) {
            if (stObj->base.Immutable)
               img->u.tex.last_layer += stObj->base.NumLayers - 1;
            else
               img->u.tex.last_layer += img->resource->array_size - 1;
         }
      }
   }
}
Beispiel #12
0
static void
st_bind_images(struct st_context *st, struct gl_shader *shader,
              unsigned shader_type)
{
   unsigned i;
   struct pipe_image_view images[MAX_IMAGE_UNIFORMS];
   struct gl_program_constants *c;

   if (!shader || !st->pipe->set_shader_images)
      return;

   c = &st->ctx->Const.Program[shader->Stage];

   for (i = 0; i < shader->NumImages; i++) {
      struct gl_image_unit *u = &st->ctx->ImageUnits[shader->ImageUnits[i]];
      struct st_texture_object *stObj = st_texture_object(u->TexObj);
      struct pipe_image_view *img = &images[i];

      if (!_mesa_is_image_unit_valid(st->ctx, u) ||
          !st_finalize_texture(st->ctx, st->pipe, u->TexObj) ||
          !stObj->pt) {
         memset(img, 0, sizeof(*img));
         continue;
      }

      img->resource = stObj->pt;
      img->format = st_mesa_format_to_pipe_format(st, u->_ActualFormat);

      switch (u->Access) {
      case GL_READ_ONLY:
         img->access = PIPE_IMAGE_ACCESS_READ;
         break;
      case GL_WRITE_ONLY:
         img->access = PIPE_IMAGE_ACCESS_WRITE;
         break;
      case GL_READ_WRITE:
         img->access = PIPE_IMAGE_ACCESS_READ_WRITE;
         break;
      default:
         unreachable("bad gl_image_unit::Access");
      }

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

         base = stObj->base.BufferOffset;
         assert(base < stObj->pt->width0);
         size = MIN2(stObj->pt->width0 - base, (unsigned)stObj->base.BufferSize);

         f = (base / (desc->block.bits / 8)) * desc->block.width;
         n = (size / (desc->block.bits / 8)) * desc->block.width;
         assert(n > 0);
         img->u.buf.first_element = f;
         img->u.buf.last_element  = f + (n - 1);
      } else {
         img->u.tex.level = u->Level + stObj->base.MinLevel;
         if (stObj->pt->target == PIPE_TEXTURE_3D) {
            if (u->Layered) {
               img->u.tex.first_layer = 0;
               img->u.tex.last_layer = u_minify(stObj->pt->depth0, img->u.tex.level) - 1;
            } else {
               img->u.tex.first_layer = u->_Layer;
               img->u.tex.last_layer = u->_Layer;
            }
         } else {
            img->u.tex.first_layer = u->_Layer + stObj->base.MinLayer;
            img->u.tex.last_layer = u->_Layer + stObj->base.MinLayer;
            if (u->Layered && img->resource->array_size > 1) {
               if (stObj->base.Immutable)
                  img->u.tex.last_layer += stObj->base.NumLayers - 1;
               else
                  img->u.tex.last_layer += img->resource->array_size - 1;
            }
         }
      }
   }
   cso_set_shader_images(st->cso_context, shader_type, 0, shader->NumImages,
                         images);
   /* clear out any stale shader images */
   if (shader->NumImages < c->MaxImageUniforms)
      cso_set_shader_images(
            st->cso_context, shader_type,
            shader->NumImages,
            c->MaxImageUniforms - shader->NumImages,
            NULL);
}
Beispiel #13
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;
   }
}
Beispiel #14
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;
}
Beispiel #15
0
/**
 * 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;
}
Beispiel #16
0
/**
 * 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;
}
Beispiel #17
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;
}