Esempio n. 1
0
void
intelCopyTexSubImage2D(GLcontext * ctx, GLenum target, GLint level,
                       GLint xoffset, GLint yoffset,
                       GLint x, GLint y, GLsizei width, GLsizei height)
{
   struct gl_texture_unit *texUnit =
      &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   struct gl_texture_object *texObj =
      _mesa_select_tex_object(ctx, texUnit, target);
   struct gl_texture_image *texImage =
      _mesa_select_tex_image(ctx, texObj, target, level);
   GLenum internalFormat = texImage->InternalFormat;


   /* Need to check texture is compatible with source format. 
    */

   if (!do_copy_texsubimage(intel_context(ctx),
                            intel_texture_image(texImage),
                            internalFormat,
                            xoffset, yoffset, x, y, width, height)) {

      DBG("%s - fallback to swrast\n", __FUNCTION__);

      _swrast_copy_texsubimage2d(ctx, target, level,
                                 xoffset, yoffset, x, y, width, height);
   }
}
Esempio n. 2
0
void
intelCopyTexImage1D(GLcontext * ctx, GLenum target, GLint level,
                    GLenum internalFormat,
                    GLint x, GLint y, GLsizei width, GLint border)
{
   struct gl_texture_unit *texUnit =
      &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   struct gl_texture_object *texObj =
      _mesa_select_tex_object(ctx, texUnit, target);
   struct gl_texture_image *texImage =
      _mesa_select_tex_image(ctx, texObj, target, level);

   if (border)
      goto fail;

   /* Setup or redefine the texture object, mipmap tree and texture
    * image.  Don't populate yet.  
    */
   ctx->Driver.TexImage1D(ctx, target, level, internalFormat,
                          width, border,
                          GL_RGBA, CHAN_TYPE, NULL,
                          &ctx->DefaultPacking, texObj, texImage);

   if (!do_copy_texsubimage(intel_context(ctx),
                            intel_texture_image(texImage),
                            internalFormat, 0, 0, x, y, width, 1))
      goto fail;

   return;

 fail:
   _swrast_copy_teximage1d(ctx, target, level, internalFormat, x, y,
                           width, border);
}
Esempio n. 3
0
void GLAPIENTRY
_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);

   if (getcompressedteximage_error_check(ctx, target, level, img)) {
      return;
   }

   if (_mesa_is_bufferobj(ctx->Pack.BufferObj) && !img) {
      /* not an error, do nothing */
      return;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);

   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
      _mesa_debug(ctx,
                  "glGetCompressedTexImage(tex %u) format = %s, w=%d, h=%d\n",
                  texObj->Name,
                  _mesa_get_format_name(texImage->TexFormat),
                  texImage->Width, texImage->Height);
   }

   _mesa_lock_texture(ctx, texObj);
   {
      ctx->Driver.GetCompressedTexImage(ctx, target, level, img,
                                        texObj, texImage);
   }
   _mesa_unlock_texture(ctx, texObj);
}
Esempio n. 4
0
/**
 * Helper function for TexStorage and teximagemultisample to set immutable
 * texture state needed by ARB_texture_view.
 */
void
_mesa_set_texture_view_state(struct gl_context *ctx,
                             struct gl_texture_object *texObj,
                             GLenum target, GLuint levels)
{
   struct gl_texture_image *texImage;

   /* Get a reference to what will become this View's base level */
   texImage = _mesa_select_tex_image(texObj, target, 0);

   /* When an immutable texture is created via glTexStorage or
    * glTexImageMultisample,
    * TEXTURE_IMMUTABLE_FORMAT becomes TRUE.
    * TEXTURE_IMMUTABLE_LEVELS and TEXTURE_VIEW_NUM_LEVELS become levels.
    * If the texture target is TEXTURE_1D_ARRAY then
    * TEXTURE_VIEW_NUM_LAYERS becomes height.
    * If the texture target is TEXTURE_2D_ARRAY, TEXTURE_CUBE_MAP_ARRAY,
    * or TEXTURE_2D_MULTISAMPLE_ARRAY then TEXTURE_VIEW_NUM_LAYERS becomes
    * depth.
    * If the texture target is TEXTURE_CUBE_MAP, then
    * TEXTURE_VIEW_NUM_LAYERS becomes 6.
    * For any other texture target, TEXTURE_VIEW_NUM_LAYERS becomes 1.
    *
    * ARB_texture_multisample: Multisample textures do
    * not have multiple image levels.
    */

   texObj->Immutable = GL_TRUE;
   texObj->ImmutableLevels = levels;
   texObj->MinLevel = 0;
   texObj->NumLevels = levels;
   texObj->MinLayer = 0;
   texObj->NumLayers = 1;
   switch (target) {
   case GL_TEXTURE_1D_ARRAY:
      texObj->NumLayers = texImage->Height;
      break;

   case GL_TEXTURE_2D_MULTISAMPLE:
      texObj->NumLevels = 1;
      texObj->ImmutableLevels = 1;
      break;

   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
      texObj->NumLevels = 1;
      texObj->ImmutableLevels = 1;
      /* fall through to set NumLayers */

   case GL_TEXTURE_2D_ARRAY:
   case GL_TEXTURE_CUBE_MAP_ARRAY:
      texObj->NumLayers = texImage->Depth;
      break;

   case GL_TEXTURE_CUBE_MAP:
      texObj->NumLayers = 6;
      break;
   }
}
Esempio n. 5
0
/**
 * Get compressed texture image.
 *
 * \param texture texture name.
 * \param level image level.
 * \param bufSize size of the pixels data buffer.
 * \param pixels returned pixel data.
 */
void glGetCompressedTextureImage(GLuint texture, GLint level,
                                GLsizei bufSize, GLvoid *pixels)
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   int i;
   GLint image_stride;
   GET_CURRENT_CONTEXT(ctx);

   texObj = _mesa_lookup_texture_err(ctx, texture,
                                     "glGetCompressedTextureImage");
   if (!texObj)
      return;

   /* Must handle special case GL_TEXTURE_CUBE_MAP. */
   if (texObj->Target == GL_TEXTURE_CUBE_MAP) {

      /* Make sure the texture object is a proper cube.
       * (See texturesubimage in teximage.c for details on why this check is
       * performed.)
       */
      if (!_mesa_cube_level_complete(texObj, level)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetCompressedTextureImage(cube map incomplete)");
         return;
      }

      /* Copy each face. */
      for (i = 0; i < 6; ++i) {
         texImage = texObj->Image[i][level];
         assert(texImage);

         _mesa_get_compressed_texture_image(ctx, texObj, texImage,
                                            texObj->Target, level,
                                            bufSize, pixels, true);

         /* Compressed images don't have a client format */
         image_stride = _mesa_format_image_size(texImage->TexFormat,
                                                texImage->Width,
                                                texImage->Height, 1);

         pixels = (GLubyte *) pixels + image_stride;
         bufSize -= image_stride;
      }
   }
   else {
      texImage = _mesa_select_tex_image(texObj, texObj->Target, level);
      if (!texImage)
         return;

      _mesa_get_compressed_texture_image(ctx, texObj, texImage,
                                         texObj->Target, level, bufSize,
                                         pixels, true);
   }
}
Esempio n. 6
0
void
radeonCopyTexImage2D(GLcontext *ctx, GLenum target, GLint level,
                     GLenum internalFormat,
                     GLint x, GLint y, GLsizei width, GLsizei height,
                     GLint border)
{
    struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
    struct gl_texture_object *texObj =
        _mesa_select_tex_object(ctx, texUnit, target);
    struct gl_texture_image *texImage =
        _mesa_select_tex_image(ctx, texObj, target, level);
    int srcx, srcy, dstx, dsty;

    radeonContextPtr radeon = RADEON_CONTEXT(ctx);
    radeon_prepare_render(radeon);

    if (border)
        goto fail;

    /* Setup or redefine the texture object, mipmap tree and texture
     * image.  Don't populate yet.
     */
    ctx->Driver.TexImage2D(ctx, target, level, internalFormat,
                           width, height, border,
                           GL_RGBA, GL_UNSIGNED_BYTE, NULL,
                           &ctx->DefaultPacking, texObj, texImage);

    srcx = x;
    srcy = y;
    dstx = 0;
    dsty = 0;
    if (!_mesa_clip_copytexsubimage(ctx,
                                    &dstx, &dsty,
                                    &srcx, &srcy,
                                    &width, &height)) {
        return;
    }

    if (!do_copy_texsubimage(ctx, target, level,
                             radeon_tex_obj(texObj), (radeon_texture_image *)texImage,
                             0, 0, x, y, width, height)) {
        goto fail;
    }

    return;

fail:
    radeon_print(RADEON_FALLBACKS, RADEON_NORMAL,
                 "Falling back to sw for glCopyTexImage2D (internalFormat %s, border %d)\n",
                 _mesa_lookup_enum_by_nr(internalFormat), border);

    _mesa_meta_CopyTexImage2D(ctx, target, level, internalFormat, x, y,
                              width, height, border);
}
/**
 * Try to do a glBlitFramebuffer using glCopyTexSubImage2D
 * We can do this when the dst renderbuffer is actually a texture and
 * there is no scaling, mirroring or scissoring.
 *
 * \return new buffer mask indicating the buffers left to blit using the
 *         normal path.
 */
