예제 #1
0
/**
 * Implementation of up or downsampling for window-system MSAA miptrees.
 */
void
brw_meta_updownsample(struct brw_context *brw,
                      struct intel_mipmap_tree *src_mt,
                      struct intel_mipmap_tree *dst_mt)
{
   struct gl_context *ctx = &brw->ctx;
   GLuint fbos[2], src_rbo, dst_rbo, src_fbo, dst_fbo;
   GLenum drawbuffer;
   GLbitfield attachment, blit_bit;

   if (_mesa_get_format_base_format(src_mt->format) == GL_DEPTH_COMPONENT ||
       _mesa_get_format_base_format(src_mt->format) == GL_DEPTH_STENCIL) {
      attachment = GL_DEPTH_ATTACHMENT;
      drawbuffer = GL_NONE;
      blit_bit = GL_DEPTH_BUFFER_BIT;
   } else {
      attachment = GL_COLOR_ATTACHMENT0;
      drawbuffer = GL_COLOR_ATTACHMENT0;
      blit_bit = GL_COLOR_BUFFER_BIT;
   }

   brw_emit_mi_flush(brw);

   _mesa_meta_begin(ctx, MESA_META_ALL);
   _mesa_GenFramebuffers(2, fbos);
   src_rbo = brw_get_rb_for_slice(brw, src_mt, 0, 0, false);
   dst_rbo = brw_get_rb_for_slice(brw, dst_mt, 0, 0, false);
   src_fbo = fbos[0];
   dst_fbo = fbos[1];

   _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, src_fbo);
   _mesa_FramebufferRenderbuffer(GL_READ_FRAMEBUFFER, attachment,
                                 GL_RENDERBUFFER, src_rbo);
   _mesa_ReadBuffer(drawbuffer);

   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, dst_fbo);
   _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, attachment,
                                 GL_RENDERBUFFER, dst_rbo);
   _mesa_DrawBuffer(drawbuffer);

   _mesa_BlitFramebuffer(0, 0,
                         src_mt->logical_width0, src_mt->logical_height0,
                         0, 0,
                         dst_mt->logical_width0, dst_mt->logical_height0,
                         blit_bit, GL_NEAREST);

   _mesa_DeleteRenderbuffers(1, &src_rbo);
   _mesa_DeleteRenderbuffers(1, &dst_rbo);
   _mesa_DeleteFramebuffers(2, fbos);

   _mesa_meta_end(ctx);

   brw_emit_mi_flush(brw);
}
예제 #2
0
파일: clear.c 프로젝트: maxenceledore/mesa
/**
 * The ClearBuffer framework is so complicated and so riddled with the
 * assumption that the framebuffer is bound that, for now, we will just fake
 * direct state access clearing for the user.
 */
void GLAPIENTRY
_mesa_ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer,
                              GLfloat depth, GLint stencil)
{
   GLint oldfb;

   _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb);
   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
   _mesa_ClearBufferfi(buffer, 0, depth, stencil);
   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb);
}
예제 #3
0
파일: clear.c 프로젝트: maxenceledore/mesa
/**
 * The ClearBuffer framework is so complicated and so riddled with the
 * assumption that the framebuffer is bound that, for now, we will just fake
 * direct state access clearing for the user.
 */
void GLAPIENTRY
_mesa_ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer,
                              GLint drawbuffer, const GLfloat *value)
{
   GLint oldfb;

   _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb);
   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
   _mesa_ClearBufferfv(buffer, drawbuffer, value);
   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb);
}
void
brw_meta_resolve_color(struct brw_context *brw,
                       struct intel_mipmap_tree *mt)
{
    struct gl_context *ctx = &brw->ctx;
    GLuint fbo;
    struct gl_renderbuffer *rb;
    struct rect rect;

    brw_emit_mi_flush(brw);

    _mesa_meta_begin(ctx, MESA_META_ALL);

    _mesa_GenFramebuffers(1, &fbo);
    rb = brw_get_rb_for_slice(brw, mt, 0, 0, false);

