コード例 #1
0
ファイル: texobj.c プロジェクト: jay8muel/Renderfusion
/**
 * Set texture priorities.
 * 
 * \param n number of textures.
 * \param texName texture names.
 * \param priorities corresponding texture priorities.
 * 
 * \sa glPrioritizeTextures().
 * 
 * Looks up each texture in the hash, clamps the corresponding priority between
 * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
 */
void GLAPIENTRY
_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
                          const GLclampf *priorities )
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);

   if (n < 0) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
      return;
   }

   if (!priorities)
      return;

   for (i = 0; i < n; i++) {
      if (texName[i] > 0) {
         struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]);
         if (t) {
            t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
         }
      }
   }

   ctx->NewState |= _NEW_TEXTURE;
}
コード例 #2
0
ファイル: texobj.c プロジェクト: RAOF/mesa
/**
 * Set texture priorities.
 * 
 * \param n number of textures.
 * \param texName texture names.
 * \param priorities corresponding texture priorities.
 * 
 * \sa glPrioritizeTextures().
 * 
 * Looks up each texture in the hash, clamps the corresponding priority between
 * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
 */
void GLAPIENTRY
_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
                          const GLclampf *priorities )
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;

   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
      _mesa_debug(ctx, "glPrioritizeTextures %d\n", n);

   FLUSH_VERTICES(ctx, 0);

   if (n < 0) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
      return;
   }

   if (!priorities)
      return;

   for (i = 0; i < n; i++) {
      if (texName[i] > 0) {
         struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]);
         if (t) {
            t->Priority = CLAMP( priorities[i], 0.0F, 1.0F );
         }
      }
   }

   ctx->NewState |= _NEW_TEXTURE;
}
コード例 #3
0
ファイル: meta_blit.c プロジェクト: TechnoMancer/mesa
GLboolean
_mesa_meta_bind_rb_as_tex_image(struct gl_context *ctx,
                                struct gl_renderbuffer *rb,
                                GLuint *tex,
                                struct gl_texture_object **texObj,
                                GLenum *target)
{
   struct gl_texture_image *texImage;

   if (rb->NumSamples > 1)
      *target = GL_TEXTURE_2D_MULTISAMPLE;
   else
      *target = GL_TEXTURE_2D;

   _mesa_GenTextures(1, tex);
   _mesa_BindTexture(*target, *tex);
   *texObj = _mesa_lookup_texture(ctx, *tex);
   texImage = _mesa_get_tex_image(ctx, *texObj, *target, 0);

   if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) {
      _mesa_DeleteTextures(1, tex);
      return false;
   }

   if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
      rb->NeedsFinishRenderTexture = true;
      ctx->Driver.FinishRenderTexture(ctx, rb);
   }

   return true;
}
コード例 #4
0
void GLAPIENTRY
_mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level,
                       GLboolean layered, GLint layer, GLenum access,
                       GLenum format)
{
   GET_CURRENT_CONTEXT(ctx);
   struct gl_image_unit *u;

   if (!validate_bind_image_texture(ctx, unit, texture, level,
                                    layered, layer, access, format))
      return;

   u = &ctx->ImageUnits[unit];

   FLUSH_VERTICES(ctx, 0);
   ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;

   if (texture) {
      struct gl_texture_object *t = _mesa_lookup_texture(ctx, texture);

      if (!t) {
         _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(texture)");
         return;
      }

      /* From section 8.22 "Texture Image Loads and Stores" of the OpenGL ES
       * 3.1 spec:
       *
       * "An INVALID_OPERATION error is generated if texture is not the name
       *  of an immutable texture object."
       */
      if (_mesa_is_gles(ctx) && !t->Immutable) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glBindImageTexture(!immutable)");
         return;
      }

      _mesa_reference_texobj(&u->TexObj, t);
   } else {
      _mesa_reference_texobj(&u->TexObj, NULL);
   }

   u->Level = level;
   u->Access = access;
   u->Format = format;
   u->_ActualFormat = _mesa_get_shader_image_format(format);

   if (u->TexObj && _mesa_tex_target_is_layered(u->TexObj->Target)) {
      u->Layered = layered;
      u->Layer = layer;
      u->_Layer = (u->Layered ? 0 : u->Layer);
   } else {
      u->Layered = GL_FALSE;
      u->Layer = 0;
   }

   if (ctx->Driver.BindImageTexture)
      ctx->Driver.BindImageTexture(ctx, u, u->TexObj, level, layered,
                                   layer, access, format);
}
コード例 #5
0
ファイル: texobj.c プロジェクト: jay8muel/Renderfusion
/**
 * See if textures are loaded in texture memory.
 * 
 * \param n number of textures to query.
 * \param texName array with the texture names.
 * \param residences array which will hold the residence status.
 *
 * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 
 * 
 * Note: we assume all textures are always resident
 */
GLboolean GLAPIENTRY
_mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
                          GLboolean *residences)
{
   GET_CURRENT_CONTEXT(ctx);
   GLboolean allResident = GL_TRUE;
   GLint i;
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);

   if (n < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
      return GL_FALSE;
   }

   if (!texName || !residences)
      return GL_FALSE;

   /* We only do error checking on the texture names */
   for (i = 0; i < n; i++) {
      struct gl_texture_object *t;
      if (texName[i] == 0) {
         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
         return GL_FALSE;
      }
      t = _mesa_lookup_texture(ctx, texName[i]);
      if (!t) {
         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
         return GL_FALSE;
      }
   }
   
   return allResident;
}
/* This function makes a texture view without bothering with all of the API
 * checks.  Most of them are the same for CopyTexSubImage so checking would
 * be redundant.  The one major difference is that we don't check for
 * whether the texture is immutable or not.  However, since the view will
 * be created and then immediately destroyed, this should not be a problem.
 */