static GLbitfield
intel_blit_framebuffer_copy_tex_sub_image(struct gl_context *ctx,
                                          GLint srcX0, GLint srcY0,
                                          GLint srcX1, GLint srcY1,
                                          GLint dstX0, GLint dstY0,
                                          GLint dstX1, GLint dstY1,
                                          GLbitfield mask, GLenum filter)
{
   if (mask & GL_COLOR_BUFFER_BIT) {
      const struct gl_framebuffer *drawFb = ctx->DrawBuffer;
      const struct gl_framebuffer *readFb = ctx->ReadBuffer;
      const struct gl_renderbuffer_attachment *drawAtt =
         &drawFb->Attachment[drawFb->_ColorDrawBufferIndexes[0]];
      struct intel_renderbuffer *srcRb = 
         intel_renderbuffer(readFb->_ColorReadBuffer);

      /* If the source and destination are the same size with no
         mirroring, the rectangles are within the size of the
         texture and there is no scissor then we can use
         glCopyTexSubimage2D to implement the blit. This will end
         up as a fast hardware blit on some drivers */
      if (srcRb && drawAtt && drawAtt->Texture &&
          srcX0 - srcX1 == dstX0 - dstX1 &&
          srcY0 - srcY1 == dstY0 - dstY1 &&
          srcX1 >= srcX0 &&
          srcY1 >= srcY0 &&
          srcX0 >= 0 && srcX1 <= readFb->Width &&
          srcY0 >= 0 && srcY1 <= readFb->Height &&
          dstX0 >= 0 && dstX1 <= drawFb->Width &&
          dstY0 >= 0 && dstY1 <= drawFb->Height &&
          !ctx->Scissor.Enabled) {
         const struct gl_texture_object *texObj = drawAtt->Texture;
         const GLuint dstLevel = drawAtt->TextureLevel;
         const GLenum target = texObj->Target;

         struct gl_texture_image *texImage =
            _mesa_select_tex_image(ctx, texObj, target, dstLevel);

         if (intel_copy_texsubimage(intel_context(ctx),
                                    intel_texture_image(texImage),
                                    dstX0, dstY0,
                                    srcRb,
                                    srcX0, srcY0,
                                    srcX1 - srcX0, /* width */
                                    srcY1 - srcY0))
            mask &= ~GL_COLOR_BUFFER_BIT;
      }
   }

   return mask;
}
Esempio n. 8
0
void GLAPIENTRY
_mesa_VDPAUUnmapSurfacesNV(GLsizei numSurfaces, const GLintptr *surfaces)
{
   GET_CURRENT_CONTEXT(ctx);
   int i;

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

   for (i = 0; i < numSurfaces; ++i) {
      struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];

      if (!_mesa_set_search(ctx->vdpSurfaces, surf)) {
         _mesa_error(ctx, GL_INVALID_VALUE, "VDPAUSurfaceAccessNV");
         return;
      }

      if (surf->state != GL_SURFACE_MAPPED_NV) {
         _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUSurfaceAccessNV");
         return;
      }
   }

   for (i = 0; i < numSurfaces; ++i) {
      struct vdp_surface *surf = (struct vdp_surface *)surfaces[i];
      unsigned numTextureNames = surf->output ? 1 : 4;
      unsigned j;

      for (j = 0; j < numTextureNames; ++j) {
         struct gl_texture_object *tex = surf->textures[j];
         struct gl_texture_image *image;

         _mesa_lock_texture(ctx, tex);

         image = _mesa_select_tex_image(tex, surf->target, 0);

         ctx->Driver.VDPAUUnmapSurface(ctx, surf->target, surf->access,
                                       surf->output, tex, image,
                                       surf->vdpSurface, j);

         if (image)
            ctx->Driver.FreeTextureImageBuffer(ctx, image);

         _mesa_unlock_texture(ctx, tex);
      }
      surf->state = GL_SURFACE_REGISTERED_NV;
   }
}
Esempio n. 9
0
void glGetnCompressedTexImageARB(GLenum target, GLint level, GLsizei bufSize,
                                GLvoid *img)
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   GET_CURRENT_CONTEXT(ctx);

   texObj = _mesa_get_current_tex_object(ctx, target);
   if (!texObj)
      return;

   texImage = _mesa_select_tex_image(texObj, target, level);
   if (!texImage)
      return;

   _mesa_get_compressed_texture_image(ctx, texObj, texImage, target, level,
                                      bufSize, img, false);
}
Esempio n. 10
0
/**
 * Get texture image.  Called by glGetTexImage.
 *
 * \param target texture target.
 * \param level image level.
 * \param format pixel data format for returned image.
 * \param type pixel data type for returned image.
 * \param bufSize size of the pixels data buffer.
 * \param pixels returned pixel data.
 */
void GLAPIENTRY
_mesa_GetnTexImageARB( GLenum target, GLint level, GLenum format,
                       GLenum type, GLsizei bufSize, GLvoid *pixels )
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   GET_CURRENT_CONTEXT(ctx);

   FLUSH_VERTICES(ctx, 0);

   if (getteximage_error_check(ctx, target, level, format, type,
                               bufSize, pixels)) {
      return;
   }

   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj) && !pixels) {
      /* not an error, do nothing */
      return;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   texImage = _mesa_select_tex_image(ctx, texObj, target, level);

   if (_mesa_is_zero_size_texture(texImage))
      return;

   if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {
      _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d, h=%d,"
                  " dstFmt=0x%x, dstType=0x%x\n",
                  texObj->Name,
                  _mesa_get_format_name(texImage->TexFormat),
                  texImage->Width, texImage->Height,
                  format, type);
   }

   _mesa_lock_texture(ctx, texObj);
   {
      ctx->Driver.GetTexImage(ctx, format, type, pixels, texImage);
   }
   _mesa_unlock_texture(ctx, texObj);
}
Esempio n. 11
0
/**
 * Get texture image.  Called by glGetTexImage.
 *
 * \param target texture target.
 * \param level image level.
 * \param format pixel data format for returned image.
 * \param type pixel data type for returned image.
 * \param bufSize size of the pixels data buffer.
 * \param pixels returned pixel data.
 */
