Esempio n. 1
0
/**
 * Called by ctx->Driver.RenderTexture
 */
static void
st_render_texture(struct gl_context *ctx,
                  struct gl_framebuffer *fb,
                  struct gl_renderbuffer_attachment *att)
{
   struct st_context *st = st_context(ctx);
   struct pipe_context *pipe = st->pipe;
   struct gl_renderbuffer *rb = att->Renderbuffer;
   struct st_renderbuffer *strb = st_renderbuffer(rb);
   struct pipe_resource *pt;

   if (!st_finalize_texture(ctx, pipe, att->Texture))
      return;

   pt = st_get_texobj_resource(att->Texture);
   assert(pt);

   /* point renderbuffer at texobject */
   strb->is_rtt = TRUE;
   strb->rtt_face = att->CubeMapFace;
   strb->rtt_slice = att->Zoffset;
   strb->rtt_layered = att->Layered;
   pipe_resource_reference(&strb->texture, pt);

   pipe_surface_release(pipe, &strb->surface);

   st_update_renderbuffer_surface(st, strb);

   strb->Base.Format = st_pipe_format_to_mesa_format(pt->format);

   /* Invalidate buffer state so that the pipe's framebuffer state
    * gets updated.
    * That's where the new renderbuffer (which we just created) gets
    * passed to the pipe as a (color/depth) render target.
    */
   st_invalidate_state(ctx, _NEW_BUFFERS);


   /* Need to trigger a call to update_framebuffer() since we just
    * attached a new renderbuffer.
    */
   ctx->NewState |= _NEW_BUFFERS;
}
Esempio n. 2
0
/**
 * 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);
   }
}
Esempio n. 3
0
static __DRIimage *
dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture,
                         int depth, int level, unsigned *error,
                         void *loaderPrivate)
{
   __DRIimage *img;
   struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx;
   struct gl_texture_object *obj;
   struct pipe_resource *tex;
   GLuint face = 0;

   obj = _mesa_lookup_texture(ctx, texture);
   if (!obj || obj->Target != target) {
      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
      return NULL;
   }

   tex = st_get_texobj_resource(obj);
   if (!tex) {
      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
      return NULL;
   }

   if (target == GL_TEXTURE_CUBE_MAP)
      face = depth;

   _mesa_test_texobj_completeness(ctx, obj);
   if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) {
      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
      return NULL;
   }

   if (level < obj->BaseLevel || level > obj->_MaxLevel) {
      *error = __DRI_IMAGE_ERROR_BAD_MATCH;
      return NULL;
   }

   if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) {
      *error = __DRI_IMAGE_ERROR_BAD_MATCH;
      return NULL;
   }

   img = CALLOC_STRUCT(__DRIimageRec);
   if (!img) {
      *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
      return NULL;
   }

   img->level = level;
   img->layer = depth;
   img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat);

   img->loader_private = loaderPrivate;

   if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) {
      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
      free(img);
      return NULL;
   }

   pipe_resource_reference(&img->texture, tex);

   *error = __DRI_IMAGE_ERROR_SUCCESS;
   return img;
}
/**
 * Called by ctx->Driver.RenderTexture
 */
static void
st_render_texture(struct gl_context *ctx,
                  struct gl_framebuffer *fb,
                  struct gl_renderbuffer_attachment *att)
{
   struct st_context *st = st_context(ctx);
   struct pipe_context *pipe = st->pipe;
   struct st_renderbuffer *strb;
   struct gl_renderbuffer *rb;
   struct pipe_resource *pt;
   struct st_texture_object *stObj;
   const struct gl_texture_image *texImage;
   struct pipe_surface surf_tmpl;

   if (!st_finalize_texture(ctx, pipe, att->Texture))
      return;

   pt = st_get_texobj_resource(att->Texture);
   assert(pt);

   /* get pointer to texture image we're rendeing to */
   texImage = _mesa_get_attachment_teximage(att);

   /* create new renderbuffer which wraps the texture image.
    * Use the texture's name as the renderbuffer's name so that we have
    * something that's non-zero (to determine vertical orientation) and
    * possibly helpful for debugging.
    */
   rb = st_new_renderbuffer(ctx, att->Texture->Name);
   if (!rb) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
      return;
   }

   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
   assert(rb->RefCount == 1);
   rb->AllocStorage = NULL; /* should not get called */
   strb = st_renderbuffer(rb);

   assert(strb->Base.RefCount > 0);

   /* get the texture for the texture object */
   stObj = st_texture_object(att->Texture);

   /* point renderbuffer at texobject */
   strb->rtt = stObj;
   strb->rtt_level = att->TextureLevel;
   strb->rtt_face = att->CubeMapFace;
   strb->rtt_slice = att->Zoffset;

   rb->Width = texImage->Width2;
   rb->Height = texImage->Height2;
   rb->_BaseFormat = texImage->_BaseFormat;
   rb->InternalFormat = texImage->InternalFormat;

   pipe_resource_reference( &strb->texture, pt );

   pipe_surface_release(pipe, &strb->surface);

   assert(strb->rtt_level <= strb->texture->last_level);

   /* new surface for rendering into the texture */
   memset(&surf_tmpl, 0, sizeof(surf_tmpl));
   surf_tmpl.format = ctx->Color.sRGBEnabled
      ? strb->texture->format : util_format_linear(strb->texture->format);
   surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
   surf_tmpl.u.tex.level = strb->rtt_level;
   surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
   surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
   strb->surface = pipe->create_surface(pipe,
                                        strb->texture,
                                        &surf_tmpl);

   strb->Base.Format = st_pipe_format_to_mesa_format(pt->format);

   /* Invalidate buffer state so that the pipe's framebuffer state
    * gets updated.
    * That's where the new renderbuffer (which we just created) gets
    * passed to the pipe as a (color/depth) render target.
    */
   st_invalidate_state(ctx, _NEW_BUFFERS);


   /* Need to trigger a call to update_framebuffer() since we just
    * attached a new renderbuffer.
    */
   ctx->NewState |= _NEW_BUFFERS;
}
Esempio n. 5
0
/**
 * Called by ctx->Driver.RenderTexture
 */