static bool
make_view(struct gl_context *ctx, struct gl_texture_image *tex_image,
          struct gl_texture_image **view_tex_image, GLuint *view_tex_name,
          GLenum internal_format)
{
   struct gl_texture_object *tex_obj = tex_image->TexObject;
   struct gl_texture_object *view_tex_obj;
   mesa_format tex_format;

   /* Set up the new texture object */
   _mesa_GenTextures(1, view_tex_name);
   view_tex_obj = _mesa_lookup_texture(ctx, *view_tex_name);
   if (!view_tex_obj)
      return false;

   tex_format = _mesa_choose_texture_format(ctx, view_tex_obj, tex_obj->Target,
                                           0, internal_format,
                                           GL_NONE, GL_NONE);

   if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 0, tex_format,
                                      tex_image->Width, tex_image->Height,
                                      tex_image->Depth, 0)) {
      _mesa_DeleteTextures(1, view_tex_name);
      *view_tex_name = 0;
      return false;
   }

   view_tex_obj->Target = tex_obj->Target;

   *view_tex_image = _mesa_get_tex_image(ctx, view_tex_obj, tex_obj->Target, 0);

   if (!*view_tex_image) {
      _mesa_DeleteTextures(1, view_tex_name);
      *view_tex_name = 0;
      return false;
   }

   _mesa_init_teximage_fields(ctx, *view_tex_image,
                              tex_image->Width, tex_image->Height,
                              tex_image->Depth,
                              0, internal_format, tex_format);

   view_tex_obj->MinLevel = tex_image->Level;
   view_tex_obj->NumLevels = 1;
   view_tex_obj->MinLayer = tex_obj->MinLayer;
   view_tex_obj->NumLayers = tex_obj->NumLayers;
   view_tex_obj->Immutable = tex_obj->Immutable;
   view_tex_obj->ImmutableLevels = tex_obj->ImmutableLevels;
   view_tex_obj->Target = tex_obj->Target;

   if (ctx->Driver.TextureView != NULL &&
       !ctx->Driver.TextureView(ctx, view_tex_obj, tex_obj)) {
      _mesa_DeleteTextures(1, view_tex_name);
      *view_tex_name = 0;
      return false; /* driver recorded error */
   }

   return true;
}
コード例 #7
0
ファイル: intel_screen.c プロジェクト: ashmew2/kolibriosSVN
static __DRIimage *
intel_create_image_from_texture(__DRIcontext *context, int target,
                                unsigned texture, int zoffset,
                                int level,
                                unsigned *error,
                                void *loaderPrivate)
{
   __DRIimage *image;
   struct brw_context *brw = context->driverPrivate;
   struct gl_texture_object *obj;
   struct intel_texture_object *iobj;
   GLuint face = 0;

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

   if (target == GL_TEXTURE_CUBE_MAP)
      face = zoffset;

   _mesa_test_texobj_completeness(&brw->ctx, obj);
   iobj = intel_texture_object(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 < zoffset) {
      *error = __DRI_IMAGE_ERROR_BAD_MATCH;
      return NULL;
   }
   image = calloc(1, sizeof *image);
   if (image == NULL) {
      *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
      return NULL;
   }

   image->internal_format = obj->Image[face][level]->InternalFormat;
   image->format = obj->Image[face][level]->TexFormat;
   image->data = loaderPrivate;
   intel_setup_image_from_mipmap_tree(brw, image, iobj->mt, level, zoffset);
   image->dri_format = driGLFormatToImageFormat(image->format);
   image->has_depthstencil = iobj->mt->stencil_mt? true : false;
   if (image->dri_format == MESA_FORMAT_NONE) {
      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
      free(image);
      return NULL;
   }

   *error = __DRI_IMAGE_ERROR_SUCCESS;
   return image;
}
コード例 #8
0
ファイル: texobj.c プロジェクト: RAOF/mesa
/**
 * Delete named textures.
 *
 * \param n number of textures to be deleted.
 * \param textures array of texture IDs to be deleted.
 *
 * \sa glDeleteTextures().
 *
 * If we're about to delete a texture that's currently bound to any
 * texture unit, unbind the texture first.  Decrement the reference
 * count on the texture object and delete it if it's zero.
 * Recall that texture objects can be shared among several rendering
 * contexts.
 */
void GLAPIENTRY
_mesa_DeleteTextures( GLsizei n, const GLuint *textures)
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;

   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
      _mesa_debug(ctx, "glDeleteTextures %d\n", n);

   FLUSH_VERTICES(ctx, 0); /* too complex */

   if (!textures)
      return;

   for (i = 0; i < n; i++) {
      if (textures[i] > 0) {
         struct gl_texture_object *delObj
            = _mesa_lookup_texture(ctx, textures[i]);

         if (delObj) {
            _mesa_lock_texture(ctx, delObj);

            /* Check if texture is bound to any framebuffer objects.
             * If so, unbind.
             * See section 4.4.2.3 of GL_EXT_framebuffer_object.
             */
            unbind_texobj_from_fbo(ctx, delObj);

            /* Check if this texture is currently bound to any texture units.
             * If so, unbind it.
             */
            unbind_texobj_from_texunits(ctx, delObj);

            _mesa_unlock_texture(ctx, delObj);

            ctx->NewState |= _NEW_TEXTURE;

            /* The texture _name_ is now free for re-use.
             * Remove it from the hash table now.
             */
            _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
            _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
            _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);

            /* Unreference the texobj.  If refcount hits zero, the texture
             * will be deleted.
             */
            _mesa_reference_texobj(&delObj, NULL);
         }
      }
   }
}
コード例 #9
0
ファイル: texobj.c プロジェクト: jay8muel/Renderfusion
static struct gl_texture_object *
invalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture,
                                 GLint level, const char *name)
{
   /* The GL_ARB_invalidate_subdata spec says:
    *
    *     "If <texture> is zero or is not the name of a texture, the error
    *     INVALID_VALUE is generated."
    *
    * This performs the error check in a different order than listed in the
    * spec.  We have to get the texture object before we can validate the
    * other parameters against values in the texture object.
    */
   struct gl_texture_object *const t = _mesa_lookup_texture(ctx, texture);
   if (texture == 0 || t == NULL) {
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(texture)", name);
      return NULL;
   }

   /* The GL_ARB_invalidate_subdata spec says:
    *
    *     "If <level> is less than zero or greater than the base 2 logarithm
    *     of the maximum texture width, height, or depth, the error
    *     INVALID_VALUE is generated."
    */
   if (level < 0 || level > t->MaxLevel) {
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name);
      return NULL;
   }

   /* The GL_ARB_invalidate_subdata spec says:
    *
    *     "If the target of <texture> is TEXTURE_RECTANGLE, TEXTURE_BUFFER,
    *     TEXTURE_2D_MULTISAMPLE, or TEXTURE_2D_MULTISAMPLE_ARRAY, and <level>
    *     is not zero, the error INVALID_VALUE is generated."
    */
   if (level != 0) {
      switch (t->Target) {
      case GL_TEXTURE_RECTANGLE:
      case GL_TEXTURE_BUFFER:
      case GL_TEXTURE_2D_MULTISAMPLE:
      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
         _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name);
         return NULL;

      default:
         break;
      }
   }

   return t;
}
コード例 #10
0
ファイル: shaderimage.c プロジェクト: DirectFB/mesa
void GLAPIENTRY
_mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level,
                       GLboolean layered, GLint layer, GLenum access,
                       GLenum format)
{
   GET_CURRENT_CONTEXT(ctx);
   struct gl_texture_object *t = NULL;
   struct gl_image_unit *u;

   if (!validate_bind_image_texture(ctx, unit, texture, level,
                                    layered, layer, access, format))
      return;

   u = &ctx->ImageUnits[unit];

   FLUSH_VERTICES(ctx, 0);
   ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;

   if (texture) {
      t = _mesa_lookup_texture(ctx, texture);
      if (!t) {
         _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(texture)");
         return;
      }

      _mesa_reference_texobj(&u->TexObj, t);
      u->Level = level;
      u->Access = access;
      u->Format = format;
      u->_ActualFormat = get_image_format(format);

      if (_mesa_tex_target_is_layered(t->Target)) {
         u->Layered = layered;
         u->Layer = (layered ? 0 : layer);
      } else {
         u->Layered = GL_FALSE;
         u->Layer = 0;
      }

   } else {
      _mesa_reference_texobj(&u->TexObj, NULL);
   }

   u->_Valid = validate_image_unit(ctx, u);

   if (ctx->Driver.BindImageTexture)
      ctx->Driver.BindImageTexture(ctx, u, t, level, layered,
                                   layer, access, format);
}
コード例 #11
0
ファイル: texobj.c プロジェクト: jay8muel/Renderfusion
/**
 * See if a name corresponds to a texture.
 *
 * \param texture texture name.
 *
 * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
 * otherwise.
 * 
 * \sa glIsTexture().
 *
 * Calls _mesa_HashLookup().
 */