void glGetnTexImageARB(GLenum target, GLint level, GLenum format,
                      GLenum type, GLsizei bufSize, GLvoid *pixels)
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   GLenum err;
   GET_CURRENT_CONTEXT(ctx);

   /*
    * This has been moved here because a format/type mismatch can cause a NULL
    * texImage object, which in turn causes the mismatch error to be
    * ignored.
    */
   err = _mesa_error_check_format_and_type(ctx, format, type);
   if (err != GL_NO_ERROR) {
      _mesa_error(ctx, err, "glGetnTexImage(format/type)");
      return;
   }

   /*
    * Legal target checking has been moved here to prevent exiting with a NULL
    * texImage object.
    */
   if (!legal_getteximage_target(ctx, target, false)) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetnTexImage(target=0x%x)",
                  target);
      return;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   if (!texObj)
      return;

   texImage = _mesa_select_tex_image(texObj, target, level);
   if (!texImage)
      return;

   _mesa_get_texture_image(ctx, texObj, texImage, target, level, format, type,
                           bufSize, pixels, false);
}
Esempio n. 12
0
static void
intelCopyTexSubImage2D(struct gl_context * ctx, GLenum target, GLint level,
                       GLint xoffset, GLint yoffset,
                       GLint x, GLint y, GLsizei width, GLsizei height)
{
   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
   struct gl_texture_object *texObj =
      _mesa_select_tex_object(ctx, texUnit, target);
   struct gl_texture_image *texImage =
      _mesa_select_tex_image(ctx, texObj, target, level);

   /* Need to check texture is compatible with source format. 
    */

   if (!intel_copy_texsubimage(intel_context(ctx),
                               intel_texture_image(texImage),
                               xoffset, yoffset, x, y, width, height)) {
      fallback_debug("%s - fallback to swrast\n", __FUNCTION__);
      _mesa_meta_CopyTexSubImage2D(ctx, target, level,
                                   xoffset, yoffset, x, y, width, height);
   }
}
Esempio n. 13
0
void
intelCopyTexSubImage1D(GLcontext * ctx, GLenum target, GLint level,
                       GLint xoffset, GLint x, GLint y, GLsizei width)
{
   struct gl_texture_unit *texUnit =
      &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
   struct gl_texture_object *texObj =
      _mesa_select_tex_object(ctx, texUnit, target);
   struct gl_texture_image *texImage =
      _mesa_select_tex_image(ctx, texObj, target, level);
   GLenum internalFormat = texImage->InternalFormat;

   /* XXX need to check <border> as in above function? */

   /* Need to check texture is compatible with source format. 
    */

   if (!do_copy_texsubimage(intel_context(ctx),
                            intel_texture_image(texImage),
                            internalFormat, xoffset, 0, x, y, width, 1)) {
      _swrast_copy_texsubimage1d(ctx, target, level, xoffset, x, y, width);
   }
}
Esempio n. 14
0
void
radeonCopyTexSubImage2D(GLcontext *ctx, GLenum target, GLint level,
                        GLint xoffset, GLint yoffset,
                        GLint x, GLint y,
                        GLsizei width, GLsizei height)
{
    struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
    struct gl_texture_object *texObj = _mesa_select_tex_object(ctx, texUnit, target);
    struct gl_texture_image *texImage = _mesa_select_tex_image(ctx, texObj, target, level);

    radeonContextPtr radeon = RADEON_CONTEXT(ctx);
    radeon_prepare_render(radeon);

    if (!do_copy_texsubimage(ctx, target, level,
                             radeon_tex_obj(texObj), (radeon_texture_image *)texImage,
                             xoffset, yoffset, x, y, width, height)) {

        radeon_print(RADEON_FALLBACKS, RADEON_NORMAL,
                     "Falling back to sw for glCopyTexSubImage2D\n");

        _mesa_meta_CopyTexSubImage2D(ctx, target, level,
                                     xoffset, yoffset, x, y, width, height);
    }
}
Esempio n. 15
0
void GLAPIENTRY
_mesa_GetTexLevelParameteriv( GLenum target, GLint level,
                              GLenum pname, GLint *params )
{
   const struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   const struct gl_texture_image *img = NULL;
   GLuint dimensions;
   GLboolean isProxy;
   GLint maxLevels;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxTextureImageUnits) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGetTexLevelParameteriv(current unit)");
      return;
   }

   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];

   /* this will catch bad target values */
   dimensions = tex_image_dimensions(ctx, target);  /* 1, 2 or 3 */
   if (dimensions == 0) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexLevelParameter[if]v(target)");
      return;
   }

   maxLevels = _mesa_max_texture_levels(ctx, target);
   if (maxLevels == 0) {
      /* should not happen since <target> was just checked above */
      _mesa_problem(ctx, "maxLevels=0 in _mesa_GetTexLevelParameter");
      return;
   }

   if (level < 0 || level >= maxLevels) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameter[if]v" );
      return;
   }

   texObj = _mesa_select_tex_object(ctx, texUnit, target);
   _mesa_lock_texture(ctx, texObj);

   img = _mesa_select_tex_image(ctx, texObj, target, level);
   if (!img || !img->TexFormat) {
      /* undefined texture image */
      if (pname == GL_TEXTURE_COMPONENTS)
         *params = 1;
      else
         *params = 0;
      goto out;
   }

   isProxy = _mesa_is_proxy_texture(target);

   switch (pname) {
      case GL_TEXTURE_WIDTH:
         *params = img->Width;
         break;
      case GL_TEXTURE_HEIGHT:
         *params = img->Height;
         break;
      case GL_TEXTURE_DEPTH:
         *params = img->Depth;
         break;
      case GL_TEXTURE_INTERNAL_FORMAT:
         *params = img->InternalFormat;
         break;
      case GL_TEXTURE_BORDER:
         *params = img->Border;
         break;
      case GL_TEXTURE_RED_SIZE:
         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
            *params = img->TexFormat->RedBits;
         else
            *params = 0;
         break;
      case GL_TEXTURE_GREEN_SIZE:
         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
            *params = img->TexFormat->GreenBits;
         else
            *params = 0;
         break;
      case GL_TEXTURE_BLUE_SIZE:
         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
            *params = img->TexFormat->BlueBits;
         else
            *params = 0;
         break;
      case GL_TEXTURE_ALPHA_SIZE:
         if (img->_BaseFormat == GL_ALPHA ||
             img->_BaseFormat == GL_LUMINANCE_ALPHA ||
             img->_BaseFormat == GL_RGBA)
            *params = img->TexFormat->AlphaBits;
         else
            *params = 0;
         break;
      case GL_TEXTURE_INTENSITY_SIZE:
         if (img->_BaseFormat != GL_INTENSITY)
            *params = 0;
         else if (img->TexFormat->IntensityBits > 0)
            *params = img->TexFormat->IntensityBits;
         else /* intensity probably stored as rgb texture */
            *params = MIN2(img->TexFormat->RedBits, img->TexFormat->GreenBits);
         break;
      case GL_TEXTURE_LUMINANCE_SIZE:
         if (img->_BaseFormat != GL_LUMINANCE &&
             img->_BaseFormat != GL_LUMINANCE_ALPHA)
            *params = 0;
         else if (img->TexFormat->LuminanceBits > 0)
            *params = img->TexFormat->LuminanceBits;
         else /* luminance probably stored as rgb texture */
            *params = MIN2(img->TexFormat->RedBits, img->TexFormat->GreenBits);
         break;
      case GL_TEXTURE_INDEX_SIZE_EXT:
         if (img->_BaseFormat == GL_COLOR_INDEX)
            *params = img->TexFormat->IndexBits;
         else
            *params = 0;
         break;
      case GL_TEXTURE_DEPTH_SIZE_ARB:
         if (ctx->Extensions.ARB_depth_texture)
            *params = img->TexFormat->DepthBits;
         else
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         break;
      case GL_TEXTURE_STENCIL_SIZE_EXT:
         if (ctx->Extensions.EXT_packed_depth_stencil) {
            *params = img->TexFormat->StencilBits;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;

      /* GL_ARB_texture_compression */
      case GL_TEXTURE_COMPRESSED_IMAGE_SIZE:
         if (ctx->Extensions.ARB_texture_compression) {
            if (img->IsCompressed && !isProxy) {
               /* Don't use ctx->Driver.CompressedTextureSize() since that
                * may returned a padded hardware size.
                */
               *params = _mesa_compressed_texture_size(ctx, img->Width,
                                                   img->Height, img->Depth,
                                                   img->TexFormat->MesaFormat);
            }
            else {
               _mesa_error(ctx, GL_INVALID_OPERATION,
                           "glGetTexLevelParameter[if]v(pname)");
            }
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;
      case GL_TEXTURE_COMPRESSED:
         if (ctx->Extensions.ARB_texture_compression) {
            *params = (GLint) img->IsCompressed;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;

      /* GL_ARB_texture_float */
      case GL_TEXTURE_RED_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = img->TexFormat->RedBits ? img->TexFormat->DataType : GL_NONE;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;
      case GL_TEXTURE_GREEN_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = img->TexFormat->GreenBits ? img->TexFormat->DataType : GL_NONE;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;
      case GL_TEXTURE_BLUE_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = img->TexFormat->BlueBits ? img->TexFormat->DataType : GL_NONE;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;
      case GL_TEXTURE_ALPHA_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = img->TexFormat->AlphaBits ? img->TexFormat->DataType : GL_NONE;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;
      case GL_TEXTURE_LUMINANCE_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = img->TexFormat->LuminanceBits ? img->TexFormat->DataType : GL_NONE;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;
      case GL_TEXTURE_INTENSITY_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = img->TexFormat->IntensityBits ? img->TexFormat->DataType : GL_NONE;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;
      case GL_TEXTURE_DEPTH_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = img->TexFormat->DepthBits ? img->TexFormat->DataType : GL_NONE;
         }
         else {
            _mesa_error(ctx, GL_INVALID_ENUM,
                        "glGetTexLevelParameter[if]v(pname)");
         }
         break;

      default:
         _mesa_error(ctx, GL_INVALID_ENUM,
                     "glGetTexLevelParameter[if]v(pname)");
   }

 out:
   _mesa_unlock_texture(ctx, texObj);
}
Esempio n. 16
0
void GLAPIENTRY
_mesa_GetTexLevelParameteriv( GLenum target, GLint level,
                              GLenum pname, GLint *params )
{
   struct gl_texture_object *texObj;
   const struct gl_texture_image *img = NULL;
   GLint maxLevels;
   gl_format texFormat;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   /* this will catch bad target values */
   maxLevels = _mesa_max_texture_levels(ctx, target);
   if (maxLevels == 0) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glGetTexLevelParameter[if]v(target=0x%x)", target);
      return;
   }

   if (level < 0 || level >= maxLevels) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameter[if]v" );
      return;
   }

   texObj = _mesa_select_tex_object(ctx, target);

   img = _mesa_select_tex_image(ctx, texObj, target, level);
   if (!img || img->TexFormat == MESA_FORMAT_NONE) {
      /* undefined texture image */
      if (pname == GL_TEXTURE_COMPONENTS)
         *params = 1;
      else
         *params = 0;
      return;
   }

   texFormat = img->TexFormat;

   switch (pname) {
      case GL_TEXTURE_WIDTH:
         *params = img->Width;
         break;
      case GL_TEXTURE_HEIGHT:
         *params = img->Height;
         break;
      case GL_TEXTURE_DEPTH:
         *params = img->Depth;
         break;
      case GL_TEXTURE_INTERNAL_FORMAT:
         *params = img->InternalFormat;
         break;
      case GL_TEXTURE_BORDER:
         *params = img->Border;
         break;
      case GL_TEXTURE_RED_SIZE:
      case GL_TEXTURE_GREEN_SIZE:
      case GL_TEXTURE_BLUE_SIZE:
      case GL_TEXTURE_ALPHA_SIZE:
         if (_mesa_base_format_has_channel(img->_BaseFormat, pname))
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_INTENSITY_SIZE:
      case GL_TEXTURE_LUMINANCE_SIZE:
         if (_mesa_base_format_has_channel(img->_BaseFormat, pname)) {
            *params = _mesa_get_format_bits(texFormat, pname);
            if (*params == 0) {
               /* intensity or luminance is probably stored as RGB[A] */
               *params = MIN2(_mesa_get_format_bits(texFormat,
                                                    GL_TEXTURE_RED_SIZE),
                              _mesa_get_format_bits(texFormat,
                                                    GL_TEXTURE_GREEN_SIZE));
            }
         }
         else {
            *params = 0;
         }
         break;

      /* GL_ARB_texture_float */
      case GL_TEXTURE_RED_TYPE_ARB:
      case GL_TEXTURE_GREEN_TYPE_ARB:
      case GL_TEXTURE_BLUE_TYPE_ARB:
      case GL_TEXTURE_ALPHA_TYPE_ARB:
      case GL_TEXTURE_LUMINANCE_TYPE_ARB:
      case GL_TEXTURE_INTENSITY_TYPE_ARB:
      case GL_TEXTURE_DEPTH_TYPE_ARB:
         if (!ctx->Extensions.ARB_texture_float)
            goto invalid_pname;
	 if (_mesa_base_format_has_channel(img->_BaseFormat, pname))
	    *params = _mesa_get_format_datatype(texFormat);
	 else
	    *params = GL_NONE;
         break;

      default:
         goto invalid_pname;
   }

   /* no error if we get here */
   return;

