st/mesa: optimize 4-component ubyte glDrawPixels

If we didn't find a gallium surface format that exactly matched the
glDrawPixels format/type combination, we used some other 32-bit packed
RGBA format and swizzled the whole image in the mesa texstore/format code.

That slow path can be avoided in some common cases by using the
pipe_samper_view's swizzle terms to do the swizzling at texture sampling
time instead.

For now, only GL_RGBA/ubyte and GL_BGRA/ubyte combinations are supported.
In the future other formats and types like GL_UNSIGNED_INT_8_8_8_8 could
be added.

v2: fix incorrect swizzle setup (need to invert the tex format's swizzle)

Reviewed by: Jose Fonseca <jfonseca@vmware.com>
This commit is contained in:
Brian Paul 2015-10-15 11:54:06 -06:00
parent cf405922eb
commit d11fefa961

View file

@ -395,15 +395,35 @@ make_texture(struct st_context *st,
* Note that the image is actually going to be upside down in
* the texture. We deal with that with texcoords.
*/
success = _mesa_texstore(ctx, 2, /* dims */
baseInternalFormat, /* baseInternalFormat */
mformat, /* mesa_format */
transfer->stride, /* dstRowStride, bytes */
&dest, /* destSlices */
width, height, 1, /* size */
format, type, /* src format/type */
pixels, /* data source */
unpack);
if ((format == GL_RGBA || format == GL_BGRA)
&& type == GL_UNSIGNED_BYTE) {
/* Use a memcpy-based texstore to avoid software pixel swizzling.
* We'll do the necessary swizzling with the pipe_sampler_view to
* give much better performance.
* XXX in the future, expand this to accomodate more format and
* type combinations.
*/
_mesa_memcpy_texture(ctx, 2,
mformat, /* mesa_format */
transfer->stride, /* dstRowStride, bytes */
&dest, /* destSlices */
width, height, 1, /* size */
format, type, /* src format/type */
pixels, /* data source */
unpack);
success = GL_TRUE;
}
else {
success = _mesa_texstore(ctx, 2, /* dims */
baseInternalFormat, /* baseInternalFormat */
mformat, /* mesa_format */
transfer->stride, /* dstRowStride, bytes */
&dest, /* destSlices */
width, height, 1, /* size */
format, type, /* src format/type */
pixels, /* data source */
unpack);
}
/* unmap */
pipe_transfer_unmap(pipe, transfer);
@ -957,6 +977,69 @@ clamp_size(struct pipe_context *pipe, GLsizei *width, GLsizei *height,
}
/**
* Search the array of 4 swizzle components for the named component and return
* its position.
*/
static unsigned
search_swizzle(const unsigned char swizzle[4], unsigned component)
{
unsigned i;
for (i = 0; i < 4; i++) {
if (swizzle[i] == component)
return i;
}
assert(!"search_swizzle() failed");
return 0;
}
/**
* Set the sampler view's swizzle terms. This is used to handle RGBA
* swizzling when the incoming image format isn't an exact match for
* the actual texture format. For example, if we have glDrawPixels(
* GL_RGBA, GL_UNSIGNED_BYTE) and we chose the texture format
* PIPE_FORMAT_B8G8R8A8 then we can do use the sampler view swizzle to
* avoid swizzling all the pixels in software in the texstore code.
*/
static void
setup_sampler_swizzle(struct pipe_sampler_view *sv, GLenum format, GLenum type)
{
if ((format == GL_RGBA || format == GL_BGRA) && type == GL_UNSIGNED_BYTE) {
const struct util_format_description *desc =
util_format_description(sv->texture->format);
unsigned c0, c1, c2, c3;
/* Every gallium driver supports at least one 32-bit packed RGBA format.
* We must have chosen one for (GL_RGBA, GL_UNSIGNED_BYTE).
*/
assert(desc->block.bits == 32);
/* invert the format's swizzle to setup the sampler's swizzle */
if (format == GL_RGBA) {
c0 = UTIL_FORMAT_SWIZZLE_X;
c1 = UTIL_FORMAT_SWIZZLE_Y;
c2 = UTIL_FORMAT_SWIZZLE_Z;
c3 = UTIL_FORMAT_SWIZZLE_W;
}
else {
assert(format == GL_BGRA);
c0 = UTIL_FORMAT_SWIZZLE_Z;
c1 = UTIL_FORMAT_SWIZZLE_Y;
c2 = UTIL_FORMAT_SWIZZLE_X;
c3 = UTIL_FORMAT_SWIZZLE_W;
}
sv->swizzle_r = search_swizzle(desc->swizzle, c0);
sv->swizzle_g = search_swizzle(desc->swizzle, c1);
sv->swizzle_b = search_swizzle(desc->swizzle, c2);
sv->swizzle_a = search_swizzle(desc->swizzle, c3);
}
else {
/* use the default sampler swizzle */
}
}
/**
* Called via ctx->Driver.DrawPixels()
*/
@ -1046,6 +1129,9 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y,
return;
}
/* Set up the sampler view's swizzle */
setup_sampler_swizzle(sv[0], format, type);
/* Create a second sampler view to read stencil. The stencil is
* written using the shader stencil export functionality.
*/