GLboolean GLAPIENTRY
_mesa_IsTexture( GLuint texture )
{
   struct gl_texture_object *t;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);

   if (!texture)
      return GL_FALSE;

   t = _mesa_lookup_texture(ctx, texture);

   /* IsTexture is true only after object has been bound once. */
   return t && t->Target;
}
コード例 #12
0
ファイル: r300_texstate.c プロジェクト: emcmanus/FlashMesa3D
void r300SetTexOffset(__DRIcontext * pDRICtx, GLint texname,
		      unsigned long long offset, GLint depth, GLuint pitch)
{
	r300ContextPtr rmesa = pDRICtx->driverPrivate;
	struct gl_texture_object *tObj =
	    _mesa_lookup_texture(rmesa->radeon.glCtx, texname);
	radeonTexObjPtr t = radeon_tex_obj(tObj);
	uint32_t pitch_val;

	if (!tObj)
		return;

	t->image_override = GL_TRUE;

	if (!offset)
		return;

	t->bo = NULL;
	t->override_offset = offset;
	t->pp_txpitch &= (1 << 13) -1;
	pitch_val = pitch;

	switch (depth) {
	case 32:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, W, W8Z8Y8X8);
		t->pp_txfilter |= tx_table[2].filter;
		pitch_val /= 4;
		break;
	case 24:
	default:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8);
		t->pp_txfilter |= tx_table[4].filter;
		pitch_val /= 4;
		break;
	case 16:
		t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, Z5Y6X5);
		t->pp_txfilter |= tx_table[5].filter;
		pitch_val /= 2;
		break;
	}
	pitch_val--;

	t->pp_txpitch |= pitch_val;
}
コード例 #13
0
ファイル: texobj.c プロジェクト: GYGit/reactos
/**
 * Delete named textures.
 *
 * \param n number of textures to be deleted.
 * \param textures array of texture IDs to be deleted.
 *
 * \sa glDeleteTextures().
 *
 * If we're about to delete a texture that's currently bound to any
 * texture unit, unbind the texture first.  Decrement the reference
 * count on the texture object and delete it if it's zero.
 * Recall that texture objects can be shared among several rendering
 * contexts.
 */
void GLAPIENTRY
_mesa_DeleteTextures( GLsizei n, const GLuint *textures)
{
   GET_CURRENT_CONTEXT(ctx);
   GLint i;
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */

   if (!textures)
      return;

   for (i = 0; i < n; i++) {
      if (textures[i] > 0) {
         struct gl_texture_object *delObj
            = _mesa_lookup_texture(ctx, textures[i]);

         if (delObj) {
            _mesa_lock_texture(ctx, delObj);

            /* Check if this texture is currently bound to any texture units.
             * If so, unbind it.
             */
            unbind_texobj_from_texunits(ctx, delObj);

            _mesa_unlock_texture(ctx, delObj);

            ctx->NewState |= _NEW_TEXTURE;

            /* The texture _name_ is now free for re-use.
             * Remove it from the hash table now.
             */
            _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
            _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
            _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);

            /* Unreference the texobj.  If refcount hits zero, the texture
             * will be deleted.
             */
            _mesa_reference_texobj(&delObj, NULL);
         }
      }
   }
}
コード例 #14
0
void
intelSetTexOffset(__DRIcontext *pDRICtx, GLint texname,
		  unsigned long long offset, GLint depth, GLuint pitch)
{
   struct intel_context *intel = (struct intel_context*)
      ((__DRIcontextPrivate*)pDRICtx->private)->driverPrivate;
   struct gl_texture_object *tObj = _mesa_lookup_texture(&intel->ctx, texname);
   struct intel_texture_object *intelObj = intel_texture_object(tObj);

   if (!intelObj)
      return;

   if (intelObj->mt)
      intel_miptree_release(intel, &intelObj->mt);

   intelObj->imageOverride = GL_TRUE;
   intelObj->depthOverride = depth;
   intelObj->pitchOverride = pitch;

   if (offset)
      intelObj->textureOffset = offset;
}
コード例 #15
0
/**
 * Try to do a color or depth glBlitFramebuffer using texturing.
 *
 * We can do this when the src renderbuffer is actually a texture, or when the
 * driver exposes BindRenderbufferTexImage().
 */