invalid_pname:
   _mesa_error(ctx, GL_INVALID_ENUM,
               "glGetTexLevelParameter[if]v(pname=%s)",
               _mesa_lookup_enum_by_nr(pname));
}
Esempio n. 17
0
void GLAPIENTRY
_mesa_GetTexLevelParameteriv( GLenum target, GLint level,
                              GLenum pname, GLint *params )
{
   const struct gl_texture_unit *texUnit;
   struct gl_texture_object *texObj;
   const struct gl_texture_image *img = NULL;
   GLint maxLevels;
   gl_format texFormat;
   GET_CURRENT_CONTEXT(ctx);
   ASSERT_OUTSIDE_BEGIN_END(ctx);

   if (ctx->Texture.CurrentUnit >= ctx->Const.MaxCombinedTextureImageUnits) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGetTexLevelParameteriv(current unit)");
      return;
   }

   texUnit = _mesa_get_current_tex_unit(ctx);

   /* this will catch bad target values */
   maxLevels = _mesa_max_texture_levels(ctx, target);
   if (maxLevels == 0) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glGetTexLevelParameter[if]v(target=0x%x)", target);
      return;
   }

   if (level < 0 || level >= maxLevels) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexLevelParameter[if]v" );
      return;
   }

   texObj = _mesa_select_tex_object(ctx, texUnit, target);

   img = _mesa_select_tex_image(ctx, texObj, target, level);
   if (!img || !img->TexFormat) {
      /* undefined texture image */
      if (pname == GL_TEXTURE_COMPONENTS)
         *params = 1;
      else
         *params = 0;
      return;
   }

   texFormat = img->TexFormat;

   switch (pname) {
      case GL_TEXTURE_WIDTH:
         *params = img->Width;
         break;
      case GL_TEXTURE_HEIGHT:
         *params = img->Height;
         break;
      case GL_TEXTURE_DEPTH:
         *params = img->Depth;
         break;
      case GL_TEXTURE_INTERNAL_FORMAT:
         if (_mesa_is_format_compressed(texFormat)) {
            /* need to return the actual compressed format */
            *params = _mesa_compressed_format_to_glenum(ctx, texFormat);
         }
         else {
	    /* If the true internal format is not compressed but the user
	     * requested a generic compressed format, we have to return the
	     * generic base format that matches.
	     *
	     * From page 119 (page 129 of the PDF) of the OpenGL 1.3 spec:
	     *
	     *     "If no specific compressed format is available,
	     *     internalformat is instead replaced by the corresponding base
	     *     internal format."
	     *
	     * Otherwise just return the user's requested internal format
	     */
	    const GLenum f =
	       _mesa_gl_compressed_format_base_format(img->InternalFormat);

	    *params = (f != 0) ? f : img->InternalFormat;
	 }
         break;
      case GL_TEXTURE_BORDER:
         *params = img->Border;
         break;
      case GL_TEXTURE_RED_SIZE:
         if (img->_BaseFormat == GL_RED) {
            *params = _mesa_get_format_bits(texFormat, pname);
	    break;
	 }
	 /* FALLTHROUGH */
      case GL_TEXTURE_GREEN_SIZE:
         if (img->_BaseFormat == GL_RG) {
            *params = _mesa_get_format_bits(texFormat, pname);
	    break;
	 }
	 /* FALLTHROUGH */
      case GL_TEXTURE_BLUE_SIZE:
         if (img->_BaseFormat == GL_RGB || img->_BaseFormat == GL_RGBA)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_ALPHA_SIZE:
         if (img->_BaseFormat == GL_ALPHA ||
             img->_BaseFormat == GL_LUMINANCE_ALPHA ||
             img->_BaseFormat == GL_RGBA)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_INTENSITY_SIZE:
         if (img->_BaseFormat != GL_INTENSITY)
            *params = 0;
         else {
            *params = _mesa_get_format_bits(texFormat, pname);
            if (*params == 0) {
               /* intensity probably stored as rgb texture */
               *params = MIN2(_mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE),
                              _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE));
            }
         }
         break;
      case GL_TEXTURE_LUMINANCE_SIZE:
         if (img->_BaseFormat != GL_LUMINANCE &&
             img->_BaseFormat != GL_LUMINANCE_ALPHA)
            *params = 0;
         else {
            *params = _mesa_get_format_bits(texFormat, pname);
            if (*params == 0) {
               /* luminance probably stored as rgb texture */
               *params = MIN2(_mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE),
                              _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE));
            }
         }
         break;
      case GL_TEXTURE_INDEX_SIZE_EXT:
         if (img->_BaseFormat == GL_COLOR_INDEX)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            *params = 0;
         break;
      case GL_TEXTURE_DEPTH_SIZE_ARB:
         if (ctx->Extensions.ARB_depth_texture)
            *params = _mesa_get_format_bits(texFormat, pname);
         else
            goto invalid_pname;
         break;
      case GL_TEXTURE_STENCIL_SIZE_EXT:
         if (ctx->Extensions.EXT_packed_depth_stencil ||
             ctx->Extensions.ARB_framebuffer_object) {
            *params = _mesa_get_format_bits(texFormat, pname);
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_SHARED_SIZE:
         if (ctx->VersionMajor >= 3 ||
             ctx->Extensions.EXT_texture_shared_exponent) {
            *params = texFormat == MESA_FORMAT_RGB9_E5_FLOAT ? 5 : 0;
         }
         else {
            goto invalid_pname;
         }
         break;

      /* GL_ARB_texture_compression */
      case GL_TEXTURE_COMPRESSED_IMAGE_SIZE:
	 if (_mesa_is_format_compressed(texFormat) &&
             !_mesa_is_proxy_texture(target)) {
            *params = _mesa_format_image_size(texFormat, img->Width,
                                              img->Height, img->Depth);
	 }
	 else {
	    _mesa_error(ctx, GL_INVALID_OPERATION,
			"glGetTexLevelParameter[if]v(pname)");
	 }
         break;
      case GL_TEXTURE_COMPRESSED:
         *params = (GLint) _mesa_is_format_compressed(texFormat);
         break;

      /* GL_ARB_texture_float */
      case GL_TEXTURE_RED_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_RED_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_GREEN_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_GREEN_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_BLUE_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_BLUE_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_ALPHA_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_ALPHA_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_LUMINANCE_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_LUMINANCE_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_INTENSITY_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_INTENSITY_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;
      case GL_TEXTURE_DEPTH_TYPE_ARB:
         if (ctx->Extensions.ARB_texture_float) {
            *params = _mesa_get_format_bits(texFormat, GL_TEXTURE_DEPTH_SIZE) ?
               _mesa_get_format_datatype(texFormat) : GL_NONE;
         }
         else {
            goto invalid_pname;
         }
         break;

      default:
         goto invalid_pname;
   }

   /* no error if we get here */
   return;