    _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
    _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, GL_COLOR_ATTACHMENT0,
                                   rb);
    _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);

    brw_fast_clear_init(brw);

    use_rectlist(brw, true);

    brw_bind_rep_write_shader(brw, (float *) fast_clear_color);

    /* SKL+ also has a resolve mode for compressed render targets and thus more
     * bits to let us select the type of resolve.  For fast clear resolves, it
     * turns out we can use the same value as pre-SKL though.
     */
    if (intel_miptree_is_lossless_compressed(brw, mt))
        set_fast_clear_op(brw, GEN9_PS_RENDER_TARGET_RESOLVE_FULL);
    else
        set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE);

    mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED;
    get_resolve_rect(brw, mt, &rect);

    brw_draw_rectlist(brw, &rect, 1);

    set_fast_clear_op(brw, 0);
    use_rectlist(brw, false);

    _mesa_reference_renderbuffer(&rb, NULL);
    _mesa_DeleteFramebuffers(1, &fbo);

    _mesa_meta_end(ctx);

    /* We're typically called from intel_update_state() and we're supposed to
     * return with the state all updated to what it was before
     * brw_meta_resolve_color() was called.  The meta rendering will have
     * messed up the state and we need to call _mesa_update_state() again to
     * get back to where we were supposed to be when resolve was called.
     */
    if (ctx->NewState)
        _mesa_update_state(ctx);
}
예제 #5
0
void
brw_meta_resolve_color(struct brw_context *brw,
                       struct intel_mipmap_tree *mt)
{
   struct gl_context *ctx = &brw->ctx;
   GLuint fbo, rbo;
   struct rect rect;

   intel_batchbuffer_emit_mi_flush(brw);

   _mesa_meta_begin(ctx, MESA_META_ALL);

   _mesa_GenFramebuffers(1, &fbo);
   rbo = brw_get_rb_for_slice(brw, mt, 0, 0, false);

   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
   _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
                                 GL_COLOR_ATTACHMENT0,
                                 GL_RENDERBUFFER, rbo);
   _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);

   brw_fast_clear_init(brw);

   use_rectlist(brw, true);

   brw_bind_rep_write_shader(brw, (float *) fast_clear_color);

   set_fast_clear_op(brw, GEN7_PS_RENDER_TARGET_RESOLVE_ENABLE);

   mt->fast_clear_state = INTEL_FAST_CLEAR_STATE_RESOLVED;
   get_resolve_rect(brw, mt, &rect);

   brw_draw_rectlist(ctx, &rect, 1);

   set_fast_clear_op(brw, 0);
   use_rectlist(brw, false);

   _mesa_DeleteRenderbuffers(1, &rbo);
   _mesa_DeleteFramebuffers(1, &fbo);

   _mesa_meta_end(ctx);

   /* We're typically called from intel_update_state() and we're supposed to
    * return with the state all updated to what it was before
    * brw_meta_resolve_color() was called.  The meta rendering will have
    * messed up the state and we need to call _mesa_update_state() again to
    * get back to where we were supposed to be when resolve was called.
    */
   if (ctx->NewState)
      _mesa_update_state(ctx);
}
예제 #6
0
bool
_mesa_meta_pbo_GetTexSubImage(struct gl_context *ctx, GLuint dims,
                              struct gl_texture_image *tex_image,
                              int xoffset, int yoffset, int zoffset,
                              int width, int height, int depth,
                              GLenum format, GLenum type, const void *pixels,
                              const struct gl_pixelstore_attrib *packing)
{
   GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 };
   int full_height, image_height;
   struct gl_texture_image *pbo_tex_image;
   struct gl_renderbuffer *rb = NULL;
   GLenum status;
   bool success = false;
   int z;

   if (!_mesa_is_bufferobj(packing->BufferObj))
      return false;

   if (format == GL_DEPTH_COMPONENT ||
       format == GL_DEPTH_STENCIL ||
       format == GL_STENCIL_INDEX ||
       format == GL_COLOR_INDEX)
      return false;

   if (ctx->_ImageTransferState)
      return false;


   if (!tex_image) {
      rb = ctx->ReadBuffer->_ColorReadBuffer;
      if (_mesa_need_rgb_to_luminance_conversion(rb->Format, format))
         return false;
   }

   /* For arrays, use a tall (height * depth) 2D texture but taking into
    * account the inter-image padding specified with the image height packing
    * property.
    */
   image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight;
   full_height = image_height * (depth - 1) + height;

   pbo_tex_image = create_texture_for_pbo(ctx, false, GL_PIXEL_PACK_BUFFER,
                                          width, full_height * depth,
                                          format, type, pixels, packing,
                                          &pbo, &pbo_tex);
   if (!pbo_tex_image)
      return false;

   _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER |
                           MESA_META_PIXEL_STORE));

   _mesa_GenFramebuffers(2, fbos);

   if (tex_image && tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
      assert(depth == 1);
      assert(zoffset == 0);
      depth = height;
      height = 1;
      image_height = 1;
      zoffset = yoffset;
      yoffset = 0;
   }

   /* If we were given a texture, bind it to the read framebuffer.  If not,
    * we're doing a ReadPixels and we should just use whatever framebuffer
    * the client has bound.
    */
   if (tex_image) {
      _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
      _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                tex_image, zoffset);
      /* If this passes on the first layer it should pass on the others */
      status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
      if (status != GL_FRAMEBUFFER_COMPLETE)
         goto fail;
   } else {
      assert(depth == 1);
   }

   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
   _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                             pbo_tex_image, 0);
   /* If this passes on the first layer it should pass on the others */
   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto fail;

   _mesa_update_state(ctx);

   if (_mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
                                  xoffset, yoffset,
                                  xoffset + width, yoffset + height,
                                  0, 0, width, height,
                                  GL_COLOR_BUFFER_BIT, GL_NEAREST))
      goto fail;

   for (z = 1; z < depth; z++) {
      _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                tex_image, zoffset + z);

      _mesa_update_state(ctx);

      _mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
                                 xoffset, yoffset,
                                 xoffset + width, yoffset + height,
                                 0, z * image_height,
                                 width, z * image_height + height,
                                 GL_COLOR_BUFFER_BIT, GL_NEAREST);
   }

   success = true;