static void
st_render_texture(struct gl_context *ctx,
                  struct gl_framebuffer *fb,
                  struct gl_renderbuffer_attachment *att)
{
   struct st_context *st = st_context(ctx);
   struct pipe_context *pipe = st->pipe;
   struct gl_renderbuffer *rb = att->Renderbuffer;
   struct st_renderbuffer *strb = st_renderbuffer(rb);
   struct pipe_resource *pt;
   struct st_texture_object *stObj;
   const struct gl_texture_image *texImage;
   struct pipe_surface surf_tmpl;

   if (!st_finalize_texture(ctx, pipe, att->Texture))
      return;

   pt = st_get_texobj_resource(att->Texture);
   assert(pt);

   /* get pointer to texture image we're rendeing to */
   texImage = _mesa_get_attachment_teximage(att);

   /* get the texture for the texture object */
   stObj = st_texture_object(att->Texture);

   /* point renderbuffer at texobject */
   strb->rtt = stObj;
   strb->rtt_level = att->TextureLevel;
   strb->rtt_face = att->CubeMapFace;
   strb->rtt_slice = att->Zoffset;

   pipe_resource_reference( &strb->texture, pt );

   pipe_surface_release(pipe, &strb->surface);

   assert(strb->rtt_level <= strb->texture->last_level);

   /* new surface for rendering into the texture */
   memset(&surf_tmpl, 0, sizeof(surf_tmpl));
   surf_tmpl.format = ctx->Color.sRGBEnabled
      ? strb->texture->format : util_format_linear(strb->texture->format);
   surf_tmpl.u.tex.level = strb->rtt_level;
   surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
   surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
   strb->surface = pipe->create_surface(pipe,
                                        strb->texture,
                                        &surf_tmpl);

   strb->Base.Format = st_pipe_format_to_mesa_format(pt->format);

   /* Invalidate buffer state so that the pipe's framebuffer state
    * gets updated.
    * That's where the new renderbuffer (which we just created) gets
    * passed to the pipe as a (color/depth) render target.
    */
   st_invalidate_state(ctx, _NEW_BUFFERS);


   /* Need to trigger a call to update_framebuffer() since we just
    * attached a new renderbuffer.
    */
   ctx->NewState |= _NEW_BUFFERS;
}
Esempio n. 6
0
/**
 * 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;
   enum pipe_format format;
   uint lastLevel, first_layer, last_layer;

   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;

   st_flush_bitmap_cache(st);
   st_invalidate_readpix_cache(st);

   /* 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 (!texObj->Immutable) {
      const GLboolean genSave = texObj->GenerateMipmap;

      /* Temporarily set GenerateMipmap to true so that allocate_full_mipmap()
       * makes the right decision about full mipmap allocation.
       */
      texObj->GenerateMipmap = GL_TRUE;

      _mesa_prepare_mipmap_levels(ctx, texObj, baseLevel, lastLevel);

      texObj->GenerateMipmap = genSave;

      /* At this point, memory for all the texture levels has been
       * allocated.  However, the base level image may be in one resource
       * while the subsequent/smaller levels may be in another resource.
       * Finalizing the texture will copy the base images from the former
       * resource to the latter.
       *
       * After this, we'll have all mipmap levels in one resource.
       */
      st_finalize_texture(ctx, st->pipe, texObj);
   }

   pt = stObj->pt;
   if (!pt) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "mipmap generation");
      return;
   }

   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);
   }

   if (stObj->surface_based)
      format = stObj->surface_format;
   else
      format = pt->format;

   /* First see if the driver supports hardware mipmap generation,
    * if not then generate the mipmap by rendering/texturing.
    * If that fails, use the software fallback.
    */
   if (!st->pipe->screen->get_param(st->pipe->screen,
                                    PIPE_CAP_GENERATE_MIPMAP) ||
       !st->pipe->generate_mipmap(st->pipe, pt, format, baseLevel,
                                  lastLevel, first_layer, last_layer)) {

      if (!util_gen_mipmap(st->pipe, pt, format, baseLevel, lastLevel,
                           first_layer, last_layer, PIPE_TEX_FILTER_LINEAR)) {
         _mesa_generate_mipmap(ctx, target, texObj);
      }
   }
}
Esempio n. 7
0
/**
 * Software fallback for generate mipmap levels.
 */