invalid_pname:
   _mesa_error(ctx, GL_INVALID_ENUM,
               "glGetTexLevelParameter[if]v(pname=%s)",
               _mesa_lookup_enum_by_nr(pname));
}
/**
 * Do error checking for a glGetTexImage() call.
 * \return GL_TRUE if any error, GL_FALSE if no errors.
 */
static GLboolean
getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
                        GLenum format, GLenum type, GLsizei clientMemSize,
                        GLvoid *pixels )
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
   GLenum baseFormat, err;

   if (!legal_getteximage_target(ctx, target)) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target=0x%x)", target);
      return GL_TRUE;
   }

   assert(maxLevels != 0);
   if (level < 0 || level >= maxLevels) {
      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
      return GL_TRUE;
   }

   err = _mesa_error_check_format_and_type(ctx, format, type);
   if (err != GL_NO_ERROR) {
      _mesa_error(ctx, err, "glGetTexImage(format/type)");
      return GL_TRUE;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);

   if (!texObj) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
      return GL_TRUE;
   }

   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
   if (!texImage) {
      /* non-existant texture image */
      return GL_TRUE;
   }

   baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
      
   /* Make sure the requested image format is compatible with the
    * texture's format.
    */
   if (_mesa_is_color_format(format)
       && !_mesa_is_color_format(baseFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
      return GL_TRUE;
   }
   else if (_mesa_is_depth_format(format)
            && !_mesa_is_depth_format(baseFormat)
            && !_mesa_is_depthstencil_format(baseFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
      return GL_TRUE;
   }
   else if (_mesa_is_ycbcr_format(format)
            && !_mesa_is_ycbcr_format(baseFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
      return GL_TRUE;
   }
   else if (_mesa_is_depthstencil_format(format)
            && !_mesa_is_depthstencil_format(baseFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
      return GL_TRUE;
   }
   else if (_mesa_is_dudv_format(format)
            && !_mesa_is_dudv_format(baseFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
      return GL_TRUE;
   }

   if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
                                  texImage->Height, texImage->Depth,
                                  format, type, clientMemSize, pixels)) {
      if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetTexImage(out of bounds PBO access)");
      } else {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetnTexImageARB(out of bounds access:"
                     " bufSize (%d) is too small)", clientMemSize);
      }
      return GL_TRUE;
   }

   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
      /* PBO should not be mapped */
      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetTexImage(PBO is mapped)");
         return GL_TRUE;
      }
   }

   return GL_FALSE;
}
Esempio n. 19
0
/**
 * Check if the call to _mesa_meta_GenerateMipmap() will require a
 * software fallback.  The fallback path will require that the texture
 * images are mapped.
 * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise
 */
static bool
fallback_required(struct gl_context *ctx, GLenum target,
                  struct gl_texture_object *texObj)
{
   struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
   struct gl_texture_image *baseImage;
   GLuint srcLevel;
   GLenum status;

   /* check for fallbacks */
   if (target == GL_TEXTURE_3D) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() to %s target\n",
                       _mesa_enum_to_string(target));
      return true;
   }

   srcLevel = texObj->BaseLevel;
   baseImage = _mesa_select_tex_image(texObj, target, srcLevel);
   if (!baseImage) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() couldn't find base teximage\n");
      return true;
   }

   if (_mesa_is_format_compressed(baseImage->TexFormat)) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() with %s format\n",
                       _mesa_get_format_name(baseImage->TexFormat));
      return true;
   }

   if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB &&
       !ctx->Extensions.EXT_texture_sRGB_decode) {
      /* The texture format is sRGB but we can't turn off sRGB->linear
       * texture sample conversion.  So we won't be able to generate the
       * right colors when rendering.  Need to use a fallback.
       */
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() of sRGB texture without "
                       "sRGB decode\n");
      return true;
   }

   /*
    * Test that we can actually render in the texture's format.
    */
   if (mipmap->fb == NULL) {
      mipmap->fb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF);
      if (mipmap->fb == NULL) {
         _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                          "glGenerateMipmap() ran out of memory\n");
         return true;
      }
   }

   _mesa_meta_framebuffer_texture_image(ctx, mipmap->fb,
                                        GL_COLOR_ATTACHMENT0, baseImage, 0);

   status = _mesa_check_framebuffer_status(ctx, mipmap->fb);
   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() got incomplete FBO\n");
      return true;
   }

   return false;
}
/**
 * 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;
}
Esempio n. 21
0
/**
 * Check if the call to _mesa_meta_GenerateMipmap() will require a
 * software fallback.  The fallback path will require that the texture
 * images are mapped.
 * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise
 */
static bool
fallback_required(struct gl_context *ctx, GLenum target,
                  struct gl_texture_object *texObj)
{
   const GLuint fboSave = ctx->DrawBuffer->Name;
   struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
   struct gl_texture_image *baseImage;
   GLuint srcLevel;
   GLenum status;

   /* check for fallbacks */
//   if (target == GL_TEXTURE_3D) {
//      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
//                       "glGenerateMipmap() to %s target\n",
//                       _mesa_lookup_enum_by_nr(target));
//      return true;
//   }

   srcLevel = texObj->BaseLevel;
   baseImage = _mesa_select_tex_image(texObj, target, srcLevel);
   if (!baseImage) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() couldn't find base teximage\n");
      return true;
   }

   if (_mesa_is_format_compressed(baseImage->TexFormat)) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() with %s format\n",
                       _mesa_get_format_name(baseImage->TexFormat));
      return true;
   }

   if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB &&
       !ctx->Extensions.EXT_texture_sRGB_decode) {
      /* The texture format is sRGB but we can't turn off sRGB->linear
       * texture sample conversion.  So we won't be able to generate the
       * right colors when rendering.  Need to use a fallback.
       */
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() of sRGB texture without "
                       "sRGB decode\n");
      return true;
   }

   /*
    * Test that we can actually render in the texture's format.
    */
   if (!mipmap->FBO)
      glGenFramebuffers(1, &mipmap->FBO);
   glBindFramebuffer(GL_FRAMEBUFFER, mipmap->FBO);

   _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, baseImage, 0);

   status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

   glBindFramebuffer(GL_FRAMEBUFFER, fboSave);

   if (status != GL_FRAMEBUFFER_COMPLETE) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() got incomplete FBO\n");
      return true;
   }

   return false;
}
Esempio n. 22
0
/**
 * Called via ctx->Driver.GenerateMipmap()
 * Note: We don't yet support 3D textures, 1D/2D array textures or texture
 * borders.
 */
void
_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
                          struct gl_texture_object *texObj)
{
   struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
   struct vertex verts[4];
   const GLuint baseLevel = texObj->BaseLevel;
   const GLuint maxLevel = texObj->MaxLevel;
   const GLint maxLevelSave = texObj->MaxLevel;
   const GLboolean genMipmapSave = texObj->GenerateMipmap;
   const GLuint currentTexUnitSave = ctx->Texture.CurrentUnit;
   const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
                                      ctx->Extensions.ARB_fragment_shader;
   GLenum faceTarget;
   GLuint dstLevel;
   GLuint samplerSave;
   GLint swizzle[4];
   GLboolean swizzleSaved = GL_FALSE;