fail:
   _mesa_DeleteFramebuffers(2, fbos);
   _mesa_DeleteTextures(1, &pbo_tex);
   _mesa_DeleteBuffers(1, &pbo);

   _mesa_meta_end(ctx);

   return success;
}
예제 #7
0
/** A partial implementation of glCopyImageSubData
 *
 * This is a partial implementation of glCopyImageSubData that works only
 * if both textures are uncompressed and the destination texture is
 * renderable.  It uses a slight abuse of a texture view (see make_view) to
 * turn the source texture into the destination texture type and then uses
 * _mesa_meta_BlitFramebuffers to do the copy.
 */
bool
_mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx,
                                         struct gl_texture_image *src_tex_image,
                                         struct gl_renderbuffer *src_renderbuffer,
                                         int src_x, int src_y, int src_z,
                                         struct gl_texture_image *dst_tex_image,
                                         struct gl_renderbuffer *dst_renderbuffer,
                                         int dst_x, int dst_y, int dst_z,
                                         int src_width, int src_height)
{
   mesa_format src_format, dst_format;
   GLint src_internal_format, dst_internal_format;
   GLuint src_view_texture = 0;
   struct gl_texture_image *src_view_tex_image;
   GLuint fbos[2];
   bool success = false;
   GLbitfield mask;
   GLenum status, attachment;

   if (src_renderbuffer) {
      src_format = src_renderbuffer->Format;
      src_internal_format = src_renderbuffer->InternalFormat;
   } else {
      assert(src_tex_image);
      src_format = src_tex_image->TexFormat;
      src_internal_format = src_tex_image->InternalFormat;
   }

   if (dst_renderbuffer) {
      dst_format = dst_renderbuffer->Format;
      dst_internal_format = dst_renderbuffer->InternalFormat;
   } else {
      assert(dst_tex_image);
      dst_format = dst_tex_image->TexFormat;
      dst_internal_format = dst_tex_image->InternalFormat;
   }

   if (_mesa_is_format_compressed(src_format))
      return false;

   if (_mesa_is_format_compressed(dst_format))
      return false;

   if (src_internal_format == dst_internal_format) {
      src_view_tex_image = src_tex_image;
   } else {
      if (src_renderbuffer) {
         assert(src_tex_image == NULL);
         src_tex_image = wrap_renderbuffer(ctx, src_renderbuffer);
      }
      if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture,
                     dst_tex_image->InternalFormat))
         goto cleanup;
   }

   /* We really only need to stash the bound framebuffers and scissor. */
   _mesa_meta_begin(ctx, MESA_META_SCISSOR);

   _mesa_GenFramebuffers(2, fbos);
   _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);

   switch (_mesa_get_format_base_format(src_format)) {
   case GL_DEPTH_COMPONENT:
      attachment = GL_DEPTH_ATTACHMENT;
      mask = GL_DEPTH_BUFFER_BIT;
      break;
   case GL_DEPTH_STENCIL:
      attachment = GL_DEPTH_STENCIL_ATTACHMENT;
      mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
      break;
   case GL_STENCIL_INDEX:
      attachment = GL_STENCIL_ATTACHMENT;
      mask = GL_STENCIL_BUFFER_BIT;
      break;
   default:
      attachment = GL_COLOR_ATTACHMENT0;
      mask = GL_COLOR_BUFFER_BIT;
      _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
      _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0);
   }

   if (src_view_tex_image) {
      /* Prefer the tex image because, even if we have a renderbuffer, we may
       * have had to wrap it in a texture view.
       */
      _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment,
                                src_view_tex_image, src_z);
   } else {
      _mesa_FramebufferRenderbuffer(GL_READ_FRAMEBUFFER,
                                    attachment,
                                    GL_RENDERBUFFER,
                                    src_renderbuffer->Name);
   }

   status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto meta_end;

   if (dst_renderbuffer) {
      _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
                                    attachment,
                                    GL_RENDERBUFFER,
                                    dst_renderbuffer->Name);
   } else {
      _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment,
                                dst_tex_image, dst_z);
   }

   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto meta_end;

   /* Since we've bound a new draw framebuffer, we need to update its
    * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to
    * be correct.
    */
   _mesa_update_state(ctx);

   /* We skip the core BlitFramebuffer checks for format consistency.
    * We have already created views to ensure that the texture formats
    * match.
    */
   ctx->Driver.BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
                               src_x, src_y,
                               src_x + src_width, src_y + src_height,
                               dst_x, dst_y,
                               dst_x + src_width, dst_y + src_height,
                               mask, GL_NEAREST);

   success = true;

