/** * 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; }
static void st_vdpau_unmap_surface(struct gl_context *ctx, GLenum target, GLenum access, GLboolean output, struct gl_texture_object *texObj, struct gl_texture_image *texImage, const GLvoid *vdpSurface, GLuint index) { struct st_texture_object *stObj = st_texture_object(texObj); struct st_texture_image *stImage = st_texture_image(texImage); pipe_resource_reference(&stObj->pt, NULL); pipe_sampler_view_reference(&stObj->sampler_view, NULL); pipe_resource_reference(&stImage->pt, NULL); _mesa_dirty_texobj(ctx, texObj); }
static void st_bind_surface(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj, struct gl_texture_image *texImage, struct pipe_surface *ps) { struct st_texture_object *stObj; struct st_texture_image *stImage; GLenum internalFormat; gl_format texFormat; /* map pipe format to base format */ if (util_format_get_component_bits(ps->format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) internalFormat = GL_RGBA; else internalFormat = GL_RGB; stObj = st_texture_object(texObj); stImage = st_texture_image(texImage); /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texFormat = st_pipe_format_to_mesa_format(ps->format); _mesa_init_teximage_fields(ctx, texImage, ps->width, ps->height, 1, 0, internalFormat, texFormat); /* FIXME create a non-default sampler view from the pipe_surface? */ pipe_resource_reference(&stObj->pt, ps->texture); pipe_sampler_view_reference(&stObj->sampler_view, NULL); pipe_resource_reference(&stImage->pt, stObj->pt); stObj->width0 = ps->width; stObj->height0 = ps->height; stObj->depth0 = 1; stObj->surface_format = ps->format; _mesa_dirty_texobj(ctx, texObj); }
/** * 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 st_vdpau_unmap_surface(struct gl_context *ctx, GLenum target, GLenum access, GLboolean output, struct gl_texture_object *texObj, struct gl_texture_image *texImage, const void *vdpSurface, GLuint index) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct st_texture_image *stImage = st_texture_image(texImage); pipe_resource_reference(&stObj->pt, NULL); st_texture_release_all_sampler_views(st, stObj); pipe_resource_reference(&stImage->pt, NULL); stObj->layer_override = 0; _mesa_dirty_texobj(ctx, texObj); st_flush(st, NULL, 0); }
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 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; }
static void st_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access, GLboolean output, struct gl_texture_object *texObj, struct gl_texture_image *texImage, const GLvoid *vdpSurface, GLuint index) { int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr); uint32_t device = (uintptr_t)ctx->vdpDevice; struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct st_texture_image *stImage = st_texture_image(texImage); struct pipe_resource *res; struct pipe_sampler_view *sv, templ; gl_format texFormat; getProcAddr = ctx->vdpGetProcAddress; if (output) { VdpOutputSurfaceGallium *f; if (getProcAddr(device, VDP_FUNC_ID_OUTPUT_SURFACE_GALLIUM, (void**)&f)) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } res = f((uintptr_t)vdpSurface); if (!res) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } } else { VdpVideoSurfaceGallium *f; struct pipe_video_buffer *buffer; struct pipe_sampler_view **samplers; if (getProcAddr(device, VDP_FUNC_ID_VIDEO_SURFACE_GALLIUM, (void**)&f)) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } buffer = f((uintptr_t)vdpSurface); if (!buffer) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } samplers = buffer->get_sampler_view_planes(buffer); if (!samplers) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } sv = samplers[index >> 1]; if (!sv) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } res = sv->texture; } if (!res) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } /* do we have different screen objects ? */ if (res->screen != st->pipe->screen) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texFormat = st_pipe_format_to_mesa_format(res->format); _mesa_init_teximage_fields(ctx, texImage, res->width0, res->height0, 1, 0, GL_RGBA, texFormat); pipe_resource_reference(&stObj->pt, res); pipe_sampler_view_reference(&stObj->sampler_view, NULL); pipe_resource_reference(&stImage->pt, res); u_sampler_view_default_template(&templ, res, res->format); templ.u.tex.first_layer = index & 1; templ.u.tex.last_layer = index & 1; templ.swizzle_r = GET_SWZ(stObj->base._Swizzle, 0); templ.swizzle_g = GET_SWZ(stObj->base._Swizzle, 1); templ.swizzle_b = GET_SWZ(stObj->base._Swizzle, 2); templ.swizzle_a = GET_SWZ(stObj->base._Swizzle, 3); stObj->sampler_view = st->pipe->create_sampler_view(st->pipe, res, &templ); stObj->width0 = res->width0; stObj->height0 = res->height0; stObj->depth0 = 1; stObj->surface_format = res->format; _mesa_dirty_texobj(ctx, texObj); }
static void st_bind_egl_image(struct gl_context *ctx, struct gl_texture_object *texObj, struct gl_texture_image *texImage, struct st_egl_image *stimg) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj; struct st_texture_image *stImage; GLenum internalFormat; mesa_format texFormat; /* map pipe format to base format */ if (util_format_get_component_bits(stimg->format, UTIL_FORMAT_COLORSPACE_RGB, 3) > 0) internalFormat = GL_RGBA; else internalFormat = GL_RGB; stObj = st_texture_object(texObj); stImage = st_texture_image(texImage); /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj, NULL); stObj->surface_based = GL_TRUE; } texFormat = st_pipe_format_to_mesa_format(stimg->format); /* TODO RequiredTextureImageUnits should probably be reset back * to 1 somewhere if different texture is bound?? */ if (texFormat == MESA_FORMAT_NONE) { switch (stimg->format) { case PIPE_FORMAT_NV12: texFormat = MESA_FORMAT_R_UNORM8; texObj->RequiredTextureImageUnits = 2; break; case PIPE_FORMAT_IYUV: texFormat = MESA_FORMAT_R_UNORM8; texObj->RequiredTextureImageUnits = 3; break; default: unreachable("bad YUV format!"); } } _mesa_init_teximage_fields(ctx, texImage, stimg->texture->width0, stimg->texture->height0, 1, 0, internalFormat, texFormat); pipe_resource_reference(&stObj->pt, stimg->texture); st_texture_release_all_sampler_views(st, stObj); pipe_resource_reference(&stImage->pt, stObj->pt); stObj->surface_format = stimg->format; stObj->level_override = stimg->level; stObj->layer_override = stimg->layer; _mesa_dirty_texobj(ctx, texObj); }
static void st_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access, GLboolean output, struct gl_texture_object *texObj, struct gl_texture_image *texImage, const void *vdpSurface, GLuint index) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct st_texture_image *stImage = st_texture_image(texImage); struct pipe_resource *res; struct pipe_sampler_view templ, **sampler_view; mesa_format texFormat; if (output) { res = st_vdpau_output_surface_dma_buf(ctx, vdpSurface); if (!res) res = st_vdpau_output_surface_gallium(ctx, vdpSurface); } else { res = st_vdpau_video_surface_dma_buf(ctx, vdpSurface, index); if (!res) res = st_vdpau_video_surface_gallium(ctx, vdpSurface, index); } if (!res) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } /* do we have different screen objects ? */ if (res->screen != st->pipe->screen) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texFormat = st_pipe_format_to_mesa_format(res->format); _mesa_init_teximage_fields(ctx, texImage, res->width0, res->height0, 1, 0, GL_RGBA, texFormat); pipe_resource_reference(&stObj->pt, res); st_texture_release_all_sampler_views(st, stObj); pipe_resource_reference(&stImage->pt, res); u_sampler_view_default_template(&templ, res, res->format); templ.u.tex.first_layer = index & 1; templ.u.tex.last_layer = index & 1; templ.swizzle_r = GET_SWZ(stObj->base._Swizzle, 0); templ.swizzle_g = GET_SWZ(stObj->base._Swizzle, 1); templ.swizzle_b = GET_SWZ(stObj->base._Swizzle, 2); templ.swizzle_a = GET_SWZ(stObj->base._Swizzle, 3); sampler_view = st_texture_get_sampler_view(st, stObj); *sampler_view = st->pipe->create_sampler_view(st->pipe, res, &templ); stObj->surface_format = res->format; _mesa_dirty_texobj(ctx, texObj); }
/** * This is called just prior to changing any texture object state which * can effect texture completeness (texture base level, max level). * Any pending rendering will be flushed out, we'll set the _NEW_TEXTURE * state flag and then mark the texture object as 'incomplete' so that any * per-texture derived state gets recomputed. */ static inline void incomplete(struct gl_context *ctx, struct gl_texture_object *texObj) { FLUSH_VERTICES(ctx, _NEW_TEXTURE); _mesa_dirty_texobj(ctx, texObj, GL_TRUE); }
static void st_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access, GLboolean output, struct gl_texture_object *texObj, struct gl_texture_image *texImage, const void *vdpSurface, GLuint index) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct st_texture_image *stImage = st_texture_image(texImage); struct pipe_resource *res; mesa_format texFormat; uint layer_override = 0; if (output) { res = st_vdpau_output_surface_dma_buf(ctx, vdpSurface); if (!res) res = st_vdpau_output_surface_gallium(ctx, vdpSurface); } else { res = st_vdpau_video_surface_dma_buf(ctx, vdpSurface, index); if (!res) { res = st_vdpau_video_surface_gallium(ctx, vdpSurface, index); layer_override = index & 1; } } if (!res) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } /* do we have different screen objects ? */ if (res->screen != st->pipe->screen) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); pipe_resource_reference(&res, NULL); return; } /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texFormat = st_pipe_format_to_mesa_format(res->format); _mesa_init_teximage_fields(ctx, texImage, res->width0, res->height0, 1, 0, GL_RGBA, texFormat); pipe_resource_reference(&stObj->pt, res); st_texture_release_all_sampler_views(st, stObj); pipe_resource_reference(&stImage->pt, res); stObj->surface_format = res->format; stObj->layer_override = layer_override; _mesa_dirty_texobj(ctx, texObj); pipe_resource_reference(&res, NULL); }