static bool
blitframebuffer_texture(struct gl_context *ctx,
                        const struct gl_framebuffer *readFb,
                        const struct gl_framebuffer *drawFb,
                        GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                        GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                        GLenum filter, GLint flipX, GLint flipY,
                        GLboolean glsl_version, GLboolean do_depth)
{
   int att_index = do_depth ? BUFFER_DEPTH : readFb->_ColorReadBufferIndex;
   const struct gl_renderbuffer_attachment *readAtt =
      &readFb->Attachment[att_index];
   struct blit_state *blit = &ctx->Meta->Blit;
   struct fb_tex_blit_state fb_tex_blit;
   const GLint dstX = MIN2(dstX0, dstX1);
   const GLint dstY = MIN2(dstY0, dstY1);
   const GLint dstW = abs(dstX1 - dstX0);
   const GLint dstH = abs(dstY1 - dstY0);
   const int srcW = abs(srcX1 - srcX0);
   const int srcH = abs(srcY1 - srcY0);
   bool scaled_blit = false;
   struct gl_texture_object *texObj;
   GLuint srcLevel;
   GLenum target;
   struct gl_renderbuffer *rb = readAtt->Renderbuffer;
   struct temp_texture *meta_temp_texture;

   if (rb->NumSamples && !ctx->Extensions.ARB_texture_multisample)
      return false;

   _mesa_meta_fb_tex_blit_begin(ctx, &fb_tex_blit);

   if (readAtt->Texture &&
       (readAtt->Texture->Target == GL_TEXTURE_2D ||
        readAtt->Texture->Target == GL_TEXTURE_RECTANGLE ||
        readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE ||
        readAtt->Texture->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) {
      /* If there's a texture attached of a type we can handle, then just use
       * it directly.
       */
      srcLevel = readAtt->TextureLevel;
      texObj = readAtt->Texture;
      target = texObj->Target;
   } else if (!readAtt->Texture && ctx->Driver.BindRenderbufferTexImage) {
      if (!_mesa_meta_bind_rb_as_tex_image(ctx, rb, &fb_tex_blit.tempTex,
                                           &texObj, &target))
         return false;

      srcLevel = 0;
      if (_mesa_is_winsys_fbo(readFb)) {
         GLint temp = srcY0;
         srcY0 = rb->Height - srcY1;
         srcY1 = rb->Height - temp;
         flipY = -flipY;
      }
   } else {
      GLenum tex_base_format;
      /* Fall back to doing a CopyTexSubImage to get the destination
       * renderbuffer into a texture.
       */
      if (ctx->Meta->Blit.no_ctsi_fallback)
         return false;

      if (rb->NumSamples > 1)
         return false;

      if (do_depth) {
         meta_temp_texture = _mesa_meta_get_temp_depth_texture(ctx);
         tex_base_format = GL_DEPTH_COMPONENT;
      } else {
         meta_temp_texture = _mesa_meta_get_temp_texture(ctx);
         tex_base_format =
            _mesa_base_tex_format(ctx, rb->InternalFormat);
      }

      srcLevel = 0;
      target = meta_temp_texture->Target;
      texObj = _mesa_lookup_texture(ctx, meta_temp_texture->TexObj);
      if (texObj == NULL) {
         return false;
      }

      _mesa_meta_setup_copypix_texture(ctx, meta_temp_texture,
                                       srcX0, srcY0,
                                       srcW, srcH,
                                       tex_base_format,
                                       filter);


      srcX0 = 0;
      srcY0 = 0;
      srcX1 = srcW;
      srcY1 = srcH;
   }

   fb_tex_blit.baseLevelSave = texObj->BaseLevel;
   fb_tex_blit.maxLevelSave = texObj->MaxLevel;
   fb_tex_blit.stencilSamplingSave = texObj->StencilSampling;

   scaled_blit = dstW != srcW || dstH != srcH;

   if (glsl_version) {
      setup_glsl_blit_framebuffer(ctx, blit, drawFb, rb, target, filter, scaled_blit,
                                  do_depth);
   }
   else {
      _mesa_meta_setup_ff_tnl_for_blit(ctx,
                                       &ctx->Meta->Blit.VAO,
                                       &ctx->Meta->Blit.buf_obj,
                                       2);
   }

   /*
     printf("Blit from texture!\n");
     printf("  srcAtt %p  dstAtt %p\n", readAtt, drawAtt);
     printf("  srcTex %p  dstText %p\n", texObj, drawAtt->Texture);
   */

   fb_tex_blit.sampler = _mesa_meta_setup_sampler(ctx, texObj, target, filter,
                                                  srcLevel);

   /* Always do our blits with no net sRGB decode or encode.
    *
    * However, if both the src and dst can be srgb decode/encoded, enable them
    * so that we do any blending (from scaling or from MSAA resolves) in the
    * right colorspace.
    *
    * Our choice of not doing any net encode/decode is from the GL 3.0
    * specification:
    *
    *     "Blit operations bypass the fragment pipeline. The only fragment
    *      operations which affect a blit are the pixel ownership test and the
    *      scissor test."
    *
    * The GL 4.4 specification disagrees and says that the sRGB part of the
    * fragment pipeline applies, but this was found to break applications.
    */
   if (ctx->Extensions.EXT_texture_sRGB_decode) {
      if (_mesa_get_format_color_encoding(rb->Format) == GL_SRGB &&
          drawFb->Visual.sRGBCapable) {
         _mesa_SamplerParameteri(fb_tex_blit.sampler,
                                 GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
         _mesa_set_framebuffer_srgb(ctx, GL_TRUE);
      } else {
         _mesa_SamplerParameteri(fb_tex_blit.sampler,
                                 GL_TEXTURE_SRGB_DECODE_EXT,
                                 GL_SKIP_DECODE_EXT);
         /* set_framebuffer_srgb was set by _mesa_meta_begin(). */
      }
   }

   if (!glsl_version) {
      _mesa_TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
      _mesa_set_enable(ctx, target, GL_TRUE);
   }

   /* Prepare vertex data (the VBO was previously created and bound) */
   {
      struct vertex verts[4];
      GLfloat s0, t0, s1, t1;

      if (target == GL_TEXTURE_2D) {
         const struct gl_texture_image *texImage
            = _mesa_select_tex_image(texObj, target, srcLevel);
         s0 = srcX0 / (float) texImage->Width;
         s1 = srcX1 / (float) texImage->Width;
         t0 = srcY0 / (float) texImage->Height;
         t1 = srcY1 / (float) texImage->Height;
      }
      else {
         assert(target == GL_TEXTURE_RECTANGLE_ARB ||
                target == GL_TEXTURE_2D_MULTISAMPLE ||
                target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
         s0 = (float) srcX0;
         s1 = (float) srcX1;
         t0 = (float) srcY0;
         t1 = (float) srcY1;
      }

      /* Silence valgrind warnings about reading uninitialized stack. */
      memset(verts, 0, sizeof(verts));

      /* setup vertex positions */
      verts[0].x = -1.0F * flipX;
      verts[0].y = -1.0F * flipY;
      verts[1].x =  1.0F * flipX;
      verts[1].y = -1.0F * flipY;
      verts[2].x =  1.0F * flipX;
      verts[2].y =  1.0F * flipY;
      verts[3].x = -1.0F * flipX;
      verts[3].y =  1.0F * flipY;

      verts[0].tex[0] = s0;
      verts[0].tex[1] = t0;
      verts[0].tex[2] = readAtt->Zoffset;
      verts[1].tex[0] = s1;
      verts[1].tex[1] = t0;
      verts[1].tex[2] = readAtt->Zoffset;
      verts[2].tex[0] = s1;
      verts[2].tex[1] = t1;
      verts[2].tex[2] = readAtt->Zoffset;
      verts[3].tex[0] = s0;
      verts[3].tex[1] = t1;
      verts[3].tex[2] = readAtt->Zoffset;

      _mesa_buffer_sub_data(ctx, blit->buf_obj, 0, sizeof(verts), verts,
                            __func__);
   }

   /* setup viewport */
   _mesa_set_viewport(ctx, 0, dstX, dstY, dstW, dstH);
   _mesa_ColorMask(!do_depth, !do_depth, !do_depth, !do_depth);
   _mesa_set_enable(ctx, GL_DEPTH_TEST, do_depth);
   _mesa_DepthMask(do_depth);
   _mesa_DepthFunc(GL_ALWAYS);

   _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
   _mesa_meta_fb_tex_blit_end(ctx, target, &fb_tex_blit);

   return true;
}
コード例 #16
0
ファイル: texobj.c プロジェクト: jay8muel/Renderfusion
/**
 * Bind a named texture to a texturing target.
 * 
 * \param target texture target.
 * \param texName texture name.
 * 
 * \sa glBindTexture().
 *
 * Determines the old texture object bound and returns immediately if rebinding
 * the same texture.  Get the current texture which is either a default texture
 * if name is null, a named texture from the hash, or a new texture if the
 * given texture name is new. Increments its reference count, binds it, and
 * calls dd_function_table::BindTexture. Decrements the old texture reference
 * count and deletes it if it reaches zero.
 */
void GLAPIENTRY
_mesa_BindTexture( GLenum target, GLuint texName )
{
   GET_CURRENT_CONTEXT(ctx);
   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
   struct gl_texture_object *newTexObj = NULL;
   GLint targetIndex;
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
      _mesa_debug(ctx, "glBindTexture %s %d\n",
                  _mesa_lookup_enum_by_nr(target), (GLint) texName);

   targetIndex = target_enum_to_index(ctx, target);
   if (targetIndex < 0) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)");
      return;
   }
   assert(targetIndex < NUM_TEXTURE_TARGETS);

   /*
    * Get pointer to new texture object (newTexObj)
    */
   if (texName == 0) {
      /* Use a default texture object */
      newTexObj = ctx->Shared->DefaultTex[targetIndex];
   }
   else {
      /* non-default texture object */
      newTexObj = _mesa_lookup_texture(ctx, texName);
      if (newTexObj) {
         /* error checking */
         if (newTexObj->Target != 0 && newTexObj->Target != target) {
            /* the named texture object's target doesn't match the given target */
            _mesa_error( ctx, GL_INVALID_OPERATION,
                         "glBindTexture(target mismatch)" );
            return;
         }
         if (newTexObj->Target == 0) {
            finish_texture_init(ctx, target, newTexObj);
         }
      }
      else {
         if (ctx->API == API_OPENGL_CORE) {
            _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture");
            return;
         }

         /* if this is a new texture id, allocate a texture object now */
         newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target);
         if (!newTexObj) {
            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture");
            return;
         }

         /* and insert it into hash table */
         _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
         _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj);
         _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
      }
      newTexObj->Target = target;
   }

   assert(valid_texture_object(newTexObj));

   /* Check if this texture is only used by this context and is already bound.
    * If so, just return.
    */
   {
      GLboolean early_out;
      _glthread_LOCK_MUTEX(ctx->Shared->Mutex);
      early_out = ((ctx->Shared->RefCount == 1)
                   && (newTexObj == texUnit->CurrentTex[targetIndex]));
      _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex);
      if (early_out) {
         return;
      }
   }

   /* flush before changing binding */
   FLUSH_VERTICES(ctx, _NEW_TEXTURE);

   /* Do the actual binding.  The refcount on the previously bound
    * texture object will be decremented.  It'll be deleted if the
    * count hits zero.
    */
   _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj);
   ASSERT(texUnit->CurrentTex[targetIndex]);

   /* Pass BindTexture call to device driver */
   if (ctx->Driver.BindTexture)
      ctx->Driver.BindTexture(ctx, target, newTexObj);
}
コード例 #17
0
ファイル: dri2.c プロジェクト: cwabbott0/mesa
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;
}
コード例 #18
0
ファイル: vdpau.c プロジェクト: ashmew2/kolibriosSVN
static GLintptr
register_surface(struct gl_context *ctx, GLboolean isOutput,
                 const GLvoid *vdpSurface, GLenum target,
                 GLsizei numTextureNames, const GLuint *textureNames)
{
   struct vdp_surface *surf;
   int i;

   if (!ctx->vdpDevice || !ctx->vdpGetProcAddress || !ctx->vdpSurfaces) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAURegisterSurfaceNV");
      return (GLintptr)NULL;
   }

   if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE) {
      _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
      return (GLintptr)NULL;
   }

   if (target == GL_TEXTURE_RECTANGLE && !ctx->Extensions.NV_texture_rectangle) {
      _mesa_error(ctx, GL_INVALID_ENUM, "VDPAURegisterSurfaceNV");
      return (GLintptr)NULL;
   }

   surf = CALLOC_STRUCT( vdp_surface );
   if (surf == NULL) {
      _mesa_error_no_memory("VDPAURegisterSurfaceNV");
      return (GLintptr)NULL;
   }

   surf->vdpSurface = vdpSurface;
   surf->target = target;
   surf->access = GL_READ_WRITE;
   surf->state = GL_SURFACE_REGISTERED_NV;
   surf->output = isOutput;
   for (i = 0; i < numTextureNames; ++i) {
      struct gl_texture_object *tex;
      tex  = _mesa_lookup_texture(ctx, textureNames[i]);
      if (tex == NULL) {
         free(surf);
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "VDPAURegisterSurfaceNV(texture ID not found)");
         return (GLintptr)NULL;
      }

      _mesa_lock_texture(ctx, tex);

      if (tex->Immutable) {
         _mesa_unlock_texture(ctx, tex);
         free(surf);
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "VDPAURegisterSurfaceNV(texture is immutable)");
         return (GLintptr)NULL;
      }

      if (tex->Target == 0)
         tex->Target = target;
      else if (tex->Target != target) {
         _mesa_unlock_texture(ctx, tex);
         free(surf);
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "VDPAURegisterSurfaceNV(target mismatch)");
         return (GLintptr)NULL;
      }

      /* This will disallow respecifying the storage. */
      tex->Immutable = GL_TRUE;
      _mesa_unlock_texture(ctx, tex);

      _mesa_reference_texobj(&surf->textures[i], tex);
   }

   _mesa_set_add(ctx->vdpSurfaces, surf);

   return (GLintptr)surf;
}
コード例 #19
0
ファイル: copyimage.c プロジェクト: Acidburn0zzz/mesa
/**
 * Prepare the source or destination resource, including:
 * - Error checking
 * - Creating texture wrappers for renderbuffers
 * \param name  the texture or renderbuffer name
 * \param target  GL_TEXTURE target or GL_RENDERBUFFER.  For the later, will
 *                be changed to a compatible GL_TEXTURE target.
 * \param level  mipmap level
 * \param tex_obj  returns a pointer to a texture object
 * \param tex_image  returns a pointer to a texture image
 * \param tmp_tex  returns temporary texture object name
 * \return true if success, false if error
 */