meta_end:
   _mesa_DeleteFramebuffers(2, fbos);
   _mesa_meta_end(ctx);

cleanup:
   _mesa_DeleteTextures(1, &src_view_texture);

   /* If we got a renderbuffer source, delete the temporary texture */
   if (src_renderbuffer && src_tex_image)
      ctx->Driver.DeleteTexture(ctx, src_tex_image->TexObject);

   return success;
}
예제 #8
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)
      _mesa_GenFramebuffers(1, &mipmap->FBO);
   _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);

   _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, baseImage, 0);

   status = _mesa_CheckFramebufferStatus(GL_FRAMEBUFFER_EXT);

   _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, fboSave);

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

   return false;
}
예제 #9
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)
      _mesa_BindTexture(target, texObj->Name);

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

      _mesa_SamplerParameteri(mipmap->Sampler,
                              GL_TEXTURE_MIN_FILTER,
                              GL_LINEAR_MIPMAP_LINEAR);
      _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
      _mesa_SamplerParameteri(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) {
         _mesa_SamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT,
               GL_SKIP_DECODE_EXT);
      }
   } else {
      _mesa_BindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler);
   }

   assert(mipmap->FBO != 0);
   _mesa_BindFramebuffer(GL_FRAMEBUFFER_EXT, mipmap->FBO);

   _mesa_TexParameteri(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;
      _mesa_TexParameteriv(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;

      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_TexParameteri(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 */
      _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel);

      /* 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, 1, /* width, height never used here */
                                         verts[0].tex,
                                         verts[1].tex,
                                         verts[2].tex,
                                         verts[3].tex);

         /* upload vertex data */
         _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts),
                          verts, GL_DYNAMIC_DRAW_ARB);

         _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstImage, layer);

         /* sanity check */
         if (_mesa_CheckFramebufferStatus(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);
         }

         _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
      }
   }

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

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

   _mesa_meta_end(ctx);

   _mesa_TexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave);
   if (genMipmapSave)
      _mesa_TexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave);
   if (swizzleSaved)
      _mesa_TexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
}
/** A partial implementation of glCopyImageSubData
 *
 * This is a partial implementation of glCopyImageSubData that works only
 * if both textures are uncompressed and the destination texture is
 * renderable.  It uses a slight abuse of a texture view (see make_view) to
 * turn the source texture into the destination texture type and then uses
 * _mesa_meta_BlitFramebuffers to do the copy.
 */