static void
fallback_generate_mipmap(struct gl_context *ctx, GLenum target,
                         struct gl_texture_object *texObj)
{
   struct pipe_context *pipe = st_context(ctx)->pipe;
   struct pipe_resource *pt = st_get_texobj_resource(texObj);
   const uint baseLevel = texObj->BaseLevel;
   const uint lastLevel = pt->last_level;
   const uint face = _mesa_tex_target_to_face(target);
   uint dstLevel;
   GLenum datatype;
   GLuint comps;
   GLboolean compressed;

   if (ST_DEBUG & DEBUG_FALLBACK)
      debug_printf("%s: fallback processing\n", __FUNCTION__);

   assert(target != GL_TEXTURE_3D); /* not done yet */

   compressed =
      _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat);

   if (compressed) {
      GLenum type =
         _mesa_get_format_datatype(texObj->Image[face][baseLevel]->TexFormat);

      datatype = type == GL_UNSIGNED_NORMALIZED ? GL_UNSIGNED_BYTE : GL_FLOAT;
      comps = 4;
   }
   else {
      _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat,
                                     &datatype, &comps);
      assert(comps > 0 && "bad texture format in fallback_generate_mipmap()");
   }

   for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
      const uint srcLevel = dstLevel - 1;
      const uint srcWidth = u_minify(pt->width0, srcLevel);
      const uint srcHeight = u_minify(pt->height0, srcLevel);
      const uint srcDepth = u_minify(pt->depth0, srcLevel);
      const uint dstWidth = u_minify(pt->width0, dstLevel);
      const uint dstHeight = u_minify(pt->height0, dstLevel);
      const uint dstDepth = u_minify(pt->depth0, dstLevel);
      struct pipe_transfer *srcTrans, *dstTrans;
      const ubyte *srcData;
      ubyte *dstData;
      int srcStride, dstStride;

      srcTrans = pipe_get_transfer(pipe, pt, srcLevel,
                                   face,
                                   PIPE_TRANSFER_READ, 0, 0,
                                   srcWidth, srcHeight);

      dstTrans = pipe_get_transfer(pipe, pt, dstLevel,
                                   face,
                                   PIPE_TRANSFER_WRITE, 0, 0,
                                   dstWidth, dstHeight);

      srcData = (ubyte *) pipe_transfer_map(pipe, srcTrans);
      dstData = (ubyte *) pipe_transfer_map(pipe, dstTrans);

      srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format);
      dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format);

     /* this cannot work correctly for 3d since it does
        not respect layerStride. */
      if (compressed) {
         const enum pipe_format format = pt->format;
         const uint bw = util_format_get_blockwidth(format);
         const uint bh = util_format_get_blockheight(format);
         const uint srcWidth2 = align(srcWidth, bw);
         const uint srcHeight2 = align(srcHeight, bh);
         const uint dstWidth2 = align(dstWidth, bw);
         const uint dstHeight2 = align(dstHeight, bh);
         uint8_t *srcTemp, *dstTemp;

         assert(comps == 4);

         srcTemp = malloc(srcWidth2 * srcHeight2 * comps * (datatype == GL_FLOAT ? 4 : 1));
         dstTemp = malloc(dstWidth2 * dstHeight2 * comps * (datatype == GL_FLOAT ? 4 : 1));

         /* decompress the src image: srcData -> srcTemp */
         decompress_image(format, datatype, srcData, srcTemp, srcWidth2, srcHeight2, srcTrans->stride);

         _mesa_generate_mipmap_level(target, datatype, comps,
                                     0 /*border*/,
                                     srcWidth2, srcHeight2, srcDepth,
                                     srcTemp,
                                     srcWidth2, /* stride in texels */
                                     dstWidth2, dstHeight2, dstDepth,
                                     dstTemp,
                                     dstWidth2); /* stride in texels */

         /* compress the new image: dstTemp -> dstData */
         compress_image(format, datatype, dstTemp, dstData, dstWidth2, dstHeight2, dstTrans->stride);

         free(srcTemp);
         free(dstTemp);
      }
      else {
         _mesa_generate_mipmap_level(target, datatype, comps,
                                     0 /*border*/,
                                     srcWidth, srcHeight, srcDepth,
                                     srcData,
                                     srcStride, /* stride in texels */
                                     dstWidth, dstHeight, dstDepth,
                                     dstData,
                                     dstStride); /* stride in texels */
      }

      pipe_transfer_unmap(pipe, srcTrans);
      pipe_transfer_unmap(pipe, dstTrans);

      pipe->transfer_destroy(pipe, srcTrans);
      pipe->transfer_destroy(pipe, dstTrans);
   }
}