st/mesa: simplify and improve CopyTexSubImage

It has become a bit messy.

Changes:

- finally correct checking for transfer ops depending on the base format

- making sure the base internal format and the texture format match
  (we were ignoring it, but it's important for correctness)

- the way-too-strict rule that both src and dst base formats must be the same
  was dropped; ensuring the simpler and more permissive rule mentioned above
  is enough

- stop using util_blit_pixels; pipe->blit is flexible enough, and now that we
  have RGBX and red-alpha formats, pipe->blit can be used for more cases

Reviewed-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
Marek Olšák
2013-02-14 12:08:33 +01:00
parent 6520a86c67
commit 40ee93c4e8
3 changed files with 100 additions and 261 deletions
+21 -16
View File
@@ -3792,26 +3792,21 @@ _mesa_get_texstore_func(gl_format format)
GLboolean
_mesa_texstore_can_use_memcpy(struct gl_context *ctx,
GLenum baseInternalFormat, gl_format dstFormat,
GLenum srcFormat, GLenum srcType,
const struct gl_pixelstore_attrib *srcPacking)
_mesa_texstore_needs_transfer_ops(struct gl_context *ctx,
GLenum baseInternalFormat,
gl_format dstFormat)
{
GLenum dstType;
/* There are different restrictions depending on the base format... */
/* There are different rules depending on the base format. */
switch (baseInternalFormat) {
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL:
/* Depth scale and bias are not allowed. */
if (ctx->Pixel.DepthScale != 1.0f ||
ctx->Pixel.DepthBias != 0.0f) {
return GL_FALSE;
}
break;
return ctx->Pixel.DepthScale != 1.0f ||
ctx->Pixel.DepthBias != 0.0f;
case GL_STENCIL_INDEX:
break;
return GL_FALSE;
default:
/* Color formats.
@@ -3820,10 +3815,20 @@ _mesa_texstore_can_use_memcpy(struct gl_context *ctx,
*/
dstType = _mesa_get_format_datatype(dstFormat);
if (dstType != GL_INT && dstType != GL_UNSIGNED_INT &&
ctx->_ImageTransferState) {
return GL_FALSE;
}
return dstType != GL_INT && dstType != GL_UNSIGNED_INT &&
ctx->_ImageTransferState;
}
}
GLboolean
_mesa_texstore_can_use_memcpy(struct gl_context *ctx,
GLenum baseInternalFormat, gl_format dstFormat,
GLenum srcFormat, GLenum srcType,
const struct gl_pixelstore_attrib *srcPacking)
{
if (_mesa_texstore_needs_transfer_ops(ctx, baseInternalFormat, dstFormat)) {
return GL_FALSE;
}
/* The base internal format and the base Mesa format must match. */
+4
View File
@@ -69,6 +69,10 @@
extern GLboolean
_mesa_texstore(TEXSTORE_PARAMS);
extern GLboolean
_mesa_texstore_needs_transfer_ops(struct gl_context *ctx,
GLenum baseInternalFormat,
gl_format dstFormat);
extern GLboolean
_mesa_texstore_can_use_memcpy(struct gl_context *ctx,
+75 -245
View File
@@ -1272,110 +1272,6 @@ fallback_copy_texsubimage(struct gl_context *ctx,
}
/**
* If the format of the src renderbuffer and the format of the dest
* texture are compatible (in terms of blitting), return a TGSI writemask
* to be used during the blit.
* If the src/dest are incompatible, return 0.
*/
static unsigned
compatible_src_dst_formats(struct gl_context *ctx,
const struct gl_renderbuffer *src,
const struct gl_texture_image *dst)
{
/* Get logical base formats for the src and dest.
* That is, use the user-requested formats and not the actual, device-
* chosen formats.
* For example, the user may have requested an A8 texture but the
* driver may actually be using an RGBA texture format. When we
* copy/blit to that texture, we only want to copy the Alpha channel
* and not the RGB channels.
*
* Similarly, when the src FBO was created an RGB format may have been
* requested but the driver actually chose an RGBA format. In that case,
* we don't want to copy the undefined Alpha channel to the dest texture
* (it should be 1.0).
*/
const GLenum srcFormat = _mesa_base_fbo_format(ctx, src->InternalFormat);
const GLenum dstFormat = _mesa_base_tex_format(ctx, dst->InternalFormat);
/**
* XXX when we have red-only and red/green renderbuffers we'll need
* to add more cases here (or implement a general-purpose routine that
* queries the existance of the R,G,B,A channels in the src and dest).
*/
if (srcFormat == dstFormat) {
/* This is the same as matching_base_formats, which should
* always pass, as it did previously.
*/
return TGSI_WRITEMASK_XYZW;
}
else if (srcFormat == GL_RGB && dstFormat == GL_RGBA) {
/* Make sure that A in the dest is 1. The actual src format
* may be RGBA and have undefined A values.
*/
return TGSI_WRITEMASK_XYZ;
}
else if (srcFormat == GL_RGBA && dstFormat == GL_RGB) {
/* Make sure that A in the dest is 1. The actual dst format
* may be RGBA and will need A=1 to provide proper alpha values
* when sampled later.
*/
return TGSI_WRITEMASK_XYZ;
}
else {
if (ST_DEBUG & DEBUG_FALLBACK)
debug_printf("%s failed for src %s, dst %s\n",
__FUNCTION__,
_mesa_lookup_enum_by_nr(srcFormat),
_mesa_lookup_enum_by_nr(dstFormat));
/* Otherwise fail.
*/
return 0;
}
}
/**
* Do pipe->blit. Return FALSE if the blitting is unsupported
* for the given formats.
*/
static GLboolean
st_pipe_blit(struct pipe_context *pipe, struct pipe_blit_info *blit)
{
struct pipe_screen *screen = pipe->screen;
unsigned dst_usage;
if (util_format_is_depth_or_stencil(blit->dst.format)) {
dst_usage = PIPE_BIND_DEPTH_STENCIL;
}
else {
dst_usage = PIPE_BIND_RENDER_TARGET;
}
/* try resource_copy_region in case the format is not supported
* for rendering */
if (util_try_blit_via_copy_region(pipe, blit)) {
return GL_TRUE; /* done */
}
/* check the format support */
if (!screen->is_format_supported(screen, blit->src.format,
PIPE_TEXTURE_2D, 0,
PIPE_BIND_SAMPLER_VIEW) ||
!screen->is_format_supported(screen, blit->dst.format,
PIPE_TEXTURE_2D, 0,
dst_usage)) {
return GL_FALSE;
}
pipe->blit(pipe, blit);
return GL_TRUE;
}
/**
* 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
@@ -1391,36 +1287,57 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
GLint srcX, GLint srcY, GLsizei width, GLsizei height)
{
struct st_texture_image *stImage = st_texture_image(texImage);
const GLenum texBaseFormat = texImage->_BaseFormat;
struct st_texture_object *stObj = st_texture_object(texImage->TexObject);
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;
GLuint color_writemask;
struct pipe_surface *dest_surface = NULL;
struct pipe_blit_info blit;
enum pipe_format dst_format;
GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
struct pipe_surface surf_tmpl;
unsigned dst_usage;
unsigned blit_mask;
unsigned bind;
GLint srcY0, srcY1, yStep;
/* 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;
}
assert(strb);
assert(strb->surface);
assert(stImage->pt);
if (_mesa_texstore_needs_transfer_ops(ctx, texImage->_BaseFormat,
texImage->TexFormat)) {
goto fallback;
}
src_format = util_format_linear(strb->surface->format);
dest_format = util_format_linear(stImage->pt->format);
/* The base internal format must match the mesa format, so make sure
* e.g. an RGB internal format is really allocated as RGB and not as RGBA.
*/
if (texImage->_BaseFormat !=
_mesa_get_format_base_format(texImage->TexFormat) ||
rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) {
goto fallback;
}
/* Choose the destination format to match the TexImage behavior. */
dst_format = util_format_linear(stImage->pt->format);
dst_format = util_format_luminance_to_red(dst_format);
dst_format = util_format_intensity_to_red(dst_format);
/* See if the destination format is supported. */
if (texImage->_BaseFormat == GL_DEPTH_STENCIL ||
texImage->_BaseFormat == GL_DEPTH_COMPONENT) {
bind = PIPE_BIND_DEPTH_STENCIL;
}
else {
bind = PIPE_BIND_RENDER_TARGET;
}
if (!dst_format ||
!screen->is_format_supported(screen, dst_format, stImage->pt->target,
stImage->pt->nr_samples, bind)) {
goto fallback;
}
/* Y flipping for the main framebuffer. */
if (do_flip) {
srcY1 = strb->Base.Height - srcY - height;
srcY0 = srcY1 + height;
@@ -1432,143 +1349,56 @@ st_CopyTexSubImage(struct gl_context *ctx, GLuint dims,
yStep = 1;
}
if (ctx->_ImageTransferState) {
goto fallback;
}
/* Compressed and subsampled textures aren't supported for blitting. */
if (!util_format_is_plain(dest_format)) {
goto fallback;
}
if (texBaseFormat == GL_DEPTH_STENCIL ||
texBaseFormat == GL_DEPTH_COMPONENT) {
dst_usage = PIPE_BIND_DEPTH_STENCIL;
}
else {
dst_usage = PIPE_BIND_RENDER_TARGET;
}
blit_mask = get_blit_mask(rb->_BaseFormat, texImage->_BaseFormat);
/* 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).
*
* XXX util_blit_pixels doesn't support MSAA resolve, so always use
* pipe->blit for MSAA textures
*/
if ((blit_mask & PIPE_MASK_RGBA) &&
texBaseFormat != strb->Base._BaseFormat &&
strb->texture->nr_samples <= 1) {
blit_mask = 0;
}
/* Blit the texture.
* This supports flipping, format conversions, and downsampling.
*/
if (blit_mask) {
/* 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.
*/
unsigned dstLevel = MIN2(stImage->base.Level, stImage->pt->last_level);
struct pipe_blit_info blit;
memset(&blit, 0, sizeof(blit));
blit.src.resource = strb->texture;
blit.src.format = util_format_linear(strb->surface->format);
blit.src.level = strb->surface->u.tex.level;
blit.src.box.x = srcX;
blit.src.box.y = srcY0;
blit.src.box.z = strb->surface->u.tex.first_layer;
blit.src.box.width = width;
blit.src.box.height = srcY1 - srcY0;
blit.src.box.depth = 1;
blit.dst.resource = stImage->pt;
blit.dst.format = dst_format;
blit.dst.level = stObj->pt != stImage->pt ? 0 : texImage->Level;
blit.dst.box.x = destX;
blit.dst.box.y = destY;
blit.dst.box.z = stImage->base.Face + destZ;
blit.dst.box.width = width;
blit.dst.box.height = height;
blit.dst.box.depth = 1;
blit.mask = get_blit_mask(rb->_BaseFormat, texImage->_BaseFormat);
blit.filter = PIPE_TEX_FILTER_NEAREST;
memset(&blit, 0, sizeof(blit));
blit.src.resource = strb->texture;
blit.src.format = src_format;
blit.src.level = strb->surface->u.tex.level;
blit.src.box.x = srcX;
blit.src.box.y = srcY0;
blit.src.box.z = strb->surface->u.tex.first_layer;
blit.src.box.width = width;
blit.src.box.height = srcY1 - srcY0;
blit.src.box.depth = 1;
blit.dst.resource = stImage->pt;
blit.dst.format = dest_format;
blit.dst.level = dstLevel;
blit.dst.box.x = destX;
blit.dst.box.y = destY;
blit.dst.box.z = stImage->base.Face + destZ;
blit.dst.box.width = width;
blit.dst.box.height = height;
blit.dst.box.depth = 1;
blit.mask = blit_mask;
blit.filter = PIPE_TEX_FILTER_NEAREST;
/* 1D array textures need special treatment.
* Blit rows from the source to layers in the destination. */
if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
int y, layer;
for (y = srcY0, layer = 0; layer < height; y += yStep, layer++) {
blit.src.box.y = y;
blit.src.box.height = 1;
blit.dst.box.y = 0;
blit.dst.box.height = 1;
blit.dst.box.z = destY + layer;
if (!st_pipe_blit(pipe, &blit)) {
goto fallback;
}
}
}
else {
/* All the other texture targets. */
if (!st_pipe_blit(pipe, &blit)) {
goto fallback;
}
}
return;
}
/* try u_blit */
/* 1D array textures need special treatment.
* Blit rows from the source to layers in the destination. */
if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
/* u_blit cannot copy 1D array textures as required by CopyTexSubImage */
goto fallback;
int y, layer;
for (y = srcY0, layer = 0; layer < height; y += yStep, layer++) {
blit.src.box.y = y;
blit.src.box.height = 1;
blit.dst.box.y = 0;
blit.dst.box.height = 1;
blit.dst.box.z = destY + layer;
pipe->blit(pipe, &blit);
}
}
color_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage);
if (!color_writemask ||
!screen->is_format_supported(screen, src_format,
PIPE_TEXTURE_2D, 0,
PIPE_BIND_SAMPLER_VIEW) ||
!screen->is_format_supported(screen, dest_format,
PIPE_TEXTURE_2D, 0,
dst_usage)) {
goto fallback;
else {
/* All the other texture targets. */
pipe->blit(pipe, &blit);
}
memset(&surf_tmpl, 0, sizeof(surf_tmpl));
surf_tmpl.format = util_format_linear(stImage->pt->format);
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, 0);
pipe_surface_reference(&dest_surface, NULL);
return;
fallback:
/* software fallback */
fallback_copy_texsubimage(ctx,
strb, stImage, texBaseFormat,
strb, stImage, texImage->_BaseFormat,
destX, destY, destZ,
srcX, srcY, width, height);
}