bool
_mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx,
                                         struct gl_texture_image *src_tex_image,
                                         int src_x, int src_y, int src_z,
                                         struct gl_texture_image *dst_tex_image,
                                         int dst_x, int dst_y, int dst_z,
                                         int src_width, int src_height)
{
   GLuint src_view_texture = 0;
   struct gl_texture_image *src_view_tex_image;
   GLuint fbos[2];
   bool success = false;
   GLbitfield mask;
   GLenum status, attachment;

   if (_mesa_is_format_compressed(dst_tex_image->TexFormat))
      return false;

   if (_mesa_is_format_compressed(src_tex_image->TexFormat))
      return false;

   if (src_tex_image->InternalFormat == dst_tex_image->InternalFormat) {
      src_view_tex_image = src_tex_image;
   } else {
      if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture,
                     dst_tex_image->InternalFormat))
         goto cleanup;
   }

   /* We really only need to stash the bound framebuffers. */
   _mesa_meta_begin(ctx, 0);

   _mesa_GenFramebuffers(2, fbos);
   _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);

   switch (_mesa_get_format_base_format(src_tex_image->TexFormat)) {
   case GL_DEPTH_COMPONENT:
      attachment = GL_DEPTH_ATTACHMENT;
      mask = GL_DEPTH_BUFFER_BIT;
      break;
   case GL_DEPTH_STENCIL:
      attachment = GL_DEPTH_STENCIL_ATTACHMENT;
      mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
      break;
   case GL_STENCIL_INDEX:
      attachment = GL_STENCIL_ATTACHMENT;
      mask = GL_STENCIL_BUFFER_BIT;
      break;
   default:
      attachment = GL_COLOR_ATTACHMENT0;
      mask = GL_COLOR_BUFFER_BIT;
      _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
      _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0);
   }

   _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment,
                             src_view_tex_image, src_z);

   status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto meta_end;

   _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment,
                             dst_tex_image, dst_z);

   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto meta_end;

   /* Since we've bound a new draw framebuffer, we need to update its
    * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to
    * be correct.
    */
   _mesa_update_state(ctx);

   /* We skip the core BlitFramebuffer checks for format consistency.
    * We have already created views to ensure that the texture formats
    * match.
    */
   ctx->Driver.BlitFramebuffer(ctx, src_x, src_y,
                               src_x + src_width, src_y + src_height,
                               dst_x, dst_y,
                               dst_x + src_width, dst_y + src_height,
                               mask, GL_NEAREST);

   success = true;

meta_end:
   _mesa_DeleteFramebuffers(2, fbos);
   _mesa_meta_end(ctx);

