void st_generate_mipmap(GLcontext *ctx, GLenum target, struct gl_texture_object *texObj) { struct st_context *st = ctx->st; struct pipe_texture *pt = st_get_texobj_texture(texObj); const uint baseLevel = texObj->BaseLevel; uint lastLevel; uint dstLevel; if (!pt) return; lastLevel = pt->last_level; if (!st_render_mipmap(st, target, pt, baseLevel, lastLevel)) { fallback_generate_mipmap(ctx, target, texObj); } /* Fill in the Mesa gl_texture_image fields */ for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { const uint srcLevel = dstLevel - 1; const struct gl_texture_image *srcImage = _mesa_get_tex_image(ctx, texObj, target, srcLevel); struct gl_texture_image *dstImage; struct st_texture_image *stImage; uint dstWidth = pt->width[dstLevel]; uint dstHeight = pt->height[dstLevel]; uint dstDepth = pt->depth[dstLevel]; uint border = srcImage->Border; dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel); if (!dstImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); return; } /* Free old image data */ if (dstImage->Data) ctx->Driver.FreeTexImageData(ctx, dstImage); /* initialize new image */ _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight, dstDepth, border, srcImage->InternalFormat); dstImage->TexFormat = srcImage->TexFormat; stImage = (struct st_texture_image *) dstImage; pipe_texture_reference(&stImage->pt, pt); } }
GLboolean _mesa_meta_bind_rb_as_tex_image(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint *tex, struct gl_texture_object **texObj, GLenum *target) { struct gl_texture_image *texImage; if (rb->NumSamples > 1) *target = GL_TEXTURE_2D_MULTISAMPLE; else *target = GL_TEXTURE_2D; _mesa_GenTextures(1, tex); _mesa_BindTexture(*target, *tex); *texObj = _mesa_lookup_texture(ctx, *tex); texImage = _mesa_get_tex_image(ctx, *texObj, *target, 0); if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) { _mesa_DeleteTextures(1, tex); return false; } if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) { rb->NeedsFinishRenderTexture = true; ctx->Driver.FinishRenderTexture(ctx, rb); } return true; }
/** * Compute the expected number of mipmap levels in the texture given * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/ * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap * levels should be generated. */ static GLuint compute_num_levels(struct gl_context *ctx, struct gl_texture_object *texObj, GLenum target) { if (target == GL_TEXTURE_RECTANGLE_ARB) { return 1; } else { const struct gl_texture_image *baseImage = _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel); GLuint size, numLevels; size = MAX2(baseImage->Width2, baseImage->Height2); size = MAX2(size, baseImage->Depth2); numLevels = texObj->BaseLevel; while (size > 0) { numLevels++; size >>= 1; } numLevels = MIN2(numLevels, texObj->MaxLevel + 1); assert(numLevels >= 1); return numLevels; } }
/** * Clear all fields of texture object to zeros. Used for proxy texture tests. */ static void clear_image_fields(struct gl_context *ctx, GLuint dims, struct gl_texture_object *texObj) { const GLenum target = texObj->Target; const GLuint numFaces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; GLint level; GLuint face; for (level = 0; level < Elements(texObj->Image[0]); level++) { for (face = 0; face < numFaces; face++) { const GLenum faceTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target; struct gl_texture_image *texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, level); if (!texImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims); return; } _mesa_init_teximage_fields(ctx, target, texImage, 0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE); } } }
/** * Create a texture image that wraps a renderbuffer. */ static struct gl_texture_image * wrap_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) { GLenum texTarget; struct gl_texture_object *texObj; struct gl_texture_image *texImage; if (rb->NumSamples > 1) texTarget = GL_TEXTURE_2D_MULTISAMPLE; else texTarget = GL_TEXTURE_2D; /* Texture ID is not significant since it never goes into the hash table */ texObj = ctx->Driver.NewTextureObject(ctx, 0, texTarget); assert(texObj); if (!texObj) return NULL; texImage = _mesa_get_tex_image(ctx, texObj, texTarget, 0); assert(texImage); if (!texImage) return NULL; if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) { _mesa_problem(ctx, "Failed to create texture from renderbuffer"); return NULL; } if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) { rb->NeedsFinishRenderTexture = true; ctx->Driver.FinishRenderTexture(ctx, rb); } return texImage; }
/* This function makes a texture view without bothering with all of the API * checks. Most of them are the same for CopyTexSubImage so checking would * be redundant. The one major difference is that we don't check for * whether the texture is immutable or not. However, since the view will * be created and then immediately destroyed, this should not be a problem. */ static bool make_view(struct gl_context *ctx, struct gl_texture_image *tex_image, struct gl_texture_image **view_tex_image, GLuint *view_tex_name, GLenum internal_format) { struct gl_texture_object *tex_obj = tex_image->TexObject; struct gl_texture_object *view_tex_obj; mesa_format tex_format; /* Set up the new texture object */ _mesa_GenTextures(1, view_tex_name); view_tex_obj = _mesa_lookup_texture(ctx, *view_tex_name); if (!view_tex_obj) return false; tex_format = _mesa_choose_texture_format(ctx, view_tex_obj, tex_obj->Target, 0, internal_format, GL_NONE, GL_NONE); if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 0, tex_format, tex_image->Width, tex_image->Height, tex_image->Depth, 0)) { _mesa_DeleteTextures(1, view_tex_name); *view_tex_name = 0; return false; } view_tex_obj->Target = tex_obj->Target; *view_tex_image = _mesa_get_tex_image(ctx, view_tex_obj, tex_obj->Target, 0); if (!*view_tex_image) { _mesa_DeleteTextures(1, view_tex_name); *view_tex_name = 0; return false; } _mesa_init_teximage_fields(ctx, *view_tex_image, tex_image->Width, tex_image->Height, tex_image->Depth, 0, internal_format, tex_format); view_tex_obj->MinLevel = tex_image->Level; view_tex_obj->NumLevels = 1; view_tex_obj->MinLayer = tex_obj->MinLayer; view_tex_obj->NumLayers = tex_obj->NumLayers; view_tex_obj->Immutable = tex_obj->Immutable; view_tex_obj->ImmutableLevels = tex_obj->ImmutableLevels; view_tex_obj->Target = tex_obj->Target; if (ctx->Driver.TextureView != NULL && !ctx->Driver.TextureView(ctx, view_tex_obj, tex_obj)) { _mesa_DeleteTextures(1, view_tex_name); *view_tex_name = 0; return false; /* driver recorded error */ } return true; }
/** * Bind a pipe surface to a texture object. After the call, * the texture object is marked dirty and will be (re-)validated. * * If this is the first surface bound, the texture object is said to * switch from normal to surface based. It will be cleared first in * this case. * * \param ps pipe surface to be unbound * \param target texture target * \param level image level * \param format internal format of the texture */ int st_bind_texture_surface(struct pipe_surface *ps, int target, int level, enum pipe_format format) { GET_CURRENT_CONTEXT(ctx); const GLuint unit = ctx->Texture.CurrentUnit; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; struct st_texture_object *stObj; struct st_texture_image *stImage; GLenum internalFormat; switch (target) { case ST_TEXTURE_2D: target = GL_TEXTURE_2D; break; case ST_TEXTURE_RECT: target = GL_TEXTURE_RECTANGLE_ARB; break; default: return 0; } /* map pipe format to base format for now */ if (pf_get_component_bits(format, PIPE_FORMAT_COMP_A) > 0) internalFormat = GL_RGBA; else internalFormat = GL_RGB; texObj = _mesa_select_tex_object(ctx, texUnit, target); _mesa_lock_texture(ctx, texObj); stObj = st_texture_object(texObj); /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texImage = _mesa_get_tex_image(ctx, texObj, target, level); stImage = st_texture_image(texImage); _mesa_init_teximage_fields(ctx, target, texImage, ps->width, ps->height, 1, 0, internalFormat); texImage->TexFormat = st_ChooseTextureFormat(ctx, internalFormat, GL_RGBA, GL_UNSIGNED_BYTE); _mesa_set_fetch_functions(texImage, 2); pipe_texture_reference(&stImage->pt, ps->texture); _mesa_dirty_texobj(ctx, texObj, GL_TRUE); _mesa_unlock_texture(ctx, texObj); return 1; }
void intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint texture_format, __DRIdrawable *dPriv) { struct gl_framebuffer *fb = dPriv->driverPrivate; struct brw_context *brw = pDRICtx->driverPrivate; struct gl_context *ctx = &brw->ctx; struct intel_renderbuffer *rb; struct gl_texture_object *texObj; struct gl_texture_image *texImage; int level = 0, internalFormat = 0; mesa_format texFormat = MESA_FORMAT_NONE; texObj = _mesa_get_current_tex_object(ctx, target); if (!texObj) return; if (dPriv->lastStamp != dPriv->dri2.stamp || !pDRICtx->driScreenPriv->dri2.useInvalidate) intel_update_renderbuffers(pDRICtx, dPriv); rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); /* If the miptree isn't set, then intel_update_renderbuffers was unable * to get the BO for the drawable from the window system. */ if (!rb || !rb->mt) return; if (rb->mt->cpp == 4) { if (texture_format == __DRI_TEXTURE_FORMAT_RGB) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_B8G8R8X8_UNORM; } else { internalFormat = GL_RGBA; texFormat = MESA_FORMAT_B8G8R8A8_UNORM; } } else if (rb->mt->cpp == 2) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_B5G6R5_UNORM; } _mesa_lock_texture(&brw->ctx, texObj); texImage = _mesa_get_tex_image(ctx, texObj, target, level); intel_miptree_make_shareable(brw, rb->mt); intel_set_texture_image_bo(ctx, texImage, rb->mt->bo, target, internalFormat, texFormat, 0, rb->Base.Base.Width, rb->Base.Base.Height, rb->mt->pitch, 0, 0, 0); _mesa_unlock_texture(&brw->ctx, texObj); }
void intelSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint texture_format, __DRIdrawable *dPriv) { struct gl_framebuffer *fb = dPriv->driverPrivate; struct intel_context *intel = pDRICtx->driverPrivate; struct gl_context *ctx = &intel->ctx; struct intel_texture_object *intelObj; struct intel_renderbuffer *rb; struct gl_texture_object *texObj; struct gl_texture_image *texImage; int level = 0, internalFormat = 0; gl_format texFormat = MESA_FORMAT_NONE; texObj = _mesa_get_current_tex_object(ctx, target); intelObj = intel_texture_object(texObj); if (!intelObj) return; if (dPriv->lastStamp != dPriv->dri2.stamp || !pDRICtx->driScreenPriv->dri2.useInvalidate) intel_update_renderbuffers(pDRICtx, dPriv); rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); /* If the region isn't set, then intel_update_renderbuffers was unable * to get the buffers for the drawable. */ if (!rb || !rb->mt) return; if (rb->mt->cpp == 4) { if (texture_format == __DRI_TEXTURE_FORMAT_RGB) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_XRGB8888; } else { internalFormat = GL_RGBA; texFormat = MESA_FORMAT_ARGB8888; } } else if (rb->mt->cpp == 2) { internalFormat = GL_RGB; texFormat = MESA_FORMAT_RGB565; } _mesa_lock_texture(&intel->ctx, texObj); texImage = _mesa_get_tex_image(ctx, texObj, target, level); intel_set_texture_image_region(ctx, texImage, rb->mt->region, target, internalFormat, texFormat, 0, rb->mt->region->width, rb->mt->region->height, 0, 0); _mesa_unlock_texture(&intel->ctx, texObj); }
/** Helper to get a particular texture image in a texture object */ static struct gl_texture_image * get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj, GLuint face, GLuint level) { const GLenum faceTarget = (texObj->Target == GL_TEXTURE_CUBE_MAP || texObj->Target == GL_PROXY_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : texObj->Target; return _mesa_get_tex_image(ctx, texObj, faceTarget, level); }
void GLAPIENTRY _mesa_VDPAUMapSurfacesNV(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_get_tex_image(ctx, tex, surf->target, 0); if (!image) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "VDPAUMapSurfacesNV"); _mesa_unlock_texture(ctx, tex); return; } ctx->Driver.FreeTextureImageBuffer(ctx, image); ctx->Driver.VDPAUMapSurface(ctx, surf->target, surf->access, surf->output, tex, image, surf->vdpSurface, j); _mesa_unlock_texture(ctx, tex); } surf->state = GL_SURFACE_MAPPED_NV; } }
/** Redirect rendering into stfb's surface to a texture image */ int st_bind_teximage(struct st_framebuffer *stfb, uint surfIndex, int target, int format, int level) { GET_CURRENT_CONTEXT(ctx); struct st_context *st = ctx->st; struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; const GLuint unit = ctx->Texture.CurrentUnit; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; struct st_texture_image *stImage; struct st_renderbuffer *strb; GLint face = 0, slice = 0; assert(surfIndex <= ST_SURFACE_DEPTH); strb = st_renderbuffer(stfb->Base.Attachment[surfIndex].Renderbuffer); if (strb->texture_save || strb->surface_save) { /* Error! */ return 0; } if (target == ST_TEXTURE_2D) { texObj = texUnit->CurrentTex[TEXTURE_2D_INDEX]; texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, level); stImage = st_texture_image(texImage); } else { /* unsupported target */ return 0; } st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL); /* save the renderbuffer's surface/texture info */ pipe_texture_reference(&strb->texture_save, strb->texture); pipe_surface_reference(&strb->surface_save, strb->surface); /* plug in new surface/texture info */ pipe_texture_reference(&strb->texture, stImage->pt); strb->surface = screen->get_tex_surface(screen, strb->texture, face, level, slice, (PIPE_BUFFER_USAGE_GPU_READ | PIPE_BUFFER_USAGE_GPU_WRITE)); st->dirty.st |= ST_NEW_FRAMEBUFFER; return 1; }
/** * Return pointer to a default/fallback texture. * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1). * That's the value a sampler should get when sampling from an * incomplete texture. */ struct gl_texture_object * _mesa_get_fallback_texture(struct gl_context *ctx) { if (!ctx->Shared->FallbackTex) { /* create fallback texture now */ static GLubyte texels[8 * 8][4]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; gl_format texFormat; GLuint i; for (i = 0; i < 8 * 8; i++) { texels[i][0] = texels[i][1] = texels[i][2] = 0x0; texels[i][3] = 0xff; } /* create texture object */ texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D); assert(texObj->RefCount == 1); texObj->Sampler.MinFilter = GL_NEAREST; texObj->Sampler.MagFilter = GL_NEAREST; /* create level[0] texture image */ texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0); texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); /* init the image fields */ _mesa_init_teximage_fields(ctx, texImage, 8, 8, 1, 0, GL_RGBA, texFormat); ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); /* set image data */ ctx->Driver.TexImage2D(ctx, texImage, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, texels, &ctx->DefaultPacking); _mesa_test_texobj_completeness(ctx, texObj); assert(texObj->_Complete); ctx->Shared->FallbackTex = texObj; } return ctx->Shared->FallbackTex; }
/** * Compute the expected number of mipmap levels in the texture given * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/ * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap * levels should be generated. */ static GLuint compute_num_levels(struct gl_context *ctx, struct gl_texture_object *texObj, GLenum target) { const struct gl_texture_image *baseImage; GLuint numLevels; baseImage = _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel); numLevels = texObj->BaseLevel + baseImage->MaxNumLevels; numLevels = MIN2(numLevels, (GLuint) texObj->MaxLevel + 1); assert(numLevels >= 1); return numLevels; }
/** * Initialize new texture's gl_texture_image structures. Will not call driver * to allocate new space, simply record relevant layer, face, format, etc. * \return GL_FALSE if any error, GL_TRUE otherwise. */ static GLboolean initialize_texture_fields(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj, GLint levels, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, mesa_format texFormat) { const GLuint numFaces = _mesa_num_tex_faces(target); GLint level, levelWidth = width, levelHeight = height, levelDepth = depth; GLuint face; /* Pretend we are bound to initialize the gl_texture_image structs */ texObj->Target = target; /* Set up all the texture object's gl_texture_images */ for (level = 0; level < levels; level++) { for (face = 0; face < numFaces; face++) { struct gl_texture_image *texImage; GLenum faceTarget = target; if (target == GL_TEXTURE_CUBE_MAP) faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, level); if (!texImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage"); return GL_FALSE; } _mesa_init_teximage_fields(ctx, texImage, levelWidth, levelHeight, levelDepth, 0, internalFormat, texFormat); } _mesa_next_mipmap_level_size(target, 0, levelWidth, levelHeight, levelDepth, &levelWidth, &levelHeight, &levelDepth); } /* "unbind" */ texObj->Target = 0; return GL_TRUE; }
/** * Unbind a pipe surface from a texture object. After the call, * the texture object is marked dirty and will be (re-)validated. * * \param ps pipe surface to be unbound * \param target texture target * \param level image level */ int st_unbind_texture_surface(struct pipe_surface *ps, int target, int level) { GET_CURRENT_CONTEXT(ctx); const GLuint unit = ctx->Texture.CurrentUnit; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; struct st_texture_object *stObj; struct st_texture_image *stImage; switch (target) { case ST_TEXTURE_2D: target = GL_TEXTURE_2D; break; case ST_TEXTURE_RECT: target = GL_TEXTURE_RECTANGLE_ARB; break; default: return 0; } texObj = _mesa_select_tex_object(ctx, texUnit, target); _mesa_lock_texture(ctx, texObj); texImage = _mesa_get_tex_image(ctx, texObj, target, level); stObj = st_texture_object(texObj); stImage = st_texture_image(texImage); /* Make sure the pipe surface is still bound. The texture object is still * considered surface based even if this is the last bound surface. */ if (stImage->pt == ps->texture) { pipe_texture_reference(&stImage->pt, NULL); _mesa_clear_texture_image(ctx, texImage); _mesa_dirty_texobj(ctx, texObj, GL_TRUE); } _mesa_unlock_texture(ctx, texObj); return 1; }
static void swrastSetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint texture_format, __DRIdrawable *dPriv) { struct dri_context *dri_ctx; int x, y, w, h; __DRIscreen *sPriv = dPriv->driScreenPriv; struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; struct swrast_texture_image *swImage; uint32_t internalFormat; gl_format texFormat; dri_ctx = pDRICtx->driverPrivate; internalFormat = (texture_format == __DRI_TEXTURE_FORMAT_RGB ? 3 : 4); texUnit = _mesa_get_current_tex_unit(&dri_ctx->Base); texObj = _mesa_select_tex_object(&dri_ctx->Base, texUnit, target); texImage = _mesa_get_tex_image(&dri_ctx->Base, texObj, target, 0); swImage = swrast_texture_image(texImage); _mesa_lock_texture(&dri_ctx->Base, texObj); sPriv->swrast_loader->getDrawableInfo(dPriv, &x, &y, &w, &h, dPriv->loaderPrivate); if (texture_format == __DRI_TEXTURE_FORMAT_RGB) texFormat = MESA_FORMAT_XRGB8888; else texFormat = MESA_FORMAT_ARGB8888; _mesa_init_teximage_fields(&dri_ctx->Base, texImage, w, h, 1, 0, internalFormat, texFormat); sPriv->swrast_loader->getImage(dPriv, x, y, w, h, (char *)swImage->Buffer, dPriv->loaderPrivate); _mesa_unlock_texture(&dri_ctx->Base, texObj); }
static boolean st_context_teximage(struct st_context_iface *stctxi, enum st_texture_type tex_type, int level, enum pipe_format pipe_format, struct pipe_resource *tex, boolean mipmap) { struct st_context *st = (struct st_context *) stctxi; struct gl_context *ctx = st->ctx; struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); struct gl_texture_object *texObj; struct gl_texture_image *texImage; struct st_texture_object *stObj; struct st_texture_image *stImage; GLenum internalFormat; GLuint width, height, depth; GLenum target; switch (tex_type) { case ST_TEXTURE_1D: target = GL_TEXTURE_1D; break; case ST_TEXTURE_2D: target = GL_TEXTURE_2D; break; case ST_TEXTURE_3D: target = GL_TEXTURE_3D; break; case ST_TEXTURE_RECT: target = GL_TEXTURE_RECTANGLE_ARB; break; default: return FALSE; } texObj = _mesa_select_tex_object(ctx, texUnit, target); _mesa_lock_texture(ctx, texObj); stObj = st_texture_object(texObj); /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texImage = _mesa_get_tex_image(ctx, texObj, target, level); stImage = st_texture_image(texImage); if (tex) { gl_format texFormat = st_pipe_format_to_mesa_format(pipe_format); if (util_format_has_alpha(tex->format)) internalFormat = GL_RGBA; else internalFormat = GL_RGB; _mesa_init_teximage_fields(ctx, texImage, tex->width0, tex->height0, 1, 0, internalFormat, texFormat); width = tex->width0; height = tex->height0; depth = tex->depth0; /* grow the image size until we hit level = 0 */ while (level > 0) { if (width != 1) width <<= 1; if (height != 1) height <<= 1; if (depth != 1) depth <<= 1; level--; } } else { _mesa_clear_texture_image(ctx, texImage); width = height = depth = 0; } pipe_resource_reference(&stImage->pt, tex); stObj->width0 = width; stObj->height0 = height; stObj->depth0 = depth; stObj->surface_format = pipe_format; _mesa_dirty_texobj(ctx, texObj, GL_TRUE); _mesa_unlock_texture(ctx, texObj); return TRUE; }
/** * Called via ctx->Driver.GenerateMipmap(). */ void st_generate_mipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct pipe_resource *pt = st_get_texobj_resource(texObj); const uint baseLevel = texObj->BaseLevel; uint lastLevel, first_layer, last_layer; uint dstLevel; if (!pt) return; /* not sure if this ultimately actually should work, but we're not supporting multisampled textures yet. */ assert(pt->nr_samples < 2); /* find expected last mipmap level to generate*/ lastLevel = compute_num_levels(ctx, texObj, target) - 1; if (lastLevel == 0) return; /* The texture isn't in a "complete" state yet so set the expected * lastLevel here, since it won't get done in st_finalize_texture(). */ stObj->lastLevel = lastLevel; if (pt->last_level < lastLevel) { /* The current gallium texture doesn't have space for all the * mipmap levels we need to generate. So allocate a new texture. */ struct pipe_resource *oldTex = stObj->pt; /* create new texture with space for more levels */ stObj->pt = st_texture_create(st, oldTex->target, oldTex->format, lastLevel, oldTex->width0, oldTex->height0, oldTex->depth0, oldTex->array_size, 0, oldTex->bind); /* This will copy the old texture's base image into the new texture * which we just allocated. */ st_finalize_texture(ctx, st->pipe, texObj); /* release the old tex (will likely be freed too) */ pipe_resource_reference(&oldTex, NULL); st_texture_release_all_sampler_views(stObj); } else { /* Make sure that the base texture image data is present in the * texture buffer. */ st_finalize_texture(ctx, st->pipe, texObj); } pt = stObj->pt; assert(pt->last_level >= lastLevel); if (pt->target == PIPE_TEXTURE_CUBE) { first_layer = last_layer = _mesa_tex_target_to_face(target); } else { first_layer = 0; last_layer = util_max_layer(pt, baseLevel); } /* Try to generate the mipmap by rendering/texturing. If that fails, * use the software fallback. */ if (!util_gen_mipmap(st->pipe, pt, pt->format, baseLevel, lastLevel, first_layer, last_layer, PIPE_TEX_FILTER_LINEAR)) { _mesa_generate_mipmap(ctx, target, texObj); } /* Fill in the Mesa gl_texture_image fields */ for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { const uint srcLevel = dstLevel - 1; const struct gl_texture_image *srcImage = _mesa_get_tex_image(ctx, texObj, target, srcLevel); struct gl_texture_image *dstImage; struct st_texture_image *stImage; uint border = srcImage->Border; uint dstWidth, dstHeight, dstDepth; dstWidth = u_minify(pt->width0, dstLevel); if (texObj->Target == GL_TEXTURE_1D_ARRAY) { dstHeight = pt->array_size; } else { dstHeight = u_minify(pt->height0, dstLevel); } if (texObj->Target == GL_TEXTURE_2D_ARRAY || texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) { dstDepth = pt->array_size; } else { dstDepth = u_minify(pt->depth0, dstLevel); } dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel); if (!dstImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); return; } /* Free old image data */ ctx->Driver.FreeTextureImageBuffer(ctx, dstImage); /* initialize new image */ _mesa_init_teximage_fields(ctx, dstImage, dstWidth, dstHeight, dstDepth, border, srcImage->InternalFormat, srcImage->TexFormat); stImage = st_texture_image(dstImage); pipe_resource_reference(&stImage->pt, pt); } }
void r300SetTexBuffer2(__DRIcontext *pDRICtx, GLint target, GLint glx_texture_format, __DRIdrawable *dPriv) { struct gl_texture_unit *texUnit; struct gl_texture_object *texObj; struct gl_texture_image *texImage; struct radeon_renderbuffer *rb; radeon_texture_image *rImage; radeonContextPtr radeon; r300ContextPtr rmesa; struct radeon_framebuffer *rfb; radeonTexObjPtr t; uint32_t pitch_val; uint32_t internalFormat, type, format; type = GL_BGRA; format = GL_UNSIGNED_BYTE; internalFormat = (glx_texture_format == GLX_TEXTURE_FORMAT_RGB_EXT ? 3 : 4); radeon = pDRICtx->driverPrivate; rmesa = pDRICtx->driverPrivate; rfb = dPriv->driverPrivate; texUnit = &radeon->glCtx->Texture.Unit[radeon->glCtx->Texture.CurrentUnit]; texObj = _mesa_select_tex_object(radeon->glCtx, texUnit, target); texImage = _mesa_get_tex_image(radeon->glCtx, texObj, target, 0); rImage = get_radeon_texture_image(texImage); t = radeon_tex_obj(texObj); if (t == NULL) { return; } radeon_update_renderbuffers(pDRICtx, dPriv); /* back & depth buffer are useless free them right away */ rb = (void*)rfb->base.Attachment[BUFFER_DEPTH].Renderbuffer; if (rb && rb->bo) { radeon_bo_unref(rb->bo); rb->bo = NULL; } rb = (void*)rfb->base.Attachment[BUFFER_BACK_LEFT].Renderbuffer; if (rb && rb->bo) { radeon_bo_unref(rb->bo); rb->bo = NULL; } rb = rfb->color_rb[0]; if (rb->bo == NULL) { /* Failed to BO for the buffer */ return; } _mesa_lock_texture(radeon->glCtx, texObj); if (t->bo) { radeon_bo_unref(t->bo); t->bo = NULL; } if (rImage->bo) { radeon_bo_unref(rImage->bo); rImage->bo = NULL; } radeon_miptree_unreference(&t->mt); radeon_miptree_unreference(&rImage->mt); _mesa_init_teximage_fields(radeon->glCtx, target, texImage, rb->base.Width, rb->base.Height, 1, 0, rb->cpp); texImage->RowStride = rb->pitch / rb->cpp; rImage->bo = rb->bo; radeon_bo_ref(rImage->bo); t->bo = rb->bo; radeon_bo_ref(t->bo); t->tile_bits = 0; t->image_override = GL_TRUE; t->override_offset = 0; t->pp_txpitch &= (1 << 13) -1; pitch_val = rb->pitch; switch (rb->cpp) { case 4: if (glx_texture_format == GLX_TEXTURE_FORMAT_RGB_EXT) t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8); else t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, W, W8Z8Y8X8); t->pp_txfilter |= tx_table[2].filter; pitch_val /= 4; break; case 3: default: t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, W8Z8Y8X8); t->pp_txfilter |= tx_table[4].filter; pitch_val /= 4; break; case 2: t->pp_txformat = R300_EASY_TX_FORMAT(X, Y, Z, ONE, Z5Y6X5); t->pp_txfilter |= tx_table[5].filter; pitch_val /= 2; break; } pitch_val--; t->pp_txsize = (((R300_TX_WIDTHMASK_MASK & ((rb->base.Width - 1) << R300_TX_WIDTHMASK_SHIFT))) | ((R300_TX_HEIGHTMASK_MASK & ((rb->base.Height - 1) << R300_TX_HEIGHTMASK_SHIFT)))); t->pp_txsize |= R300_TX_SIZE_TXPITCH_EN; t->pp_txpitch |= pitch_val; if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) { if (rb->base.Width > 2048) t->pp_txpitch |= R500_TXWIDTH_BIT11; else t->pp_txpitch &= ~R500_TXWIDTH_BIT11; if (rb->base.Height > 2048) t->pp_txpitch |= R500_TXHEIGHT_BIT11; else t->pp_txpitch &= ~R500_TXHEIGHT_BIT11; } t->validated = GL_TRUE; _mesa_unlock_texture(radeon->glCtx, texObj); return; }
static struct gl_texture_image * create_texture_for_pbo(struct gl_context *ctx, bool create_pbo, GLenum pbo_target, int width, int height, GLenum format, GLenum type, const void *pixels, const struct gl_pixelstore_attrib *packing, GLuint *tmp_pbo, GLuint *tmp_tex) { uint32_t pbo_format; GLenum internal_format; unsigned row_stride; struct gl_buffer_object *buffer_obj; struct gl_texture_object *tex_obj; struct gl_texture_image *tex_image; bool read_only; if (packing->SwapBytes || packing->LsbFirst || packing->Invert) return NULL; pbo_format = _mesa_format_from_format_and_type(format, type); if (_mesa_format_is_mesa_array_format(pbo_format)) pbo_format = _mesa_format_from_array_format(pbo_format); if (!pbo_format || !ctx->TextureFormatSupported[pbo_format]) return NULL; /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */ pixels = _mesa_image_address3d(packing, pixels, width, height, format, type, 0, 0, 0); row_stride = _mesa_image_row_stride(packing, width, format, type); if (_mesa_is_bufferobj(packing->BufferObj)) { *tmp_pbo = 0; buffer_obj = packing->BufferObj; } else { bool is_pixel_pack = pbo_target == GL_PIXEL_PACK_BUFFER; assert(create_pbo); _mesa_GenBuffers(1, tmp_pbo); /* We are not doing this inside meta_begin/end. However, we know the * client doesn't have the given target bound, so we can go ahead and * squash it. We'll set it back when we're done. */ _mesa_BindBuffer(pbo_target, *tmp_pbo); /* In case of GL_PIXEL_PACK_BUFFER, pass null pointer for the pixel * data to avoid unnecessary data copying in _mesa_BufferData(). */ if (is_pixel_pack) _mesa_BufferData(pbo_target, row_stride * height, NULL, GL_STREAM_READ); else _mesa_BufferData(pbo_target, row_stride * height, pixels, GL_STREAM_DRAW); buffer_obj = packing->BufferObj; pixels = NULL; _mesa_BindBuffer(pbo_target, 0); } _mesa_GenTextures(1, tmp_tex); tex_obj = _mesa_lookup_texture(ctx, *tmp_tex); _mesa_initialize_texture_object(ctx, tex_obj, *tmp_tex, GL_TEXTURE_2D); /* This must be set after _mesa_initialize_texture_object, not before. */ tex_obj->Immutable = GL_TRUE; /* This is required for interactions with ARB_texture_view. */ tex_obj->NumLayers = 1; internal_format = _mesa_get_format_base_format(pbo_format); tex_image = _mesa_get_tex_image(ctx, tex_obj, tex_obj->Target, 0); _mesa_init_teximage_fields(ctx, tex_image, width, height, 1, 0, internal_format, pbo_format); read_only = pbo_target == GL_PIXEL_UNPACK_BUFFER; if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, tex_obj, buffer_obj, (intptr_t)pixels, row_stride, read_only)) { _mesa_DeleteTextures(1, tmp_tex); _mesa_DeleteBuffers(1, tmp_pbo); return NULL; } return tex_image; }
/** * 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; }
/** * Return pointer to a default/fallback texture of the given type/target. * The texture is an RGBA texture with all texels = (0,0,0,1). * That's the value a GLSL sampler should get when sampling from an * incomplete texture. */ struct gl_texture_object * _mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex) { if (!ctx->Shared->FallbackTex[tex]) { /* create fallback texture now */ const GLsizei width = 1, height = 1, depth = 1; GLubyte texel[4]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; gl_format texFormat; GLuint dims, face, numFaces = 1; GLenum target; texel[0] = texel[1] = texel[2] = 0x0; texel[3] = 0xff; switch (tex) { case TEXTURE_2D_ARRAY_INDEX: dims = 3; target = GL_TEXTURE_2D_ARRAY; break; case TEXTURE_1D_ARRAY_INDEX: dims = 2; target = GL_TEXTURE_1D_ARRAY; break; case TEXTURE_CUBE_INDEX: dims = 2; target = GL_TEXTURE_CUBE_MAP; numFaces = 6; break; case TEXTURE_3D_INDEX: dims = 3; target = GL_TEXTURE_3D; break; case TEXTURE_RECT_INDEX: dims = 2; target = GL_TEXTURE_RECTANGLE; break; case TEXTURE_2D_INDEX: dims = 2; target = GL_TEXTURE_2D; break; case TEXTURE_1D_INDEX: dims = 1; target = GL_TEXTURE_1D; break; case TEXTURE_BUFFER_INDEX: dims = 0; target = GL_TEXTURE_BUFFER; break; case TEXTURE_EXTERNAL_INDEX: default: /* no-op */ return NULL; } /* create texture object */ texObj = ctx->Driver.NewTextureObject(ctx, 0, target); if (!texObj) return NULL; assert(texObj->RefCount == 1); texObj->Sampler.MinFilter = GL_NEAREST; texObj->Sampler.MagFilter = GL_NEAREST; texFormat = ctx->Driver.ChooseTextureFormat(ctx, target, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); /* need a loop here just for cube maps */ for (face = 0; face < numFaces; face++) { GLenum faceTarget; if (target == GL_TEXTURE_CUBE_MAP) faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; else faceTarget = target; /* initialize level[0] texture image */ texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0); _mesa_init_teximage_fields(ctx, texImage, width, (dims > 1) ? height : 1, (dims > 2) ? depth : 1, 0, /* border */ GL_RGBA, texFormat); ctx->Driver.TexImage(ctx, dims, texImage, GL_RGBA, GL_UNSIGNED_BYTE, texel, &ctx->DefaultPacking); } _mesa_test_texobj_completeness(ctx, texObj); assert(texObj->_BaseComplete); assert(texObj->_MipmapComplete); ctx->Shared->FallbackTex[tex] = texObj; } return ctx->Shared->FallbackTex[tex]; }
/** * Do actual memory allocation for glTexStorage1/2/3D(). */ static void setup_texstorage(struct gl_context *ctx, struct gl_texture_object *texObj, GLuint dims, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) { const GLenum target = texObj->Target; const GLuint numFaces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; gl_format texFormat; GLint level, levelWidth = width, levelHeight = height, levelDepth = depth; GLuint face; assert(levels > 0); assert(width > 0); assert(height > 0); assert(depth > 0); texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0, internalFormat, GL_NONE, GL_NONE); /* Set up all the texture object's gl_texture_images */ for (level = 0; level < levels; level++) { for (face = 0; face < numFaces; face++) { const GLenum faceTarget = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : target; struct gl_texture_image *texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, level); if (!texImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage%uD", dims); return; } _mesa_init_teximage_fields(ctx, target, texImage, levelWidth, levelHeight, levelDepth, 0, internalFormat, texFormat); } next_mipmap_level_size(target, &levelWidth, &levelHeight, &levelDepth); } assert(levelWidth > 0); assert(levelHeight > 0); assert(levelDepth > 0); if (!_mesa_is_proxy_texture(texObj->Target)) { /* Do actual texture memory allocation */ if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels, width, height, depth)) { /* Reset the texture images' info to zeros. * Strictly speaking, we probably don't have to do this since * generating GL_OUT_OF_MEMORY can leave things in an undefined * state but this puts things in a consistent state. */ for (level = 0; level < levels; level++) { for (face = 0; face < numFaces; face++) { struct gl_texture_image *texImage = texObj->Image[face][level]; if (texImage) { _mesa_init_teximage_fields(ctx, target, texImage, 0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE); } } } _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims); return; } } texObj->Immutable = GL_TRUE; }
static boolean st_context_teximage(struct st_context_iface *stctxi, enum st_texture_type target, int level, enum pipe_format internal_format, struct pipe_resource *tex, boolean mipmap) { struct st_context *st = (struct st_context *) stctxi; struct gl_context *ctx = st->ctx; struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); struct gl_texture_object *texObj; struct gl_texture_image *texImage; struct st_texture_object *stObj; struct st_texture_image *stImage; GLenum internalFormat; GLuint width, height, depth; switch (target) { case ST_TEXTURE_1D: target = GL_TEXTURE_1D; break; case ST_TEXTURE_2D: target = GL_TEXTURE_2D; break; case ST_TEXTURE_3D: target = GL_TEXTURE_3D; break; case ST_TEXTURE_RECT: target = GL_TEXTURE_RECTANGLE_ARB; break; default: return FALSE; break; } texObj = _mesa_select_tex_object(ctx, texUnit, target); _mesa_lock_texture(ctx, texObj); stObj = st_texture_object(texObj); /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texImage = _mesa_get_tex_image(ctx, texObj, target, level); stImage = st_texture_image(texImage); if (tex) { gl_format texFormat; /* * XXX When internal_format and tex->format differ, st_finalize_texture * needs to allocate a new texture with internal_format and copy the * texture here into the new one. It will result in surface_copy being * called on surfaces whose formats differ. * * To avoid that, internal_format is (wrongly) ignored here. A sane fix * is to use a sampler view. */ if (!st_sampler_compat_formats(tex->format, internal_format)) internal_format = tex->format; if (util_format_get_component_bits(internal_format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) internalFormat = GL_RGBA; else internalFormat = GL_RGB; texFormat = st_ChooseTextureFormat(ctx, internalFormat, GL_BGRA, GL_UNSIGNED_BYTE); _mesa_init_teximage_fields(ctx, texImage, tex->width0, tex->height0, 1, 0, internalFormat, texFormat); width = tex->width0; height = tex->height0; depth = tex->depth0; /* grow the image size until we hit level = 0 */ while (level > 0) { if (width != 1) width <<= 1; if (height != 1) height <<= 1; if (depth != 1) depth <<= 1; level--; } } else { _mesa_clear_texture_image(ctx, texImage); width = height = depth = 0; } pipe_resource_reference(&stImage->pt, tex); stObj->width0 = width; stObj->height0 = height; stObj->depth0 = depth; _mesa_dirty_texobj(ctx, texObj, GL_TRUE); _mesa_unlock_texture(ctx, texObj); return TRUE; }
static struct gl_texture_image * create_texture_for_pbo(struct gl_context *ctx, bool create_pbo, GLenum pbo_target, int dims, int width, int height, int depth, GLenum format, GLenum type, const void *pixels, const struct gl_pixelstore_attrib *packing, struct gl_buffer_object **tmp_pbo, GLuint *tmp_tex) { uint32_t pbo_format; GLenum internal_format; unsigned row_stride; struct gl_buffer_object *buffer_obj; struct gl_texture_object *tex_obj; struct gl_texture_image *tex_image; bool read_only; if (packing->SwapBytes || packing->LsbFirst || packing->Invert) return NULL; pbo_format = _mesa_format_from_format_and_type(format, type); if (_mesa_format_is_mesa_array_format(pbo_format)) pbo_format = _mesa_format_from_array_format(pbo_format); if (!pbo_format || !ctx->TextureFormatSupported[pbo_format]) return NULL; /* Account for SKIP_PIXELS, SKIP_ROWS, ALIGNMENT, and SKIP_IMAGES */ uint32_t first_pixel = _mesa_image_offset(dims, packing, width, height, format, type, 0, 0, 0); uint32_t last_pixel = _mesa_image_offset(dims, packing, width, height, format, type, depth-1, height-1, width); row_stride = _mesa_image_row_stride(packing, width, format, type); if (_mesa_is_bufferobj(packing->BufferObj)) { *tmp_pbo = NULL; buffer_obj = packing->BufferObj; first_pixel += (intptr_t)pixels; } else { bool is_pixel_pack = pbo_target == GL_PIXEL_PACK_BUFFER; assert(create_pbo); *tmp_pbo = ctx->Driver.NewBufferObject(ctx, 0xDEADBEEF); if (*tmp_pbo == NULL) return NULL; /* In case of GL_PIXEL_PACK_BUFFER, pass null pointer for the pixel * data to avoid unnecessary data copying in _mesa_buffer_data. */ if (is_pixel_pack) _mesa_buffer_data(ctx, *tmp_pbo, GL_NONE, last_pixel - first_pixel, NULL, GL_STREAM_READ, __func__); else _mesa_buffer_data(ctx, *tmp_pbo, GL_NONE, last_pixel - first_pixel, (char *)pixels + first_pixel, GL_STREAM_DRAW, __func__); buffer_obj = *tmp_pbo; first_pixel = 0; } _mesa_GenTextures(1, tmp_tex); tex_obj = _mesa_lookup_texture(ctx, *tmp_tex); _mesa_initialize_texture_object(ctx, tex_obj, *tmp_tex, GL_TEXTURE_2D); /* This must be set after _mesa_initialize_texture_object, not before. */ tex_obj->Immutable = GL_TRUE; /* This is required for interactions with ARB_texture_view. */ tex_obj->NumLayers = 1; internal_format = _mesa_get_format_base_format(pbo_format); /* The texture is addressed as a single very-tall image, so we * need to pack the multiple image depths together taking the * inter-image padding into account. */ int image_height = packing->ImageHeight == 0 ? height : packing->ImageHeight; int full_height = image_height * (depth - 1) + height; tex_image = _mesa_get_tex_image(ctx, tex_obj, tex_obj->Target, 0); _mesa_init_teximage_fields(ctx, tex_image, width, full_height, 1, 0, internal_format, pbo_format); read_only = pbo_target == GL_PIXEL_UNPACK_BUFFER; if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, tex_obj, buffer_obj, first_pixel, row_stride, read_only)) { _mesa_DeleteTextures(1, tmp_tex); _mesa_reference_buffer_object(ctx, tmp_pbo, NULL); return NULL; } return tex_image; }