static bool
prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level,
               struct gl_texture_object **tex_obj,
               struct gl_texture_image **tex_image, GLuint *tmp_tex,
               const char *dbg_prefix)
{
   if (name == 0) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glCopyImageSubData(%sName = %d)", dbg_prefix, name);
      return false;
   }

   /*
    * INVALID_ENUM is generated
    *  * if either <srcTarget> or <dstTarget>
    *   - is not RENDERBUFFER or a valid non-proxy texture target
    *   - is TEXTURE_BUFFER, or
    *   - is one of the cubemap face selectors described in table 3.17,
    */
   switch (*target) {
   case GL_RENDERBUFFER:
      /* Not a texture target, but valid */
   case GL_TEXTURE_1D:
   case GL_TEXTURE_1D_ARRAY:
   case GL_TEXTURE_2D:
   case GL_TEXTURE_3D:
   case GL_TEXTURE_CUBE_MAP:
   case GL_TEXTURE_RECTANGLE:
   case GL_TEXTURE_2D_ARRAY:
   case GL_TEXTURE_CUBE_MAP_ARRAY:
   case GL_TEXTURE_2D_MULTISAMPLE:
   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
      /* These are all valid */
      break;
   case GL_TEXTURE_EXTERNAL_OES:
      /* Only exists in ES */
   case GL_TEXTURE_BUFFER:
   default:
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
                  _mesa_lookup_enum_by_nr(*target));
      return false;
   }

   if (*target == GL_RENDERBUFFER) {
      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
      if (!rb) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
         return false;
      }

      if (!rb->Name) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glCopyImageSubData(%sName incomplete)", dbg_prefix);
         return false;
      }

      if (level != 0) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
         return false;
      }

      if (rb->NumSamples > 1)
         *target = GL_TEXTURE_2D_MULTISAMPLE;
      else
         *target = GL_TEXTURE_2D;

      *tmp_tex = 0;
      _mesa_GenTextures(1, tmp_tex);
      if (*tmp_tex == 0)
         return false; /* Error already set by GenTextures */

      _mesa_BindTexture(*target, *tmp_tex);
      *tex_obj = _mesa_lookup_texture(ctx, *tmp_tex);
      *tex_image = _mesa_get_tex_image(ctx, *tex_obj, *target, 0);

      if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, *tex_image)) {
         _mesa_problem(ctx, "Failed to create texture from renderbuffer");
         return false;
      }

      if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
         rb->NeedsFinishRenderTexture = true;
         ctx->Driver.FinishRenderTexture(ctx, rb);
      }
   } else {
      *tex_obj = _mesa_lookup_texture(ctx, name);
      if (!*tex_obj) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
         return false;
      }

      _mesa_test_texobj_completeness(ctx, *tex_obj);
      if (!(*tex_obj)->_BaseComplete ||
          (level != 0 && !(*tex_obj)->_MipmapComplete)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glCopyImageSubData(%sName incomplete)", dbg_prefix);
         return false;
      }

      if ((*tex_obj)->Target != *target) {
         _mesa_error(ctx, GL_INVALID_ENUM,
                     "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
                     _mesa_lookup_enum_by_nr(*target));
         return false;
      }

      if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level);
         return false;
      }

      *tex_image = _mesa_select_tex_image(*tex_obj, *target, level);
      if (!*tex_image) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
         return false;
      }
   }

   return true;
}
コード例 #20
0
ファイル: meta_tex_subimage.c プロジェクト: olvaffe/mesa
static struct gl_texture_image *
create_texture_for_pbo(struct gl_context *ctx, bool create_pbo,
                       GLenum pbo_target, int width, int height,
                       GLenum format, GLenum type, const void *pixels,
                       const struct gl_pixelstore_attrib *packing,
                       GLuint *tmp_pbo, GLuint *tmp_tex)
{
   uint32_t pbo_format;
   GLenum internal_format;
   unsigned row_stride;
   struct gl_buffer_object *buffer_obj;
   struct gl_texture_object *tex_obj;
   struct gl_texture_image *tex_image;
   bool read_only;

   if (packing->SwapBytes ||
       packing->LsbFirst ||
       packing->Invert)
      return NULL;

   pbo_format = _mesa_format_from_format_and_type(format, type);
   if (_mesa_format_is_mesa_array_format(pbo_format))
      pbo_format = _mesa_format_from_array_format(pbo_format);

   if (!pbo_format || !ctx->TextureFormatSupported[pbo_format])
      return NULL;

   /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */
   pixels = _mesa_image_address3d(packing, pixels,
                                  width, height, format, type, 0, 0, 0);
   row_stride = _mesa_image_row_stride(packing, width, format, type);

   if (_mesa_is_bufferobj(packing->BufferObj)) {
      *tmp_pbo = 0;
      buffer_obj = packing->BufferObj;
   } else {
      bool is_pixel_pack = pbo_target == GL_PIXEL_PACK_BUFFER;

      assert(create_pbo);

      _mesa_GenBuffers(1, tmp_pbo);

      /* We are not doing this inside meta_begin/end.  However, we know the
       * client doesn't have the given target bound, so we can go ahead and
       * squash it.  We'll set it back when we're done.
       */
      _mesa_BindBuffer(pbo_target, *tmp_pbo);

      /* In case of GL_PIXEL_PACK_BUFFER, pass null pointer for the pixel
       * data to avoid unnecessary data copying in _mesa_BufferData().
       */
      if (is_pixel_pack)
         _mesa_BufferData(pbo_target, row_stride * height, NULL,
                          GL_STREAM_READ);
      else
         _mesa_BufferData(pbo_target, row_stride * height, pixels,
                          GL_STREAM_DRAW);

      buffer_obj = packing->BufferObj;
      pixels = NULL;

      _mesa_BindBuffer(pbo_target, 0);
   }

   _mesa_GenTextures(1, tmp_tex);
   tex_obj = _mesa_lookup_texture(ctx, *tmp_tex);
   _mesa_initialize_texture_object(ctx, tex_obj, *tmp_tex, GL_TEXTURE_2D);
   /* This must be set after _mesa_initialize_texture_object, not before. */
   tex_obj->Immutable = GL_TRUE;
   /* This is required for interactions with ARB_texture_view. */
   tex_obj->NumLayers = 1;

   internal_format = _mesa_get_format_base_format(pbo_format);

   tex_image = _mesa_get_tex_image(ctx, tex_obj, tex_obj->Target, 0);
   _mesa_init_teximage_fields(ctx, tex_image, width, height, 1,
                              0, internal_format, pbo_format);

   read_only = pbo_target == GL_PIXEL_UNPACK_BUFFER;
   if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, tex_obj,
                                                     buffer_obj,
                                                     (intptr_t)pixels,
                                                     row_stride,
                                                     read_only)) {
      _mesa_DeleteTextures(1, tmp_tex);
      _mesa_DeleteBuffers(1, tmp_pbo);
      return NULL;
   }

   return tex_image;
}
コード例 #21
0
static struct gl_texture_image *
create_texture_for_pbo(struct gl_context *ctx,
                       bool create_pbo, GLenum pbo_target,
                       int dims, int width, int height, int depth,
                       GLenum format, GLenum type, const void *pixels,
                       const struct gl_pixelstore_attrib *packing,
                       struct gl_buffer_object **tmp_pbo, GLuint *tmp_tex)
{
   uint32_t pbo_format;
   GLenum internal_format;
   unsigned row_stride;
   struct gl_buffer_object *buffer_obj;
   struct gl_texture_object *tex_obj;
   struct gl_texture_image *tex_image;
   bool read_only;