   if (fallback_required(ctx, target, texObj)) {
      _mesa_generate_mipmap(ctx, target, texObj);
      return;
   }

   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
      faceTarget = target;
      target = GL_TEXTURE_CUBE_MAP;
   } else {
      faceTarget = target;
   }

   _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);

   /* Choose between glsl version and fixed function version of
    * GenerateMipmap function.
    */
   if (use_glsl_version) {
      _mesa_meta_setup_vertex_objects(&mipmap->VAO, &mipmap->VBO, true,
                                      2, 4, 0);
      _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders);
   } else {
      _mesa_meta_setup_ff_tnl_for_blit(&mipmap->VAO, &mipmap->VBO, 3);
      _mesa_set_enable(ctx, target, GL_TRUE);
   }

   samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
      ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;

   if (currentTexUnitSave != 0)
      glBindTexture(target, texObj->Name);

   if (!mipmap->Sampler) {
      glGenSamplers(1, &mipmap->Sampler);
      glBindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler);

      glSamplerParameteri(mipmap->Sampler,
                              GL_TEXTURE_MIN_FILTER,
                              GL_LINEAR_MIPMAP_LINEAR);
      glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
      glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

      /* We don't want to encode or decode sRGB values; treat them as linear.
       * This is not technically correct for GLES3 but we don't get any API
       * error at the moment.
       */
      if (ctx->Extensions.EXT_texture_sRGB_decode) {
         glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT,
               GL_SKIP_DECODE_EXT);
      }
   } else {
      glBindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler);
   }

   assert(mipmap->FBO != 0);
   glBindFramebuffer(GL_FRAMEBUFFER, mipmap->FBO);

   glTexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE);

//   if (texObj->_Swizzle != SWIZZLE_NOOP) {
//      static const GLint swizzleNoop[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
//      memcpy(swizzle, texObj->Swizzle, sizeof(swizzle));
//      swizzleSaved = GL_TRUE;
//      glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzleNoop);
//   }

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

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

   /* texture is already locked, unlock now */
   _mesa_unlock_texture(ctx, texObj);

   for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) {
      const struct gl_texture_image *srcImage;
      struct gl_texture_image *dstImage;
      const GLuint srcLevel = dstLevel - 1;
      GLuint layer;
      GLsizei srcWidth, srcHeight, srcDepth;
      GLsizei dstWidth, dstHeight, dstDepth;

      srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel);
      assert(srcImage->Border == 0);

      /* src size */
      srcWidth = srcImage->Width;
      if (target == GL_TEXTURE_1D_ARRAY) {
         srcHeight = 1;
         srcDepth = srcImage->Height;
      } else {
         srcHeight = srcImage->Height;
         srcDepth = srcImage->Depth;
      }

      /* new dst size */
      dstWidth = minify(srcWidth, 1);
      dstHeight = minify(srcHeight, 1);
//      dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth;
      dstDepth = srcDepth;

      if (dstWidth == srcWidth &&
          dstHeight == srcHeight &&
          dstDepth == srcDepth) {
         /* all done */
         break;
      }

      /* Allocate storage for the destination mipmap image(s) */

      /* Set MaxLevel large enough to hold the new level when we allocate it */
      glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel);

      if (!prepare_mipmap_level(ctx, texObj, dstLevel,
                                dstWidth, dstHeight, dstDepth,
                                srcImage->InternalFormat,
                                srcImage->TexFormat)) {
         /* All done.  We either ran out of memory or we would go beyond the
          * last valid level of an immutable texture if we continued.
          */
         break;
      }
      dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel);

      /* limit minification to src level */
      glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);

      /* setup viewport */
      _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight);
      glDrawBuffer(GL_COLOR_ATTACHMENT0);

      for (layer = 0; layer < dstDepth; ++layer) {
         /* Setup texture coordinates */
         _mesa_meta_setup_texture_coords(faceTarget,
                                         layer,
                                         0, 0, 1, /* width, height never used here */
                                         verts[0].tex,
                                         verts[1].tex,
                                         verts[2].tex,
                                         verts[3].tex);

         /* upload vertex data */
         glBufferData(GL_ARRAY_BUFFER, sizeof(verts),
                          verts, GL_DYNAMIC_DRAW);

         _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstImage, layer);

         /* sanity check */
         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
             GL_FRAMEBUFFER_COMPLETE) {
            _mesa_problem(ctx, "Unexpected incomplete framebuffer in "
                          "_mesa_meta_GenerateMipmap()");
            break;
         }

         assert(dstWidth == ctx->DrawBuffer->Width);
         if (target == GL_TEXTURE_1D_ARRAY) {
            assert(dstHeight == 1);
         } else {
            assert(dstHeight == ctx->DrawBuffer->Height);
         }

         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
      }
   }

   _mesa_lock_texture(ctx, texObj); /* relock */

   glBindSampler(ctx->Texture.CurrentUnit, samplerSave);

   _mesa_meta_end(ctx);

   glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
   if (genMipmapSave)
      glTexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave);
//   if (swizzleSaved)
//      glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
}
/**
 * Do error checking for a glGetCompressedTexImage() call.
 * \return GL_TRUE if any error, GL_FALSE if no errors.
 */
static GLboolean
getcompressedteximage_error_check(struct gl_context *ctx, GLenum target,
                                  GLint level, GLsizei clientMemSize, GLvoid *img)
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
   GLuint compressedSize;

   if (!legal_getteximage_target(ctx, target)) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
                  target);
      return GL_TRUE;
   }

   assert(maxLevels != 0);
   if (level < 0 || level >= maxLevels) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glGetCompressedTexImageARB(bad level = %d)", level);
      return GL_TRUE;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   if (!texObj) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
      return GL_TRUE;
   }

   texImage = _mesa_select_tex_image(ctx, texObj, target, level);

   if (!texImage) {
      /* probably invalid mipmap level */
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glGetCompressedTexImageARB(level)");
      return GL_TRUE;
   }

   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGetCompressedTexImageARB(texture is not compressed)");
      return GL_TRUE;
   }

   compressedSize = _mesa_format_image_size(texImage->TexFormat,
                                            texImage->Width,
                                            texImage->Height,
                                            texImage->Depth);

   if (!_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
      /* do bounds checking on writing to client memory */
      if (clientMemSize < compressedSize) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetnCompressedTexImageARB(out of bounds access:"
                     " bufSize (%d) is too small)", clientMemSize);
         return GL_TRUE;
      }
   } else {
      /* do bounds checking on PBO write */
      if ((const GLubyte *) img + compressedSize >
          (const GLubyte *) ctx->Pack.BufferObj->Size) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetCompressedTexImage(out of bounds PBO access)");
         return GL_TRUE;
      }

      /* make sure PBO is not mapped */
      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetCompressedTexImage(PBO is mapped)");
         return GL_TRUE;
      }
   }

   return GL_FALSE;
}
Esempio n. 24
0
/**
 * Check if the call to _mesa_meta_GenerateMipmap() will require a
 * software fallback.  The fallback path will require that the texture
 * images are mapped.
 * \return GL_TRUE if a fallback is needed, GL_FALSE otherwise
 */
static bool
fallback_required(struct gl_context *ctx, GLenum target,
                  struct gl_texture_object *texObj)
{
   const GLuint fboSave = ctx->DrawBuffer->Name;
   struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
   struct gl_texture_image *baseImage;
   GLuint srcLevel;
   GLenum status;

   /* GL_DRAW_FRAMEBUFFER does not exist in OpenGL ES 1.x, and since
    * _mesa_meta_begin hasn't been called yet, we have to work-around API
    * difficulties.  The whole reason that GL_DRAW_FRAMEBUFFER is used instead
    * of GL_FRAMEBUFFER is that the read framebuffer may be different.  This
    * is moot in OpenGL ES 1.x.
    */
   const GLenum fbo_target = ctx->API == API_OPENGLES
      ? GL_FRAMEBUFFER : GL_DRAW_FRAMEBUFFER;