cleanup:
   _mesa_DeleteTextures(1, &src_view_texture);

   return success;
}
예제 #11
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;
}
예제 #12
0
bool
_mesa_meta_pbo_GetTexSubImage(struct gl_context *ctx, GLuint dims,
                              struct gl_texture_image *tex_image,
                              int xoffset, int yoffset, int zoffset,
                              int width, int height, int depth,
                              GLenum format, GLenum type, const void *pixels,
                              const struct gl_pixelstore_attrib *packing)
{
   GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 };
   int image_height;
   struct gl_texture_image *pbo_tex_image;
   struct gl_renderbuffer *rb = NULL;
   GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format);
   GLenum status, src_base_format;
   bool success = false, clear_channels_to_zero = false;
   float save_clear_color[4];
   int z;

   if (!_mesa_is_bufferobj(packing->BufferObj))
      return false;

   if (format == GL_DEPTH_COMPONENT ||
       format == GL_DEPTH_STENCIL ||
       format == GL_STENCIL_INDEX ||
       format == GL_COLOR_INDEX)
      return false;

   /* Don't use meta path for readpixels in below conditions. */
   if (!tex_image) {
      rb = ctx->ReadBuffer->_ColorReadBuffer;

      /* _mesa_get_readpixels_transfer_ops() includes the cases of read
       * color clamping along with the ctx->_ImageTransferState.
       */
      if (_mesa_get_readpixels_transfer_ops(ctx, rb->Format, format,
                                            type, GL_FALSE))
         return false;

      if (_mesa_need_rgb_to_luminance_conversion(rb->_BaseFormat,
                                                 dstBaseFormat))
         return false;

      /* This function rely on BlitFramebuffer to fill in the pixel data for
       * ReadPixels. But, BlitFrameBuffer doesn't support signed to unsigned
       * or unsigned to signed integer conversions. OpenGL spec expects an
       * invalid operation in that case.
       */
      if (need_signed_unsigned_int_conversion(rb->Format, format, type))
         return false;
   }

   /* For arrays, use a tall (height * depth) 2D texture but taking into
    * account the inter-image padding specified with the image height packing
    * property.
    */
   image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight;

   pbo_tex_image = create_texture_for_pbo(ctx, false, GL_PIXEL_PACK_BUFFER,
                                          dims, width, height, depth,
                                          format, type, pixels, packing,
                                          &pbo, &pbo_tex);
   if (!pbo_tex_image)
      return false;

   _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER |
                           MESA_META_PIXEL_STORE));

   /* GL_CLAMP_FRAGMENT_COLOR doesn't affect ReadPixels and GettexImage */
   if (ctx->Extensions.ARB_color_buffer_float)
      _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);

   _mesa_GenFramebuffers(2, fbos);

   if (tex_image && tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
      assert(depth == 1);
      assert(zoffset == 0);
      depth = height;
      height = 1;
      image_height = 1;
      zoffset = yoffset;
      yoffset = 0;
   }

   /* If we were given a texture, bind it to the read framebuffer.  If not,
    * we're doing a ReadPixels and we should just use whatever framebuffer
    * the client has bound.
    */
   if (tex_image) {
      _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
      _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                tex_image, zoffset);
      /* If this passes on the first layer it should pass on the others */
      status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
      if (status != GL_FRAMEBUFFER_COMPLETE)
         goto fail;
   } else {
      assert(depth == 1);
   }

   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
   _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                             pbo_tex_image, 0);
   /* If this passes on the first layer it should pass on the others */
   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto fail;

   _mesa_update_state(ctx);

   if (_mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
                                  xoffset, yoffset,
                                  xoffset + width, yoffset + height,
                                  0, 0, width, height,
                                  GL_COLOR_BUFFER_BIT, GL_NEAREST))
      goto fail;

   src_base_format = tex_image ?
                     tex_image->_BaseFormat :
                     ctx->ReadBuffer->_ColorReadBuffer->_BaseFormat;

   /* Depending on the base formats involved we might need to rebase some
    * values. For example if we download from a Luminance format to RGBA
    * format, we want G=0 and B=0.
    */
   clear_channels_to_zero =
      _mesa_need_luminance_to_rgb_conversion(src_base_format,
                                             pbo_tex_image->_BaseFormat);

   if (clear_channels_to_zero) {
      memcpy(save_clear_color, ctx->Color.ClearColor.f, 4 * sizeof(float));
      /* Clear the Green, Blue channels. */
      _mesa_ColorMask(GL_FALSE, GL_TRUE, GL_TRUE,
                      src_base_format != GL_LUMINANCE_ALPHA);
      _mesa_ClearColor(0.0, 0.0, 0.0, 1.0);
      _mesa_Clear(GL_COLOR_BUFFER_BIT);
   }

   for (z = 1; z < depth; z++) {
      _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                tex_image, zoffset + z);

      _mesa_update_state(ctx);

      _mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
                                 xoffset, yoffset,
                                 xoffset + width, yoffset + height,
                                 0, z * image_height,
                                 width, z * image_height + height,
                                 GL_COLOR_BUFFER_BIT, GL_NEAREST);
      if (clear_channels_to_zero)
         _mesa_Clear(GL_COLOR_BUFFER_BIT);
   }

   /* Unmask the color channels and restore the saved clear color values. */
   if (clear_channels_to_zero) {
      _mesa_ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
      _mesa_ClearColor(save_clear_color[0], save_clear_color[1],
                       save_clear_color[2], save_clear_color[3]);
   }

   success = true;