   if (packing->SwapBytes ||
       packing->LsbFirst ||
       packing->Invert)
      return NULL;

   pbo_format = _mesa_format_from_format_and_type(format, type);
   if (_mesa_format_is_mesa_array_format(pbo_format))
      pbo_format = _mesa_format_from_array_format(pbo_format);

   if (!pbo_format || !ctx->TextureFormatSupported[pbo_format])
      return NULL;

   /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */
   uint32_t first_pixel = _mesa_image_offset(dims, packing, width, height,
                                             format, type,
                                             0, 0, 0);
   uint32_t last_pixel =  _mesa_image_offset(dims, packing, width, height,
                                             format, type,
                                             depth-1, height-1, width);
   row_stride = _mesa_image_row_stride(packing, width, format, type);

   if (_mesa_is_bufferobj(packing->BufferObj)) {
      *tmp_pbo = NULL;
      buffer_obj = packing->BufferObj;
      first_pixel += (intptr_t)pixels;
   } else {
      bool is_pixel_pack = pbo_target == GL_PIXEL_PACK_BUFFER;

      assert(create_pbo);

      *tmp_pbo = ctx->Driver.NewBufferObject(ctx, 0xDEADBEEF);
      if (*tmp_pbo == NULL)
         return NULL;

      /* In case of GL_PIXEL_PACK_BUFFER, pass null pointer for the pixel
       * data to avoid unnecessary data copying in _mesa_buffer_data.
       */
      if (is_pixel_pack)
         _mesa_buffer_data(ctx, *tmp_pbo, GL_NONE,
                           last_pixel - first_pixel,
                           NULL,
                           GL_STREAM_READ,
                           __func__);
      else
         _mesa_buffer_data(ctx, *tmp_pbo, GL_NONE,
                           last_pixel - first_pixel,
                           (char *)pixels + first_pixel,
                           GL_STREAM_DRAW,
                           __func__);

      buffer_obj = *tmp_pbo;
      first_pixel = 0;
   }

   _mesa_GenTextures(1, tmp_tex);
   tex_obj = _mesa_lookup_texture(ctx, *tmp_tex);
   _mesa_initialize_texture_object(ctx, tex_obj, *tmp_tex, GL_TEXTURE_2D);
   /* This must be set after _mesa_initialize_texture_object, not before. */
   tex_obj->Immutable = GL_TRUE;
   /* This is required for interactions with ARB_texture_view. */
   tex_obj->NumLayers = 1;

   internal_format = _mesa_get_format_base_format(pbo_format);

   /* The texture is addressed as a single very-tall image, so we
    * need to pack the multiple image depths together taking the
    * inter-image padding into account.
    */
   int image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight;
   int full_height = image_height * (depth - 1) + height;

   tex_image = _mesa_get_tex_image(ctx, tex_obj, tex_obj->Target, 0);
   _mesa_init_teximage_fields(ctx, tex_image, width, full_height, 1,
                              0, internal_format, pbo_format);

   read_only = pbo_target == GL_PIXEL_UNPACK_BUFFER;
   if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, tex_obj,
                                                     buffer_obj,
                                                     first_pixel,
                                                     row_stride,
                                                     read_only)) {
      _mesa_DeleteTextures(1, tmp_tex);
      _mesa_reference_buffer_object(ctx, tmp_pbo, NULL);
      return NULL;
   }

   return tex_image;
}
コード例 #22
0
ファイル: fbobject.c プロジェクト: mariuz/haiku
/**
 * Common code called by glFramebufferTexture1D/2D/3DEXT().
 */