   /* check for fallbacks */
   if (target == GL_TEXTURE_3D) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() to %s target\n",
                       _mesa_enum_to_string(target));
      return true;
   }

   srcLevel = texObj->BaseLevel;
   baseImage = _mesa_select_tex_image(texObj, target, srcLevel);
   if (!baseImage) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() couldn't find base teximage\n");
      return true;
   }

   if (_mesa_is_format_compressed(baseImage->TexFormat)) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() with %s format\n",
                       _mesa_get_format_name(baseImage->TexFormat));
      return true;
   }

   if (_mesa_get_format_color_encoding(baseImage->TexFormat) == GL_SRGB &&
       !ctx->Extensions.EXT_texture_sRGB_decode) {
      /* The texture format is sRGB but we can't turn off sRGB->linear
       * texture sample conversion.  So we won't be able to generate the
       * right colors when rendering.  Need to use a fallback.
       */
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() of sRGB texture without "
                       "sRGB decode\n");
      return true;
   }

   /*
    * Test that we can actually render in the texture's format.
    */
   if (!mipmap->FBO)
      _mesa_GenFramebuffers(1, &mipmap->FBO);
   _mesa_BindFramebuffer(fbo_target, mipmap->FBO);

   _mesa_meta_bind_fbo_image(fbo_target, GL_COLOR_ATTACHMENT0, baseImage, 0);

   status = _mesa_CheckFramebufferStatus(fbo_target);

   _mesa_BindFramebuffer(fbo_target, fboSave);

   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
      _mesa_perf_debug(ctx, MESA_DEBUG_SEVERITY_HIGH,
                       "glGenerateMipmap() got incomplete FBO\n");
      return true;
   }

   return false;
}
Esempio n. 25
0
/**
 * 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;
}
Esempio n. 26
0
/**
 * 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 */
    }
}
Esempio n. 27
0
/**
 * Do error checking for a glGetCompressedTexImage() call.
 * \return GL_TRUE if any error, GL_FALSE if no errors.
 */
static GLboolean
getcompressedteximage_error_check(GLcontext *ctx, GLenum target, GLint level,
                                  GLvoid *img)
{
   struct gl_texture_object *texObj;
   struct gl_texture_image *texImage;
   const GLuint maxLevels = _mesa_max_texture_levels(ctx, target);

   if (maxLevels == 0) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImage(target=0x%x)",
                  target);
      return GL_TRUE;
   }

   if (level < 0 || level >= maxLevels) {
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glGetCompressedTexImageARB(bad level = %d)", level);
      return GL_TRUE;
   }

   if (_mesa_is_proxy_texture(target)) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "glGetCompressedTexImageARB(bad target = %s)",
                  _mesa_lookup_enum_by_nr(target));
      return GL_TRUE;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);
   if (!texObj) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
      return GL_TRUE;
   }

   texImage = _mesa_select_tex_image(ctx, texObj, target, level);

   if (!texImage) {
      /* probably invalid mipmap level */
      _mesa_error(ctx, GL_INVALID_VALUE,
                  "glGetCompressedTexImageARB(level)");
      return GL_TRUE;
   }

   if (!_mesa_is_format_compressed(texImage->TexFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGetCompressedTexImageARB(texture is not compressed)");
      return GL_TRUE;
   }

   if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
      GLuint compressedSize;

      /* make sure PBO is not mapped */
      if (_mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetCompressedTexImage(PBO is mapped)");
         return GL_TRUE;
      }

      compressedSize = _mesa_format_image_size(texImage->TexFormat,
                                               texImage->Width,
                                               texImage->Height,
                                               texImage->Depth);

      /* do bounds checking on PBO write */
      if ((const GLubyte *) img + compressedSize >
          (const GLubyte *) ctx->Pack.BufferObj->Size) {
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "glGetCompressedTexImage(out of bounds PBO write)");
         return GL_TRUE;
      }
   }

   return GL_FALSE;
}
Esempio n. 28
0
/**
 * Try to do a glBlitFramebuffer using glCopyTexSubImage2D
 * We can do this when the dst renderbuffer is actually a texture and
 * there is no scaling, mirroring or scissoring.
 *
 * \return new buffer mask indicating the buffers left to blit using the
 *         normal path.
 */
static GLbitfield
intel_blit_framebuffer_copy_tex_sub_image(struct gl_context *ctx,
                                          GLint srcX0, GLint srcY0,
                                          GLint srcX1, GLint srcY1,
                                          GLint dstX0, GLint dstY0,
                                          GLint dstX1, GLint dstY1,
                                          GLbitfield mask, GLenum filter)
{
   if (mask & GL_COLOR_BUFFER_BIT) {
      GLint i;
      const struct gl_framebuffer *drawFb = ctx->DrawBuffer;
      const struct gl_framebuffer *readFb = ctx->ReadBuffer;
      const struct gl_renderbuffer_attachment *drawAtt;
      struct intel_renderbuffer *srcRb = 
         intel_renderbuffer(readFb->_ColorReadBuffer);

      /* If the source and destination are the same size with no mirroring,
       * the rectangles are within the size of the texture and there is no
       * scissor then we can use glCopyTexSubimage2D to implement the blit.
       * This will end up as a fast hardware blit on some drivers.
       */
      const GLboolean use_intel_copy_texsubimage =
         srcX0 - srcX1 == dstX0 - dstX1 &&
         srcY0 - srcY1 == dstY0 - dstY1 &&
         srcX1 >= srcX0 &&
         srcY1 >= srcY0 &&
         srcX0 >= 0 && srcX1 <= readFb->Width &&
         srcY0 >= 0 && srcY1 <= readFb->Height &&
         dstX0 >= 0 && dstX1 <= drawFb->Width &&
         dstY0 >= 0 && dstY1 <= drawFb->Height &&
         !ctx->Scissor.Enabled;

      /* Verify that all the draw buffers can be blitted using
       * intel_copy_texsubimage().
       */
      for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
         int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
         if (idx == -1)
            continue;
         drawAtt = &drawFb->Attachment[idx];

         if (srcRb && drawAtt && drawAtt->Texture &&
             use_intel_copy_texsubimage)
            continue;
         else
            return mask;
      }

      /* Blit to all active draw buffers */
      for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
         int idx = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
         if (idx == -1)
            continue;
         drawAtt = &drawFb->Attachment[idx];

         {
            const struct gl_texture_object *texObj = drawAtt->Texture;
            const GLuint dstLevel = drawAtt->TextureLevel;
            const GLenum target = texObj->Target;

            struct gl_texture_image *texImage =
               _mesa_select_tex_image(ctx, texObj, target, dstLevel);

            if (!intel_copy_texsubimage(intel_context(ctx),
                                        intel_texture_image(texImage),
                                        dstX0, dstY0,
                                        srcRb,
                                        srcX0, srcY0,
                                        srcX1 - srcX0, /* width */
                                        srcY1 - srcY0))
               return mask;
         }
      }

      mask &= ~GL_COLOR_BUFFER_BIT;
   }

   return mask;
}
Esempio n. 29
0
/**
 * Generate all the mipmap levels below the base level.
 * Note: this GL function would be more useful if one could specify a
 * cube face, a set of array slices, etc.
 */
void GLAPIENTRY
_mesa_GenerateMipmap(GLenum target)
{
   struct gl_texture_image *srcImage;
   struct gl_texture_object *texObj;
   GLboolean error;

   GET_CURRENT_CONTEXT(ctx);

   FLUSH_VERTICES(ctx, 0);

   switch (target) {
   case GL_TEXTURE_1D:
      error = _mesa_is_gles(ctx);
      break;
   case GL_TEXTURE_2D:
      error = GL_FALSE;
      break;
   case GL_TEXTURE_3D:
      error = ctx->API == API_OPENGLES;
      break;
   case GL_TEXTURE_CUBE_MAP:
      error = !ctx->Extensions.ARB_texture_cube_map;
      break;
   case GL_TEXTURE_1D_ARRAY:
      error = _mesa_is_gles(ctx) || !ctx->Extensions.EXT_texture_array;
      break;
   case GL_TEXTURE_2D_ARRAY:
      error = (_mesa_is_gles(ctx) && ctx->Version < 30)
         || !ctx->Extensions.EXT_texture_array;
      break;
   case GL_TEXTURE_CUBE_MAP_ARRAY:
      error = _mesa_is_gles(ctx) ||
              !ctx->Extensions.ARB_texture_cube_map_array;
      break;
   default:
      error = GL_TRUE;
   }

   if (error) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glGenerateMipmapEXT(target=%s)",
                  _mesa_lookup_enum_by_nr(target));
      return;
   }

   texObj = _mesa_get_current_tex_object(ctx, target);

   if (texObj->BaseLevel >= texObj->MaxLevel) {
      /* nothing to do */
      return;
   }

   if (texObj->Target == GL_TEXTURE_CUBE_MAP &&
       !_mesa_cube_complete(texObj)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGenerateMipmap(incomplete cube map)");
      return;
   }

   _mesa_lock_texture(ctx, texObj);

   srcImage = _mesa_select_tex_image(ctx, texObj, target, texObj->BaseLevel);
   if (!srcImage) {
      _mesa_unlock_texture(ctx, texObj);
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGenerateMipmap(zero size base image)");
      return;
   }

   if (_mesa_is_enum_format_integer(srcImage->InternalFormat) ||
       _mesa_is_depthstencil_format(srcImage->InternalFormat) ||
       _mesa_is_stencil_format(srcImage->InternalFormat)) {
      _mesa_unlock_texture(ctx, texObj);
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "glGenerateMipmap(invalid internal format)");
      return;
   }

   if (target == GL_TEXTURE_CUBE_MAP) {
      GLuint face;
      for (face = 0; face < 6; face++)
	 ctx->Driver.GenerateMipmap(ctx,
				    GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + face,
				    texObj);
   }
   else {
      ctx->Driver.GenerateMipmap(ctx, target, texObj);
   }
   _mesa_unlock_texture(ctx, texObj);
}
Esempio n. 30
0
/**
 * Called via ctx->Driver.GenerateMipmap()
 * Note: We don't yet support 3D textures, or texture borders.
 */