fail:
   _mesa_DeleteFramebuffers(2, fbos);
   _mesa_DeleteTextures(1, &pbo_tex);
   _mesa_DeleteBuffers(1, &pbo);

   _mesa_meta_end(ctx);

   return success;
}
예제 #13
0
bool
_mesa_meta_pbo_TexSubImage(struct gl_context *ctx, GLuint dims,
                           struct gl_texture_image *tex_image,
                           int xoffset, int yoffset, int zoffset,
                           int width, int height, int depth,
                           GLenum format, GLenum type, const void *pixels,
                           bool allocate_storage, bool create_pbo,
                           const struct gl_pixelstore_attrib *packing)
{
   GLuint pbo = 0, pbo_tex = 0, fbos[2] = { 0, 0 };
   int image_height;
   struct gl_texture_image *pbo_tex_image;
   GLenum status;
   bool success = false;
   int z;

   if (!_mesa_is_bufferobj(packing->BufferObj) &&
       (!create_pbo || pixels == NULL))
      return false;

   if (format == GL_DEPTH_COMPONENT ||
       format == GL_DEPTH_STENCIL ||
       format == GL_STENCIL_INDEX ||
       format == GL_COLOR_INDEX)
      return false;

   if (ctx->_ImageTransferState)
      return false;

   /* This function rely on BlitFramebuffer to fill in the pixel data for
    * glTex[Sub]Image*D. But, BlitFrameBuffer doesn't support signed to
    * unsigned or unsigned to signed integer conversions.
    */
   if (need_signed_unsigned_int_conversion(tex_image->TexFormat, format, type))
      return false;

   /* For arrays, use a tall (height * depth) 2D texture but taking into
    * account the inter-image padding specified with the image height packing
    * property.
    */
   image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight;

   pbo_tex_image = create_texture_for_pbo(ctx, create_pbo,
                                          GL_PIXEL_UNPACK_BUFFER,
                                          dims, width, height, depth,
                                          format, type, pixels, packing,
                                          &pbo, &pbo_tex);
   if (!pbo_tex_image)
      return false;

   if (allocate_storage)
      ctx->Driver.AllocTextureImageBuffer(ctx, tex_image);

   _mesa_meta_begin(ctx, ~(MESA_META_PIXEL_TRANSFER |
                           MESA_META_PIXEL_STORE));

   _mesa_GenFramebuffers(2, fbos);
   _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);

   if (tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
      assert(depth == 1);
      assert(zoffset == 0);
      depth = height;
      height = 1;
      image_height = 1;
      zoffset = yoffset;
      yoffset = 0;
   }

   _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                             pbo_tex_image, 0);
   /* If this passes on the first layer it should pass on the others */
   status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto fail;

   _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                             tex_image, zoffset);
   /* If this passes on the first layer it should pass on the others */
   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
   if (status != GL_FRAMEBUFFER_COMPLETE)
      goto fail;

   _mesa_update_state(ctx);

   if (_mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
                                  0, 0, width, height,
                                  xoffset, yoffset,
                                  xoffset + width, yoffset + height,
                                  GL_COLOR_BUFFER_BIT, GL_NEAREST))
      goto fail;

   for (z = 1; z < depth; z++) {
      _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                                tex_image, zoffset + z);

      _mesa_update_state(ctx);

      _mesa_meta_BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
                                 0, z * image_height,
                                 width, z * image_height + height,
                                 xoffset, yoffset,
                                 xoffset + width, yoffset + height,
                                 GL_COLOR_BUFFER_BIT, GL_NEAREST);
   }

   success = true;

fail:
   _mesa_DeleteFramebuffers(2, fbos);
   _mesa_DeleteTextures(1, &pbo_tex);
   _mesa_DeleteBuffers(1, &pbo);

   _mesa_meta_end(ctx);

   return success;
}