static void
framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target, 
                    GLenum attachment, GLenum textarget, GLuint texture,
                    GLint level, GLint zoffset)
{
   struct gl_renderbuffer_attachment *att;
   struct gl_texture_object *texObj = NULL;
   struct gl_framebuffer *fb;

   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (target != GL_FRAMEBUFFER_EXT) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glFramebufferTexture%sEXT(target)", caller);
      return;
   }

   fb = ctx->DrawBuffer;
   ASSERT(fb);

   /* check framebuffer binding */
   if (fb->Name == 0) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glFramebufferTexture%sEXT", caller);
      return;
   }


   /* The textarget, level, and zoffset parameters are only validated if
    * texture is non-zero.
    */
   if (texture) {
      GLboolean err = GL_TRUE;

      texObj = _mesa_lookup_texture(ctx, texture);
      if (texObj != NULL) {
         if (textarget == 0) {
            err = (texObj->Target != GL_TEXTURE_3D) &&
                (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
                (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
         }
         else {
            err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
                ? !IS_CUBE_FACE(textarget)
                : (texObj->Target != textarget);
         }
      }

      if (err) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glFramebufferTexture%sEXT(texture target mismatch)",
                     caller);
         return;
      }

      if (texObj->Target == GL_TEXTURE_3D) {
         const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
         if (zoffset < 0 || zoffset >= maxSize) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glFramebufferTexture%sEXT(zoffset)", caller);
            return;
         }
      }
      else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
               (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
         if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glFramebufferTexture%sEXT(layer)", caller);
            return;
         }
      }


      if ((level < 0) || 
          (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glFramebufferTexture%sEXT(level)", caller);
         return;
      }
   }

   att = _mesa_get_attachment(ctx, fb, attachment);
   if (att == NULL) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glFramebufferTexture%sEXT(attachment)", caller);
      return;
   }

   FLUSH_VERTICES(ctx, _NEW_BUFFERS);
   /* The above doesn't fully flush the drivers in the way that a
    * glFlush does, but that is required here:
    */
   if (ctx->Driver.Flush)
      ctx->Driver.Flush(ctx);

   _glthread_LOCK_MUTEX(fb->Mutex);
   if (texObj) {
      _mesa_set_texture_attachment(ctx, fb, att, texObj, textarget,
                                   level, zoffset);
   }
   else {
      _mesa_remove_attachment(ctx, att);
   }
   _glthread_UNLOCK_MUTEX(fb->Mutex);
}
コード例 #23
0
ファイル: textureview.c プロジェクト: ashmew2/kolibriosSVN
/**
 * glTextureView (ARB_texture_view)
 * If an error is found, record it with _mesa_error()
 * \return none.
 */
void GLAPIENTRY
_mesa_TextureView(GLuint texture, GLenum target, GLuint origtexture,
                  GLenum internalformat,
                  GLuint minlevel, GLuint numlevels,
                  GLuint minlayer, GLuint numlayers)
{
    struct gl_texture_object *texObj;
    struct gl_texture_object *origTexObj;
    struct gl_texture_image *origTexImage;
    GLuint newViewMinLevel, newViewMinLayer;
    GLuint newViewNumLevels, newViewNumLayers;
    GLsizei width, height, depth;
    mesa_format texFormat;
    GLboolean sizeOK, dimensionsOK;
    GLenum faceTarget;

    GET_CURRENT_CONTEXT(ctx);

    if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE))
        _mesa_debug(ctx, "glTextureView %d %s %d %s %d %d %d %d\n",
                    texture, _mesa_lookup_enum_by_nr(target), origtexture,
                    _mesa_lookup_enum_by_nr(internalformat),
                    minlevel, numlevels, minlayer, numlayers);

    if (origtexture == 0) {
        _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture);
        return;
    }

    /* Need original texture information to validate arguments */
    origTexObj = _mesa_lookup_texture(ctx, origtexture);

    /* If <origtexture> is not the name of a texture, INVALID_VALUE is generated. */
    if (!origTexObj) {
        _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture);
        return;
    }

    /* If <origtexture>'s TEXTURE_IMMUTABLE_FORMAT value is not TRUE,
     * INVALID_OPERATION is generated.
     */
    if (!origTexObj->Immutable) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture not immutable)");
        return;
    }

    /* If <texture> is 0, INVALID_VALUE is generated. */
    if (texture == 0) {
        _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(texture = 0)");
        return;
    }

    /* If <texture> is not a valid name returned by GenTextures,
     * the error INVALID_OPERATION is generated.
     */
    texObj = _mesa_lookup_texture(ctx, texture);
    if (texObj == NULL) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u non-gen name)", texture);
        return;
    }

    /* If <texture> has already been bound and given a target, then
     * the error INVALID_OPERATION is generated.
     */
    if (texObj->Target) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u already bound)", texture);
        return;
    }

    /* Check for compatible target */
    if (!target_valid(ctx, origTexObj->Target, target)) {
        return; /* error was recorded */
    }

    /* minlevel and minlayer are relative to the view of origtexture
     * If minlevel or minlayer is greater than level or layer, respectively,
     * of origtexture return INVALID_VALUE.
     */
    newViewMinLevel = origTexObj->MinLevel + minlevel;
    newViewMinLayer = origTexObj->MinLayer + minlayer;
    if (newViewMinLevel >= (origTexObj->MinLevel + origTexObj->NumLevels)) {
        _mesa_error(ctx, GL_INVALID_VALUE,
                    "glTextureView(new minlevel (%d) > orig minlevel (%d) + orig numlevels (%d))",
                    newViewMinLevel, origTexObj->MinLevel, origTexObj->NumLevels);
        return;
    }

    if (newViewMinLayer >= (origTexObj->MinLayer + origTexObj->NumLayers)) {
        _mesa_error(ctx, GL_INVALID_VALUE,
                    "glTextureView(new minlayer (%d) > orig minlayer (%d) + orig numlayers (%d))",
                    newViewMinLayer, origTexObj->MinLayer, origTexObj->NumLayers);
        return;
    }

    if (!_mesa_texture_view_compatible_format(ctx,
            origTexObj->Image[0][0]->InternalFormat,
            internalformat)) {
        _mesa_error(ctx, GL_INVALID_OPERATION,
                    "glTextureView(internalformat %s not compatible with origtexture %s)",
                    _mesa_lookup_enum_by_nr(internalformat),
                    _mesa_lookup_enum_by_nr(origTexObj->Image[0][0]->InternalFormat));
        return;
    }

    texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
                                            internalformat, GL_NONE, GL_NONE);
    assert(texFormat != MESA_FORMAT_NONE);
    if (texFormat == MESA_FORMAT_NONE) return;

    newViewNumLevels = MIN2(numlevels, origTexObj->NumLevels - minlevel);
    newViewNumLayers = MIN2(numlayers, origTexObj->NumLayers - minlayer);

    faceTarget = origTexObj->Target;
    if (faceTarget == GL_TEXTURE_CUBE_MAP)
        faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + minlayer;

    /* Get a reference to what will become this View's base level */
    origTexImage = _mesa_select_tex_image(origTexObj, faceTarget, minlevel);
    width = origTexImage->Width;
    height = origTexImage->Height;
    depth = origTexImage->Depth;

    /* Adjust width, height, depth to be appropriate for new target */
    switch (target) {
    case GL_TEXTURE_1D:
        height = 1;
        break;

    case GL_TEXTURE_3D:
        break;

    case GL_TEXTURE_1D_ARRAY:
        height = (GLsizei) newViewNumLayers;
        break;

    case GL_TEXTURE_2D:
    case GL_TEXTURE_2D_MULTISAMPLE:
    case GL_TEXTURE_RECTANGLE:
    case GL_TEXTURE_CUBE_MAP:
        depth = 1;
        break;

    case GL_TEXTURE_2D_ARRAY:
    case GL_TEXTURE_CUBE_MAP_ARRAY:
    case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
        depth = newViewNumLayers;
        break;
    }

    /* If the dimensions of the original texture are larger than the maximum
     * supported dimensions of the new target, the error INVALID_OPERATION is
     * generated. For example, if the original texture has a TEXTURE_2D_ARRAY
     * target and its width is greater than MAX_CUBE_MAP_TEXTURE_SIZE, an error
     * will be generated if TextureView is called to create a TEXTURE_CUBE_MAP
     * view.
     */
    dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
                   width, height, depth, 0);
    if (!dimensionsOK) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid width or height or depth)");
        return;
    }

    sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat,
                                           width, height, depth, 0);
    if (!sizeOK) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid texture size)");
        return;
    }

    /* If <target> is TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_RECTANGLE,
     * or TEXTURE_2D_MULTISAMPLE and <numlayers> does not equal 1, the error
     * INVALID_VALUE is generated.
     */
    switch (target) {
    case GL_TEXTURE_1D:
    case GL_TEXTURE_2D:
    case GL_TEXTURE_3D:
    case GL_TEXTURE_RECTANGLE:
    case GL_TEXTURE_2D_MULTISAMPLE:
        if (numlayers != 1) {
            _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(numlayers %d != 1)", numlayers);
            return;
        }
        break;

    case GL_TEXTURE_CUBE_MAP:
        /* If the new texture's target is TEXTURE_CUBE_MAP, the clamped <numlayers>
         * must be equal to 6.
         */
        if (newViewNumLayers != 6) {
            _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(clamped numlayers %d != 6)",
                        newViewNumLayers);
            return;
        }
        break;

    case GL_TEXTURE_CUBE_MAP_ARRAY:
        /* If the new texture's target is TEXTURE_CUBE_MAP_ARRAY,
         * then <numlayers> counts layer-faces rather than layers,
         * and the clamped <numlayers> must be a multiple of 6.
         * Otherwise, the error INVALID_VALUE is generated.
         */
        if ((newViewNumLayers % 6) != 0) {
            _mesa_error(ctx, GL_INVALID_VALUE,
                        "glTextureView(clamped numlayers %d is not a multiple of 6)",
                        newViewNumLayers);
            return;
        }
        break;
    }

    /* If the new texture's target is TEXTURE_CUBE_MAP or
     * TEXTURE_CUBE_MAP_ARRAY, the width and height of the original texture's
     * levels must be equal otherwise the error INVALID_OPERATION is generated.
     */
    if ((target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY) &&
            (origTexImage->Width != origTexImage->Height)) {
        _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture width (%d) != height (%d))",
                    origTexImage->Width, origTexImage->Height);
        return;
    }

    /* When the original texture's target is TEXTURE_CUBE_MAP, the layer
     * parameters are interpreted in the same order as if it were a
     * TEXTURE_CUBE_MAP_ARRAY with 6 layer-faces.
     */

    /* If the internal format does not exactly match the internal format of the
     * original texture, the contents of the memory are reinterpreted in the
     * same manner as for image bindings described in
     * section 3.9.20 (Texture Image Loads and Stores).
     */

    /* TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are interpreted
     * relative to the view and not relative to the original data store.
     */

    if (!initialize_texture_fields(ctx, target, texObj, newViewNumLevels,
                                   width, height, depth,
                                   internalformat, texFormat)) {
        return; /* Already recorded error */
    }

    texObj->MinLevel = newViewMinLevel;
    texObj->MinLayer = newViewMinLayer;
    texObj->NumLevels = newViewNumLevels;
    texObj->NumLayers = newViewNumLayers;
    texObj->Immutable = GL_TRUE;
    texObj->ImmutableLevels = origTexObj->ImmutableLevels;
    texObj->Target = target;

    if (ctx->Driver.TextureView != NULL && !ctx->Driver.TextureView(ctx, texObj, origTexObj)) {
        return; /* driver recorded error */
    }
}
コード例 #24
0
ファイル: copyimage.c プロジェクト: elgambitero/Mesa-3D
/**
 * Prepare the source or destination resource.  This involves error
 * checking and returning the relevant gl_texture_image or gl_renderbuffer.
 * Note that one of the resulting tex_image or renderbuffer pointers will be
 * NULL and the other will be non-null.
 *
 * \param name  the texture or renderbuffer name
 * \param target  One of GL_TEXTURE_x target or GL_RENDERBUFFER
 * \param level  mipmap level
 * \param z  src or dest Z
 * \param depth  number of slices/faces/layers to copy
 * \param tex_image  returns a pointer to a texture image
 * \param renderbuffer  returns a pointer to a renderbuffer
 * \return true if success, false if error
 */