void
_mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
                          struct gl_texture_object *texObj)
{
   struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap;
   struct vertex verts[4];
   const GLuint baseLevel = texObj->BaseLevel;
   const GLuint maxLevel = texObj->MaxLevel;
   const GLint maxLevelSave = texObj->MaxLevel;
   const GLboolean genMipmapSave = texObj->GenerateMipmap;
   const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader &&
                                      ctx->Extensions.ARB_fragment_shader;
   GLenum faceTarget;
   GLuint dstLevel;
   struct gl_sampler_object *samp_obj_save = NULL;
   GLint swizzle[4];
   GLboolean swizzleSaved = GL_FALSE;

   /* GLint so the compiler won't complain about type signedness mismatch in
    * the calls to _mesa_texture_parameteriv below.
    */
   static const GLint always_false = GL_FALSE;
   static const GLint always_true = GL_TRUE;

   if (fallback_required(ctx, target, texObj)) {
      _mesa_generate_mipmap(ctx, target, texObj);
      return;
   }

   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
      faceTarget = target;
      target = GL_TEXTURE_CUBE_MAP;
   } else {
      faceTarget = target;
   }

   _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
   _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

   /* Choose between glsl version and fixed function version of
    * GenerateMipmap function.
    */
   if (use_glsl_version) {
      _mesa_meta_setup_vertex_objects(ctx, &mipmap->VAO, &mipmap->buf_obj, true,
                                      2, 4, 0);
      _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders);
   } else {
      _mesa_meta_setup_ff_tnl_for_blit(ctx, &mipmap->VAO, &mipmap->buf_obj, 3);
      _mesa_set_enable(ctx, target, GL_TRUE);
   }

   _mesa_reference_sampler_object(ctx, &samp_obj_save,
                                  ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler);

   /* We may have been called from glGenerateTextureMipmap with CurrentUnit
    * still set to 0, so we don't know when we can skip binding the texture.
    * Assume that _mesa_BindTexture will be fast if we're rebinding the same
    * texture.
    */
   _mesa_BindTexture(target, texObj->Name);

   if (mipmap->samp_obj == NULL) {
      mipmap->samp_obj =  ctx->Driver.NewSamplerObject(ctx, 0xDEADBEEF);
      if (mipmap->samp_obj == NULL) {
         /* This is a bit lazy.  Flag out of memory, and then don't bother to
          * clean up.  Once out of memory is flagged, the only realistic next
          * move is to destroy the context.  That will trigger all the right
          * clean up.
          */
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenerateMipmap");
         return;
      }

      _mesa_set_sampler_filters(ctx, mipmap->samp_obj, GL_LINEAR_MIPMAP_LINEAR,
                                GL_LINEAR);
      _mesa_set_sampler_wrap(ctx, mipmap->samp_obj, GL_CLAMP_TO_EDGE,
                             GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);

      /* We don't want to encode or decode sRGB values; treat them as linear. */
      _mesa_set_sampler_srgb_decode(ctx, mipmap->samp_obj, GL_SKIP_DECODE_EXT);
   }

   _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, mipmap->samp_obj);

   assert(mipmap->fb != NULL);
   _mesa_bind_framebuffers(ctx, mipmap->fb, mipmap->fb);

   _mesa_texture_parameteriv(ctx, texObj, GL_GENERATE_MIPMAP, &always_false, false);

   if (texObj->_Swizzle != SWIZZLE_NOOP) {
      static const GLint swizzleNoop[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
      memcpy(swizzle, texObj->Swizzle, sizeof(swizzle));
      swizzleSaved = GL_TRUE;
      _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_SWIZZLE_RGBA,
                                swizzleNoop, false);
   }

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

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

   /* texture is already locked, unlock now */
   _mesa_unlock_texture(ctx, texObj);

   _mesa_prepare_mipmap_levels(ctx, texObj, baseLevel, maxLevel);

   for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) {
      const struct gl_texture_image *srcImage;
      struct gl_texture_image *dstImage;
      const GLuint srcLevel = dstLevel - 1;
      GLuint layer;
      GLsizei srcWidth, srcHeight, srcDepth;
      GLsizei dstWidth, dstHeight, dstDepth;

      srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel);
      assert(srcImage->Border == 0);

      /* src size */
      srcWidth = srcImage->Width;
      if (target == GL_TEXTURE_1D_ARRAY) {
         srcHeight = 1;
         srcDepth = srcImage->Height;
      } else {
         srcHeight = srcImage->Height;
         srcDepth = srcImage->Depth;
      }

      /* new dst size */
      dstWidth = minify(srcWidth, 1);
      dstHeight = minify(srcHeight, 1);
      dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth;

      if (dstWidth == srcWidth &&
          dstHeight == srcHeight &&
          dstDepth == srcDepth) {
         /* all done */
         break;
      }

      /* Allocate storage for the destination mipmap image(s) */

      /* Set MaxLevel large enough to hold the new level when we allocate it */
      _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL,
                                (GLint *) &dstLevel, false);

      dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel);

      /* All done.  We either ran out of memory or we would go beyond the last
       * valid level of an immutable texture if we continued.
       */
      if (dstImage == NULL)
         break;

      /* limit minification to src level */
      _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL,
                                (GLint *) &srcLevel, false);

      /* setup viewport */
      _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight);
      _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);

      for (layer = 0; layer < dstDepth; ++layer) {
         /* Setup texture coordinates */
         _mesa_meta_setup_texture_coords(faceTarget,
                                         layer,
                                         0, 0, /* xoffset, yoffset */
                                         srcWidth, srcHeight, /* img size */
                                         srcWidth, srcHeight, srcDepth,
                                         verts[0].tex,
                                         verts[1].tex,
                                         verts[2].tex,
                                         verts[3].tex);

         /* upload vertex data */
         _mesa_buffer_data(ctx, mipmap->buf_obj, GL_NONE, sizeof(verts), verts,
                           GL_DYNAMIC_DRAW, __func__);

         _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer,
                                              GL_COLOR_ATTACHMENT0, dstImage,
                                              layer);

         /* sanity check */
         if (_mesa_check_framebuffer_status(ctx, ctx->DrawBuffer) !=
             GL_FRAMEBUFFER_COMPLETE) {
            _mesa_problem(ctx, "Unexpected incomplete framebuffer in "
                          "_mesa_meta_GenerateMipmap()");
            break;
         }

         assert(dstWidth == ctx->DrawBuffer->Width);
         if (target == GL_TEXTURE_1D_ARRAY) {
            assert(dstHeight == 1);
         } else {
            assert(dstHeight == ctx->DrawBuffer->Height);
         }

         _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
      }
   }

   _mesa_lock_texture(ctx, texObj); /* relock */

   _mesa_bind_sampler(ctx, ctx->Texture.CurrentUnit, samp_obj_save);
   _mesa_reference_sampler_object(ctx, &samp_obj_save, NULL);

   _mesa_meta_end(ctx);

   _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_MAX_LEVEL, &maxLevelSave,
                             false);
   if (genMipmapSave)
      _mesa_texture_parameteriv(ctx, texObj, GL_GENERATE_MIPMAP, &always_true,
                                false);
   if (swizzleSaved)
      _mesa_texture_parameteriv(ctx, texObj, GL_TEXTURE_SWIZZLE_RGBA, swizzle,
                                false);
}