Add a dst_internal_format parameter to _mesa_format_convert, that represents the base internal format for texture/pixel uploads, so we can do the right thing when the driver has selected a different internal format for the target dst format. --- src/mesa/main/format_utils.c | 65 +++++++++++++++++++++++++++++++++++++++++++- src/mesa/main/format_utils.h | 2 +- 2 files changed, 65 insertions(+), 2 deletions(-)
diff --git a/src/mesa/main/format_utils.c b/src/mesa/main/format_utils.c index fc59e86..5964689 100644 --- a/src/mesa/main/format_utils.c +++ b/src/mesa/main/format_utils.c @@ -303,7 +303,7 @@ _mesa_compute_component_mapping(GLenum inFormat, GLenum outFormat, GLubyte *map) void _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, void *void_src, uint32_t src_format, size_t src_stride, - size_t width, size_t height) + size_t width, size_t height, GLenum dst_internal_format) { uint8_t *dst = (uint8_t *)void_dst; uint8_t *src = (uint8_t *)void_src; @@ -422,6 +422,36 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, if (src_array_format.as_uint && dst_array_format.as_uint) { assert(src_array_format.normalized == dst_array_format.normalized); + /* If the base format of our dst is not the same as the provided base + * format it means that we are converting to a different format + * than the one originally requested by the client. This can happen when + * the internal base format requested is not supported by the driver. + * In this case we need to consider the requested internal base format to + * compute the correct swizzle operation from src to dst. We will do this + * by computing the swizzle transform src->rgba->base->rgba->dst instead + * of src->rgba->dst. + */ + mesa_format dst_mesa_format; + if (dst_format & MESA_ARRAY_FORMAT_BIT) + dst_mesa_format = _mesa_format_from_array_format(dst_format); + else + dst_mesa_format = dst_format; + if (dst_internal_format != _mesa_get_format_base_format(dst_mesa_format)) { + /* Compute src2rgba as src->rgba->base->rgba */ + uint8_t rgba2base[4], base2rgba[4], swizzle[4]; + _mesa_compute_component_mapping(GL_RGBA, dst_internal_format, rgba2base); + _mesa_compute_component_mapping(dst_internal_format, GL_RGBA, base2rgba); + + for (i = 0; i < 4; i++) { + if (base2rgba[i] > MESA_FORMAT_SWIZZLE_W) + swizzle[i] = base2rgba[i]; + else + swizzle[i] = src2rgba[rgba2base[base2rgba[i]]]; + } + memcpy(src2rgba, swizzle, sizeof(src2rgba)); + } + + /* Compute src2dst from src2rgba */ for (i = 0; i < 4; i++) { if (rgba2dst[i] > MESA_FORMAT_SWIZZLE_W) { src2dst[i] = rgba2dst[i]; @@ -539,9 +569,42 @@ _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, src += src_stride; } } else { + /* For some conversions, doing src->rgba->dst is not enough and we + * need to consider the base internal format. In these cases a + * swizzle operation is required to match the semantics of the base + * internal format requested: src->rgba->swizzle->rgba->dst. + * + * We can detect these cases by checking if the swizzle transform + * for base->rgba->base is 0123. If it is not, then we need + * to do the swizzle operation (need_convert = true). + */ + GLubyte rgba2base[4], base2rgba[4], map[4]; + bool need_convert = false; + mesa_format dst_mesa_format; + if (dst_format & MESA_ARRAY_FORMAT_BIT) + dst_mesa_format = _mesa_format_from_array_format(dst_format); + else + dst_mesa_format = dst_format; + if (dst_internal_format != + _mesa_get_format_base_format(dst_mesa_format)) { + _mesa_compute_component_mapping(GL_RGBA, dst_internal_format, + base2rgba); + _mesa_compute_component_mapping(dst_internal_format, GL_RGBA, + rgba2base); + for (i = 0; i < 4; ++i) { + map[i] = base2rgba[rgba2base[i]]; + if (map[i] != i) + need_convert = true; + } + } + for (row = 0; row < height; ++row) { _mesa_unpack_rgba_row(src_format, width, src, tmp_float + row * width); + if (need_convert) + _mesa_swizzle_and_convert(tmp_float + row * width, GL_FLOAT, 4, + tmp_float + row * width, GL_FLOAT, 4, + map, false, width); src += src_stride; } } diff --git a/src/mesa/main/format_utils.h b/src/mesa/main/format_utils.h index 4237ad3..29ab4a0 100644 --- a/src/mesa/main/format_utils.h +++ b/src/mesa/main/format_utils.h @@ -158,6 +158,6 @@ _mesa_compute_component_mapping(GLenum inFormat, GLenum outFormat, GLubyte *map) void _mesa_format_convert(void *void_dst, uint32_t dst_format, size_t dst_stride, void *void_src, uint32_t src_format, size_t src_stride, - size_t width, size_t height); + size_t width, size_t height, GLenum dst_internal_format); #endif -- 1.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev