/** called via ctx->Driver.MapTextureImage() */ static void st_MapTextureImage(struct gl_context *ctx, struct gl_texture_image *texImage, GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h, GLbitfield mode, GLubyte **mapOut, GLint *rowStrideOut) { struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); unsigned pipeMode; GLubyte *map; pipeMode = 0x0; if (mode & GL_MAP_READ_BIT) pipeMode |= PIPE_TRANSFER_READ; if (mode & GL_MAP_WRITE_BIT) pipeMode |= PIPE_TRANSFER_WRITE; if (mode & GL_MAP_INVALIDATE_RANGE_BIT) pipeMode |= PIPE_TRANSFER_DISCARD_RANGE; map = st_texture_image_map(st, stImage, slice, pipeMode, x, y, w, h); if (map) { *mapOut = map; *rowStrideOut = stImage->transfer->stride; } else { *mapOut = NULL; *rowStrideOut = 0; } }
/** called via ctx->Driver.UnmapTextureImage() */ static void st_UnmapTextureImage(struct gl_context *ctx, struct gl_texture_image *texImage, GLuint slice) { struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); st_texture_image_unmap(st, stImage); }
/** * 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; }
/** * Called via ctx->Driver.AllocTextureStorage() to allocate texture memory * for a whole mipmap stack. */ static GLboolean st_AllocTextureStorage(struct gl_context *ctx, struct gl_texture_object *texObj, GLsizei levels, GLsizei width, GLsizei height, GLsizei depth) { const GLuint numFaces = _mesa_num_tex_faces(texObj->Target); struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); GLuint ptWidth, ptHeight, ptDepth, ptLayers, bindings; enum pipe_format fmt; GLint level; assert(levels > 0); /* Save the level=0 dimensions */ stObj->width0 = width; stObj->height0 = height; stObj->depth0 = depth; stObj->lastLevel = levels - 1; fmt = st_mesa_format_to_pipe_format(texObj->Image[0][0]->TexFormat); bindings = default_bindings(st, fmt); st_gl_texture_dims_to_pipe_dims(texObj->Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); stObj->pt = st_texture_create(st, gl_target_to_pipe(texObj->Target), fmt, levels, ptWidth, ptHeight, ptDepth, ptLayers, bindings); if (!stObj->pt) return GL_FALSE; /* Set image resource pointers */ for (level = 0; level < levels; level++) { GLuint face; for (face = 0; face < numFaces; face++) { struct st_texture_image *stImage = st_texture_image(texObj->Image[face][level]); pipe_resource_reference(&stImage->pt, stObj->pt); } } return GL_TRUE; }
/** 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; }
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); }
/** called via ctx->Driver.FreeTextureImageBuffer() */ static void st_FreeTextureImageBuffer(struct gl_context *ctx, struct gl_texture_image *texImage) { struct st_texture_image *stImage = st_texture_image(texImage); DBG("%s\n", __FUNCTION__); if (stImage->pt) { pipe_resource_reference(&stImage->pt, NULL); } if (stImage->TexData) { _mesa_align_free(stImage->TexData); stImage->TexData = NULL; } }
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); }
/** * Called via ctx->Driver.GetTexImage() */ static void st_GetTexImage(struct gl_context * ctx, GLenum format, GLenum type, GLvoid * pixels, struct gl_texture_image *texImage) { struct st_texture_image *stImage = st_texture_image(texImage); if (stImage->pt && util_format_is_s3tc(stImage->pt->format)) { /* Need to decompress the texture. * We'll do this by rendering a textured quad (which is hopefully * faster than using the fallback code in texcompress.c). * Note that we only expect RGBA formats (no Z/depth formats). */ decompress_with_blit(ctx, format, type, pixels, texImage); } else { _mesa_get_teximage(ctx, format, type, pixels, texImage); } }
/** * 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 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_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); }
/** * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible. * Note that the region to copy has already been clipped so we know we * won't read from outside the source renderbuffer's bounds. * * Note: srcY=0=Bottom of renderbuffer (GL convention) */ static void st_CopyTexSubImage(struct gl_context *ctx, GLuint dims, struct gl_texture_image *texImage, GLint destX, GLint destY, GLint destZ, struct gl_renderbuffer *rb, GLint srcX, GLint srcY, GLsizei width, GLsizei height) { struct st_texture_image *stImage = st_texture_image(texImage); const GLenum texBaseFormat = texImage->_BaseFormat; struct st_renderbuffer *strb = st_renderbuffer(rb); struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format dest_format, src_format; GLboolean matching_base_formats; GLuint color_writemask, zs_writemask, sample_count; struct pipe_surface *dest_surface = NULL; GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); struct pipe_surface surf_tmpl; unsigned int dst_usage; GLint srcY0, srcY1; /* make sure finalize_textures has been called? */ if (0) st_validate_state(st); if (!strb || !strb->surface || !stImage->pt) { debug_printf("%s: null strb or stImage\n", __FUNCTION__); return; } sample_count = strb->surface->texture->nr_samples; /* I believe this would be legal, presumably would need to do a resolve for color, and for depth/stencil spec says to just use one of the depth/stencil samples per pixel? Need some transfer clarifications. */ assert(sample_count < 2); assert(strb); assert(strb->surface); assert(stImage->pt); src_format = strb->surface->format; dest_format = stImage->pt->format; /* * Determine if the src framebuffer and dest texture have the same * base format. We need this to detect a case such as the framebuffer * being GL_RGBA but the texture being GL_RGB. If the actual hardware * texture format stores RGBA we need to set A=1 (overriding the * framebuffer's alpha values). We can't do that with the blit or * textured-quad paths. */ matching_base_formats = (_mesa_get_format_base_format(strb->Base.Format) == _mesa_get_format_base_format(texImage->TexFormat)); if (ctx->_ImageTransferState) { goto fallback; } if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { /* 1D arrays might be thought of as 2D images but the actual layout * might not be that way. At some points, we convert OpenGL's 1D * array 'height' into gallium 'layers' and that prevents the blit * utility code from doing the right thing. Simpy use the memcpy-based * fallback. */ goto fallback; } if (matching_base_formats && src_format == dest_format && !do_flip) { /* use surface_copy() / blit */ struct pipe_box src_box; unsigned dstLevel; u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer, width, height, &src_box); /* If stImage->pt is an independent image (not a pointer into a full * mipmap) stImage->pt.last_level will be zero and we need to use that * as the dest level. */ dstLevel = MIN2(stImage->base.Level, stImage->pt->last_level); /* for resource_copy_region(), y=0=top, always */ pipe->resource_copy_region(pipe, /* dest */ stImage->pt, dstLevel, destX, destY, destZ + stImage->base.Face, /* src */ strb->texture, strb->surface->u.tex.level, &src_box); return; } if (texBaseFormat == GL_DEPTH_STENCIL) { goto fallback; } if (texBaseFormat == GL_DEPTH_COMPONENT) { color_writemask = 0; zs_writemask = BLIT_WRITEMASK_Z; dst_usage = PIPE_BIND_DEPTH_STENCIL; } else { color_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage); zs_writemask = 0; dst_usage = PIPE_BIND_RENDER_TARGET; } if ((!color_writemask && !zs_writemask) || !screen->is_format_supported(screen, src_format, PIPE_TEXTURE_2D, sample_count, PIPE_BIND_SAMPLER_VIEW) || !screen->is_format_supported(screen, dest_format, PIPE_TEXTURE_2D, 0, dst_usage)) { goto fallback; } if (do_flip) { srcY1 = strb->Base.Height - srcY - height; srcY0 = srcY1 + height; } else { srcY0 = srcY; srcY1 = srcY0 + height; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = util_format_linear(stImage->pt->format); surf_tmpl.usage = dst_usage; surf_tmpl.u.tex.level = stImage->base.Level; surf_tmpl.u.tex.first_layer = stImage->base.Face + destZ; surf_tmpl.u.tex.last_layer = stImage->base.Face + destZ; dest_surface = pipe->create_surface(pipe, stImage->pt, &surf_tmpl); util_blit_pixels(st->blit, strb->texture, strb->surface->u.tex.level, srcX, srcY0, srcX + width, srcY1, strb->surface->u.tex.first_layer, dest_surface, destX, destY, destX + width, destY + height, 0.0, PIPE_TEX_MIPFILTER_NEAREST, color_writemask, zs_writemask); pipe_surface_reference(&dest_surface, NULL); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } return; fallback: /* software fallback */ fallback_copy_texsubimage(ctx, strb, stImage, texBaseFormat, destX, destY, destZ, srcX, srcY, width, height); }
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); }
/** * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible. * Note that the region to copy has already been clipped so we know we * won't read from outside the source renderbuffer's bounds. * * Note: srcY=0=Bottom of renderbuffer (GL convention) */ static void st_copy_texsubimage(struct gl_context *ctx, struct gl_texture_image *texImage, GLint destX, GLint destY, GLint destZ, struct gl_renderbuffer *rb, GLint srcX, GLint srcY, GLsizei width, GLsizei height) { struct st_texture_image *stImage = st_texture_image(texImage); const GLenum texBaseFormat = texImage->_BaseFormat; struct gl_framebuffer *fb = ctx->ReadBuffer; struct st_renderbuffer *strb; struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format dest_format, src_format; GLboolean matching_base_formats; GLuint format_writemask, sample_count; struct pipe_surface *dest_surface = NULL; GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); struct pipe_surface surf_tmpl; unsigned int dst_usage; GLint srcY0, srcY1; /* make sure finalize_textures has been called? */ if (0) st_validate_state(st); /* determine if copying depth or color data */ if (texBaseFormat == GL_DEPTH_COMPONENT || texBaseFormat == GL_DEPTH_STENCIL) { strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); } else { /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */ strb = st_renderbuffer(fb->_ColorReadBuffer); } if (!strb || !strb->surface || !stImage->pt) { debug_printf("%s: null strb or stImage\n", __FUNCTION__); return; } sample_count = strb->surface->texture->nr_samples; /* I believe this would be legal, presumably would need to do a resolve for color, and for depth/stencil spec says to just use one of the depth/stencil samples per pixel? Need some transfer clarifications. */ assert(sample_count < 2); assert(strb); assert(strb->surface); assert(stImage->pt); src_format = strb->surface->format; dest_format = stImage->pt->format; /* * Determine if the src framebuffer and dest texture have the same * base format. We need this to detect a case such as the framebuffer * being GL_RGBA but the texture being GL_RGB. If the actual hardware * texture format stores RGBA we need to set A=1 (overriding the * framebuffer's alpha values). We can't do that with the blit or * textured-quad paths. */ matching_base_formats = (_mesa_get_format_base_format(strb->Base.Format) == _mesa_get_format_base_format(texImage->TexFormat)); if (ctx->_ImageTransferState) { goto fallback; } if (matching_base_formats && src_format == dest_format && !do_flip) { /* use surface_copy() / blit */ struct pipe_box src_box; u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer, width, height, &src_box); /* for resource_copy_region(), y=0=top, always */ pipe->resource_copy_region(pipe, /* dest */ stImage->pt, stImage->base.Level, destX, destY, destZ + stImage->base.Face, /* src */ strb->texture, strb->surface->u.tex.level, &src_box); return; } if (texBaseFormat == GL_DEPTH_STENCIL) { goto fallback; } if (texBaseFormat == GL_DEPTH_COMPONENT) { format_writemask = TGSI_WRITEMASK_XYZW; dst_usage = PIPE_BIND_DEPTH_STENCIL; } else { format_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage); dst_usage = PIPE_BIND_RENDER_TARGET; } if (!format_writemask || !screen->is_format_supported(screen, src_format, PIPE_TEXTURE_2D, sample_count, PIPE_BIND_SAMPLER_VIEW) || !screen->is_format_supported(screen, dest_format, PIPE_TEXTURE_2D, 0, dst_usage)) { goto fallback; } if (do_flip) { srcY1 = strb->Base.Height - srcY - height; srcY0 = srcY1 + height; } else { srcY0 = srcY; srcY1 = srcY0 + height; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = util_format_linear(stImage->pt->format); surf_tmpl.usage = dst_usage; surf_tmpl.u.tex.level = stImage->base.Level; surf_tmpl.u.tex.first_layer = stImage->base.Face + destZ; surf_tmpl.u.tex.last_layer = stImage->base.Face + destZ; dest_surface = pipe->create_surface(pipe, stImage->pt, &surf_tmpl); util_blit_pixels_writemask(st->blit, strb->texture, strb->surface->u.tex.level, srcX, srcY0, srcX + width, srcY1, strb->surface->u.tex.first_layer, dest_surface, destX, destY, destX + width, destY + height, 0.0, PIPE_TEX_MIPFILTER_NEAREST, format_writemask); pipe_surface_reference(&dest_surface, NULL); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } return; fallback: /* software fallback */ fallback_copy_texsubimage(ctx, strb, stImage, texBaseFormat, destX, destY, destZ, srcX, srcY, width, height); }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_resource *dst_texture; struct pipe_blit_info blit; unsigned bind = (PIPE_BIND_RENDER_TARGET | PIPE_BIND_TRANSFER_READ); struct pipe_transfer *tex_xfer; ubyte *map; /* create temp / dest surface */ if (!util_create_rgba_texture(pipe, width, height, bind, &dst_texture)) { _mesa_problem(ctx, "util_create_rgba_texture() failed " "in decompress_with_blit()"); return; } blit.src.resource = stObj->pt; blit.src.level = texImage->Level; blit.src.format = util_format_linear(stObj->pt->format); blit.dst.resource = dst_texture; blit.dst.level = 0; blit.dst.format = dst_texture->format; blit.src.box.x = blit.dst.box.x = 0; blit.src.box.y = blit.dst.box.y = 0; blit.src.box.z = 0; /* XXX compressed array textures? */ blit.dst.box.z = 0; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = 1; blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; /* blit/render/decompress */ st->pipe->blit(st->pipe, &blit); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); map = pipe_transfer_map(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height, &tex_xfer); if (!map) { goto end; } /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); /* map the dst_surface so we can read from it */ GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: if (map) pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe_resource_reference(&dst_texture, NULL); }
/** * Called via ctx->Driver.AllocTextureImageBuffer(). * If the texture object/buffer already has space for the indicated image, * we're done. Otherwise, allocate memory for the new texture image. */ static GLboolean st_AllocTextureImageBuffer(struct gl_context *ctx, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); const GLuint level = texImage->Level; GLuint width = texImage->Width; GLuint height = texImage->Height; GLuint depth = texImage->Depth; DBG("%s\n", __FUNCTION__); assert(!stImage->TexData); assert(!stImage->pt); /* xxx this might be wrong */ /* Look if the parent texture object has space for this image */ if (stObj->pt && level <= stObj->pt->last_level && st_texture_match_image(stObj->pt, texImage)) { /* this image will fit in the existing texture object's memory */ pipe_resource_reference(&stImage->pt, stObj->pt); return GL_TRUE; } /* The parent texture object does not have space for this image */ pipe_resource_reference(&stObj->pt, NULL); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); if (!guess_and_alloc_texture(st, stObj, stImage)) { /* Probably out of memory. * Try flushing any pending rendering, then retry. */ st_finish(st); if (!guess_and_alloc_texture(st, stObj, stImage)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return GL_FALSE; } } if (stObj->pt && st_texture_match_image(stObj->pt, texImage)) { /* The image will live in the object's mipmap memory */ pipe_resource_reference(&stImage->pt, stObj->pt); assert(stImage->pt); return GL_TRUE; } else { /* Create a new, temporary texture/resource/buffer to hold this * one texture image. Note that when we later access this image * (either for mapping or copying) we'll want to always specify * mipmap level=0, even if the image represents some other mipmap * level. */ enum pipe_format format = st_mesa_format_to_pipe_format(texImage->TexFormat); GLuint bindings = default_bindings(st, format); GLuint ptWidth, ptHeight, ptDepth, ptLayers; st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); stImage->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), format, 0, /* lastLevel */ ptWidth, ptHeight, ptDepth, ptLayers, bindings); return stImage->pt != NULL; } }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); struct pipe_sampler_view *src_view; const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_surface *dst_surface; struct pipe_resource *dst_texture; struct pipe_transfer *tex_xfer; unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */ PIPE_BIND_TRANSFER_READ); /* create temp / dest surface */ if (!util_create_rgba_surface(pipe, width, height, bind, &dst_texture, &dst_surface)) { _mesa_problem(ctx, "util_create_rgba_surface() failed " "in decompress_with_blit()"); return; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } /* Create sampler view that limits fetches to the source mipmap level */ { struct pipe_sampler_view sv_temp; u_sampler_view_default_template(&sv_temp, stObj->pt, stObj->pt->format); sv_temp.format = util_format_linear(sv_temp.format); sv_temp.u.tex.first_level = sv_temp.u.tex.last_level = texImage->Level; src_view = pipe->create_sampler_view(pipe, stObj->pt, &sv_temp); if (!src_view) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); return; } } /* blit/render/decompress */ util_blit_pixels_tex(st->blit, src_view, /* pipe_resource (src) */ 0, 0, /* src x0, y0 */ width, height, /* src x1, y1 */ dst_surface, /* pipe_surface (dst) */ 0, 0, /* dst x0, y0 */ width, height, /* dst x1, y1 */ 0.0, /* z */ PIPE_TEX_MIPFILTER_NEAREST); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } /* map the dst_surface so we can read from it */ tex_xfer = pipe_get_transfer(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); ubyte *map = pipe_transfer_map(pipe, tex_xfer); GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe->transfer_destroy(pipe, tex_xfer); /* destroy the temp / dest surface */ util_destroy_rgba_surface(dst_texture, dst_surface); pipe_sampler_view_release(pipe, &src_view); }
/** * Called during state validation. When this function is finished, * the texture object should be ready for rendering. * \return GL_TRUE for success, GL_FALSE for failure (out of mem) */ GLboolean st_finalize_texture(struct gl_context *ctx, struct pipe_context *pipe, struct gl_texture_object *tObj) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(tObj); const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; GLuint face; struct st_texture_image *firstImage; enum pipe_format firstImageFormat; GLuint ptWidth, ptHeight, ptDepth, ptLayers; if (_mesa_is_texture_complete(tObj, &tObj->Sampler)) { /* The texture is complete and we know exactly how many mipmap levels * are present/needed. This is conditional because we may be called * from the st_generate_mipmap() function when the texture object is * incomplete. In that case, we'll have set stObj->lastLevel before * we get here. */ if (stObj->base.Sampler.MinFilter == GL_LINEAR || stObj->base.Sampler.MinFilter == GL_NEAREST) stObj->lastLevel = stObj->base.BaseLevel; else stObj->lastLevel = stObj->base._MaxLevel; } firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); assert(firstImage); /* If both firstImage and stObj point to a texture which can contain * all active images, favour firstImage. Note that because of the * completeness requirement, we know that the image dimensions * will match. */ if (firstImage->pt && firstImage->pt != stObj->pt && (!stObj->pt || firstImage->pt->last_level >= stObj->pt->last_level)) { pipe_resource_reference(&stObj->pt, firstImage->pt); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); } /* Find gallium format for the Mesa texture */ firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat); /* Find size of level=0 Gallium mipmap image, plus number of texture layers */ { GLuint width, height, depth; if (!guess_base_level_size(stObj->base.Target, firstImage->base.Width2, firstImage->base.Height2, firstImage->base.Depth2, firstImage->base.Level, &width, &height, &depth)) { width = stObj->width0; height = stObj->height0; depth = stObj->depth0; } /* convert GL dims to Gallium dims */ st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, &ptWidth, &ptHeight, &ptDepth, &ptLayers); } /* If we already have a gallium texture, check that it matches the texture * object's format, target, size, num_levels, etc. */ if (stObj->pt) { if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) || !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) || stObj->pt->last_level < stObj->lastLevel || stObj->pt->width0 != ptWidth || stObj->pt->height0 != ptHeight || stObj->pt->depth0 != ptDepth || stObj->pt->array_size != ptLayers) { /* The gallium texture does not match the Mesa texture so delete the * gallium texture now. We'll make a new one below. */ pipe_resource_reference(&stObj->pt, NULL); pipe_sampler_view_release(st->pipe, &stObj->sampler_view); st->dirty.st |= ST_NEW_FRAMEBUFFER; } } /* May need to create a new gallium texture: */ if (!stObj->pt) { GLuint bindings = default_bindings(st, firstImageFormat); stObj->pt = st_texture_create(st, gl_target_to_pipe(stObj->base.Target), firstImageFormat, stObj->lastLevel, ptWidth, ptHeight, ptDepth, ptLayers, bindings); if (!stObj->pt) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return GL_FALSE; } } /* Pull in any images not in the object's texture: */ for (face = 0; face < nr_faces; face++) { GLuint level; for (level = stObj->base.BaseLevel; level <= stObj->lastLevel; level++) { struct st_texture_image *stImage = st_texture_image(stObj->base.Image[face][level]); /* Need to import images in main memory or held in other textures. */ if (stImage && stObj->pt != stImage->pt) { if (level == 0 || (stImage->base.Width == u_minify(stObj->width0, level) && stImage->base.Height == u_minify(stObj->height0, level) && stImage->base.Depth == u_minify(stObj->depth0, level))) { /* src image fits expected dest mipmap level size */ copy_image_data_to_texture(st, stObj, level, stImage); } } } } return GL_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); } }
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); }
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 GLboolean update_single_texture(struct st_context *st, struct pipe_sampler_view **sampler_view, GLuint texUnit) { struct pipe_context *pipe = st->pipe; struct gl_context *ctx = st->ctx; const struct gl_sampler_object *samp; struct gl_texture_object *texObj; struct st_texture_object *stObj; enum pipe_format st_view_format; GLboolean retval; samp = _mesa_get_samplerobj(ctx, texUnit); texObj = ctx->Texture.Unit[texUnit]._Current; if (!texObj) { texObj = _mesa_get_fallback_texture(ctx, TEXTURE_2D_INDEX); samp = &texObj->Sampler; } stObj = st_texture_object(texObj); retval = st_finalize_texture(ctx, st->pipe, texObj); if (!retval) { /* out of mem */ return GL_FALSE; } /* Determine the format of the texture sampler view */ st_view_format = stObj->pt->format; { const struct st_texture_image *firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); const gl_format texFormat = firstImage->base.TexFormat; enum pipe_format firstImageFormat = st_mesa_format_to_pipe_format(texFormat); if ((samp->sRGBDecode == GL_SKIP_DECODE_EXT) && (_mesa_get_format_color_encoding(texFormat) == GL_SRGB)) { /* Don't do sRGB->RGB conversion. Interpret the texture data as * linear values. */ const gl_format linearFormat = _mesa_get_srgb_format_linear(texFormat); firstImageFormat = st_mesa_format_to_pipe_format(linearFormat); } if (firstImageFormat != stObj->pt->format) st_view_format = firstImageFormat; } /* if sampler view has changed dereference it */ if (stObj->sampler_view) { if (check_sampler_swizzle(stObj->sampler_view, stObj->base._Swizzle, samp->DepthMode) || (st_view_format != stObj->sampler_view->format) || stObj->base.BaseLevel != stObj->sampler_view->u.tex.first_level) { pipe_sampler_view_reference(&stObj->sampler_view, NULL); } } *sampler_view = st_get_texture_sampler_view_from_stobj(stObj, pipe, samp, st_view_format); return GL_TRUE; }