static bool
prepare_target(struct gl_context *ctx, GLuint name, GLenum target,
               int level, int z, int depth,
               struct gl_texture_image **tex_image,
               struct gl_renderbuffer **renderbuffer,
               mesa_format *format,
               GLenum *internalFormat,
               GLuint *width,
               GLuint *height,
               GLuint *num_samples,
               const char *dbg_prefix)
{
   if (name == 0) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glCopyImageSubData(%sName = %d)", dbg_prefix, name);
      return false;
   }

   /*
    * INVALID_ENUM is generated
    *  * if either <srcTarget> or <dstTarget>
    *   - is not RENDERBUFFER or a valid non-proxy texture target
    *   - is TEXTURE_BUFFER, or
    *   - is one of the cubemap face selectors described in table 3.17,
    */
   switch (target) {
   case GL_RENDERBUFFER:
      /* Not a texture target, but valid */
   case GL_TEXTURE_1D:
   case GL_TEXTURE_1D_ARRAY:
   case GL_TEXTURE_2D:
   case GL_TEXTURE_3D:
   case GL_TEXTURE_CUBE_MAP:
   case GL_TEXTURE_RECTANGLE:
   case GL_TEXTURE_2D_ARRAY:
   case GL_TEXTURE_CUBE_MAP_ARRAY:
   case GL_TEXTURE_2D_MULTISAMPLE:
   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
      /* These are all valid */
      break;
   case GL_TEXTURE_EXTERNAL_OES:
      /* Only exists in ES */
   case GL_TEXTURE_BUFFER:
   default:
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
                  _mesa_enum_to_string(target));
      return false;
   }

   if (target == GL_RENDERBUFFER) {
      struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);

      if (!rb) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
         return false;
      }

      if (!rb->Name) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glCopyImageSubData(%sName incomplete)", dbg_prefix);
         return false;
      }

      if (level != 0) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
         return false;
      }

      *renderbuffer = rb;
      *format = rb->Format;
      *internalFormat = rb->InternalFormat;
      *width = rb->Width;
      *height = rb->Height;
      *num_samples = rb->NumSamples;
      *tex_image = NULL;
   } else {
      struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);

      if (!texObj) {
         /*
          * From GL_ARB_copy_image specification:
          * "INVALID_VALUE is generated if either <srcName> or <dstName> does
          * not correspond to a valid renderbuffer or texture object according
          * to the corresponding target parameter."
          */
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sName = %u)", dbg_prefix, name);
         return false;
      }

      _mesa_test_texobj_completeness(ctx, texObj);
      if (!texObj->_BaseComplete ||
          (level != 0 && !texObj->_MipmapComplete)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glCopyImageSubData(%sName incomplete)", dbg_prefix);
         return false;
      }

      /* Note that target will not be a cube face name */
      if (texObj->Target != target) {
         /*
          * From GL_ARB_copy_image_specification:
          * "INVALID_ENUM is generated if the target does not match the type
          * of the object."
          */
         _mesa_error(ctx, GL_INVALID_ENUM,
                     "glCopyImageSubData(%sTarget = %s)", dbg_prefix,
                     _mesa_enum_to_string(target));
         return false;
      }

      if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level);
         return false;
      }

      if (target == GL_TEXTURE_CUBE_MAP) {
         int i;

         assert(z < MAX_FACES);  /* should have been caught earlier */

         /* make sure all the cube faces are present */
         for (i = 0; i < depth; i++) {
            if (!texObj->Image[z+i][level]) {
               /* missing cube face */
               _mesa_error(ctx, GL_INVALID_VALUE,
                           "glCopyImageSubData(missing cube face)");
               return false;
            }
         }

         *tex_image = texObj->Image[z][level];
      }
      else {
         *tex_image = _mesa_select_tex_image(texObj, target, level);
      }

      if (!*tex_image) {
         _mesa_error(ctx, GL_INVALID_VALUE,
                     "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level);
         return false;
      }

      *renderbuffer = NULL;
      *format = (*tex_image)->TexFormat;
      *internalFormat = (*tex_image)->InternalFormat;
      *width = (*tex_image)->Width;
      *height = (*tex_image)->Height;
      *num_samples = (*tex_image)->NumSamples;
   }

   return true;
}