<div dir="ltr"><br><br><br><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Dec 16, 2014 at 11:37 PM, Iago Toral <span dir="ltr"><<a href="mailto:itoral@igalia.com" target="_blank">itoral@igalia.com</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Tue, 2014-12-16 at 10:54 -0800, Jason Ekstrand wrote:<br>
><br>
><br>
> On Tue, Dec 16, 2014 at 4:01 AM, Iago Toral <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>> wrote:<br>
>         On Tue, 2014-12-16 at 08:29 +0100, Iago Toral wrote:<br>
>         > On Mon, 2014-12-15 at 10:19 -0800, Jason Ekstrand wrote:<br>
>         > ><br>
>         > ><br>
>         > > On Mon, Dec 15, 2014 at 3:12 AM, Iago Toral<br>
>         <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>> wrote:<br>
>         > >         On Fri, 2014-12-12 at 11:36 -0800, Jason Ekstrand<br>
>         wrote:<br>
>         > >         ><br>
>         > >         ><br>
>         > >         > On Tue, Dec 9, 2014 at 4:07 AM, Iago Toral<br>
>         Quiroga<br>
>         > >         <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>><br>
>         > >         > wrote:<br>
>         > >         >         For glReadPixels with a Luminance<br>
>         destination format<br>
>         > >         we<br>
>         > >         >         compute luminance<br>
>         > >         >         values from RGBA as L=R+G+B. This,<br>
>         however, requires<br>
>         > >         ad-hoc<br>
>         > >         >         implementation,<br>
>         > >         >         since pack/unpack functions or<br>
>         > >         _mesa_swizzle_and_convert won't<br>
>         > >         >         do this<br>
>         > >         >         (and thus, neither will<br>
>         _mesa_format_convert). This<br>
>         > >         patch adds<br>
>         > >         >         helpers<br>
>         > >         >         to do this computation so they can be<br>
>         used to<br>
>         > >         support<br>
>         > >         >         conversion to luminance<br>
>         > >         >         formats.<br>
>         > >         ><br>
>         > >         >         The current implementation of<br>
>         glReadPixels does this<br>
>         > >         >         computation as part<br>
>         > >         >         of the span functions in pack.c (see<br>
>         > >         >         _mesa_pack_rgba_span_float), that do<br>
>         > >         >         this together with other things like<br>
>         type<br>
>         > >         conversion, etc. We<br>
>         > >         >         do not want<br>
>         > >         >         to use these functions but use<br>
>         _mesa_format_convert<br>
>         > >         instead<br>
>         > >         >         (later patches<br>
>         > >         >         will remove the color span functions),<br>
>         so we need to<br>
>         > >         extract<br>
>         > >         >         this functionality<br>
>         > >         >         as helpers.<br>
>         > >         >         ---<br>
>         > >         >          src/mesa/main/pack.c | 63<br>
>         > >         ><br>
>          ++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
>         > >         >          src/mesa/main/pack.h |  9 ++++++++<br>
>         > >         >          2 files changed, 72 insertions(+)<br>
>         > >         ><br>
>         > >         >         diff --git a/src/mesa/main/pack.c<br>
>         > >         b/src/mesa/main/pack.c<br>
>         > >         >         index de6ab27..fa4046c 100644<br>
>         > >         >         --- a/src/mesa/main/pack.c<br>
>         > >         >         +++ b/src/mesa/main/pack.c<br>
>         > >         >         @@ -4334,4 +4334,67 @@<br>
>         _mesa_rebase_rgba_uint(GLuint<br>
>         > >         n, GLuint<br>
>         > >         >         rgba[][4], GLenum baseFormat)<br>
>         > >         >             }<br>
>         > >         >          }<br>
>         > >         ><br>
>         > >         >         +void<br>
>         > >         ><br>
>          +_mesa_pack_luminance_from_rgba_float(GLuint n,<br>
>         > >         GLfloat<br>
>         > >         >         rgba[][4],<br>
>         > >         >         +<br>
>          GLvoid<br>
>         > >         *dstAddr, GLenum<br>
>         > >         >         dst_format,<br>
>         > >         >         +<br>
>          GLbitfield<br>
>         > >         transferOps)<br>
>         > >         >         +{<br>
>         > >         >         +   int i;<br>
>         > >         >         +   GLfloat *dst = (GLfloat *) dstAddr;<br>
>         > >         >         +<br>
>         > >         >         +   switch (dst_format) {<br>
>         > >         >         +   case GL_LUMINANCE:<br>
>         > >         >         +      if (transferOps &<br>
>         IMAGE_CLAMP_BIT) {<br>
>         > >         >         +         for (i = 0; i < n; i++) {<br>
>         > >         >         +            GLfloat sum =<br>
>         rgba[i][RCOMP] +<br>
>         > >         rgba[i][GCOMP] +<br>
>         > >         >         rgba[i][BCOMP];<br>
>         > >         >         +            dst[i] = CLAMP(sum, 0.0F,<br>
>         1.0F);<br>
>         > >         >         +         }<br>
>         > >         >         +      } else {<br>
>         > >         >         +         for (i = 0; i < n; i++) {<br>
>         > >         >         +            dst[i] = rgba[i][RCOMP] +<br>
>         > >         rgba[i][GCOMP] +<br>
>         > >         >         rgba[i][BCOMP];<br>
>         > >         >         +         }<br>
>         > >         >         +      }<br>
>         > >         >         +      return;<br>
>         > >         >         +   case GL_LUMINANCE_ALPHA:<br>
>         > >         >         +      if (transferOps &<br>
>         IMAGE_CLAMP_BIT) {<br>
>         > >         >         +         for (i = 0; i < n; i++) {<br>
>         > >         >         +            GLfloat sum =<br>
>         rgba[i][RCOMP] +<br>
>         > >         rgba[i][GCOMP] +<br>
>         > >         >         rgba[i][BCOMP];<br>
>         > >         >         +            dst[2*i] = CLAMP(sum, 0.0F,<br>
>         1.0F);<br>
>         > >         >         +            dst[2*i+1] =<br>
>         rgba[i][ACOMP];<br>
>         > >         >         +         }<br>
>         > >         >         +      } else {<br>
>         > >         >         +         for (i = 0; i < n; i++) {<br>
>         > >         >         +            dst[2*i] = rgba[i][RCOMP] +<br>
>         > >         rgba[i][GCOMP] +<br>
>         > >         >         rgba[i][BCOMP];<br>
>         > >         >         +            dst[2*i+1] =<br>
>         rgba[i][ACOMP];<br>
>         > >         >         +         }<br>
>         > >         >         +      }<br>
>         > >         >         +      return;<br>
>         > >         >         +   default:<br>
>         > >         >         +      assert(!"Unsupported format");<br>
>         > >         >         +   }<br>
>         > >         >         +}<br>
>         > >         >         +<br>
>         > >         >         +void<br>
>         > >         ><br>
>          +_mesa_pack_luminance_from_rgba_integer(GLuint n,<br>
>         > >         GLuint<br>
>         > >         >         rgba[][4],<br>
>         > >         >         +<br>
>          GLvoid<br>
>         > >         *dstAddr,<br>
>         > >         >         GLenum dst_format)<br>
>         > >         >         +{<br>
>         > >         >         +   int i;<br>
>         > >         >         +   GLuint *dst = (GLuint *) dstAddr;<br>
>         > >         >         +<br>
>         > >         >         +   switch (dst_format) {<br>
>         > >         >         +   case GL_LUMINANCE:<br>
>         > >         >         +      for (i = 0; i < n; i++) {<br>
>         > >         >         +         dst[i] = rgba[i][RCOMP] +<br>
>         rgba[i][GCOMP] +<br>
>         > >         >         rgba[i][BCOMP];<br>
>         > >         ><br>
>         > >         ><br>
>         > >         > I know this is getting old, but don't we need to<br>
>         do some<br>
>         > >         clamping<br>
>         > >         > here?  If we do, then we have to handle signed<br>
>         vs. unsigned<br>
>         > >         > seperately.  Yeah, that's annoying.<br>
>         > ><br>
>         > ><br>
>         > >         You are right, reviewing the original code it<br>
>         looks like it<br>
>         > >         ends up<br>
>         > >         clamping the result of the triple addition to the<br>
>         type of the<br>
>         > >         dst when<br>
>         > >         the type of the dst has a different size.<br>
>         > ><br>
>         > >         In our case, we call this function from the<br>
>         implementation of<br>
>         > >         glreadpixels when an integer dst luminance format<br>
>         is involved.<br>
>         > >         In that<br>
>         > >         case we convert to RGBA_INT RGBA_UINT first<br>
>         depending on the<br>
>         > >         type of the<br>
>         > >         luminance format and then we call this function,<br>
>         so I think we<br>
>         > >         only need<br>
>         > >         to handle clamping when we pack from RGBA_INT to<br>
>         short and<br>
>         > >         when we pack<br>
>         > >         from RGBA_UINT to unsigned short (meaning that we<br>
>         do not need<br>
>         > >         to handle<br>
>         > >         scenarios where we convert from int to ushort for<br>
>         example).<br>
>         > >         I'll fix<br>
>         > >         this.<br>
>         > ><br>
>         > ><br>
>         > > Yeah, RGBA_[U]INT in is the only case that matters there.<br>
>         What were<br>
>         > > you thinking here?  Personally, I'd probably just make<br>
>         this function<br>
>         > > clamp and then not special case it.  That said, I'm up for<br>
>         other<br>
>         > > solutions too.<br>
>         ><br>
>         > My plan was:<br>
>         ><br>
>         > 1) Add a "GLenum type" parameter so we can detect if we are<br>
>         in the int<br>
>         > case (GL_BYTE, GL_SHORT, etc) or the uint case<br>
>         (GL_UNSIGNED_BYTE,<br>
>         > GL_UNSIGNED_SHORT, etc).<br>
>         ><br>
>         > 2) If we are clamping uints we use<br>
>         _mesa_unsigned_to_unsigned to clamp.<br>
>         > If we are clamping ints, we use _mesa_signed_to_signed. This<br>
>         is because<br>
>         > glReadPixels converts from the render buffer format to RGBA<br>
>         UINT when<br>
>         > the dst type is uint and to RGBA INT otherwise before<br>
>         calling this<br>
>         > function.<br>
>         ><br>
>         > It would look something like this (pseudocode):<br>
>         ><br>
>         > void<br>
>         > _mesa_pack_luminance_from_rgba_integer(GLuint n, GLuint<br>
>         rgba[][4],<br>
>         >    GLvoid *dstAddr, GLenum dst_format, GLenum dst_type)<br>
>         > {<br>
>         >    // Compute L = R + G + B as we do now, without clamping<br>
>         ><br>
>         >    // Handle clamping if necessary (only if the dst_type has<br>
>         >    // a different size<br>
>         >    int bits = bits = _mesa_sizeof_type(dst_type) * 8;<br>
>         >    if (bits < 32) {<br>
>         >       int components =<br>
>         _mesa_components_in_format(dst_format);<br>
>         >       int is_signed = !_mesa_is_type_unsigned(dst_type);<br>
>         >       if (is_signed)<br>
>         >          for (i = 0; i < n; i++) {<br>
>         >             dst[i*components] =<br>
>         >                _mesa_signed_to_signed(dst[i*components],<br>
>         bits);<br>
>         >       } else {<br>
>         >          for (i = 0; i < n; i++) {<br>
>         >             dst[i*components] =<br>
>         >                _mesa_unsigned_to_unsigned(dst[i*components],<br>
>         bits);<br>
>         >       }<br>
>         >    }<br>
>         > }<br>
>         ><br>
>         > We could add the unsigned_to_signed and signed_to_unsigned<br>
>         paths too if<br>
>         > you prefer it that way, but they won't be used as far as I<br>
>         can see. In<br>
>         > that case we would also need to add a src_type parameter.<br>
><br>
><br>
>         Well, in the end I could not do it like this. There is a<br>
>         subtle problem<br>
>         with the RB format -> RGBA conversion that we do before we<br>
>         pack the<br>
>         luminance values. The problem is that we do not want this<br>
>         conversion to<br>
>         ever do int->uint clamping because we want to compute L=R+G+B<br>
>         with<br>
>         unclamped values first, then clamp the result.<br>
><br>
>         For example, if we have a signed integer render buffer and a<br>
>         pixel in<br>
>         that buffer has this value:<br>
>         r=-5, g=6, b=1<br>
><br>
>         when we convert this to RGBA we want to have<br>
>         r=-5, g=6, b=1, a = 1<br>
><br>
>         instead of<br>
>         r=0, g=6, b=1, a = 1<br>
><br>
>         which is what we would get if we convert to RGBA UINT. Then we<br>
>         would<br>
>         compute L = R+G+B = 2, and this is the value we should clamp<br>
>         to the type<br>
>         of the dst if we need to.<br>
><br>
>         So in the end I have to consider signed<->unsigned conversions<br>
>         when we<br>
>         compute L anyway.<br>
><br>
>         Here is a pastebin with the actual implementation of the<br>
>         luminance<br>
>         packing helper:<br>
>         <a href="http://pastebin.com/gB0aLtzx" target="_blank">http://pastebin.com/gB0aLtzx</a><br>
><br>
>         I tested this with a few examples and seems to produce correct<br>
>         results.<br>
>         Notice that this is currently broken in master, because pack.c<br>
>         defines<br>
>         stuff like this:<br>
><br>
>         #define SRC_CONVERT(x) CLAMP((int)x, -32768, 32767)<br>
>         #define FN_NAME pack_short_from_uint_rgba<br>
><br>
>         #define SRC_CONVERT(x) CLAMP((int)x, -128, 127)<br>
>         #define FN_NAME pack_byte_from_uint_rgba<br>
><br>
>         which does not do the right thing when 'x' is expanded to be<br>
>         an<br>
>         expression that adds R, G and B components.<br>
><br>
><br>
> Yes, I think that works but is a bit more complicated than needed.<br>
> Why can't we just do a 64-bit add of the components and then clamp to<br>
> a 32-bit value.  If the final value is 8 or 16 bits, it will get<br>
> clamped again, but that shouldn't be a problem.  We will have to<br>
> differentiate between signed and unsigned, but that's ok.  It would be<br>
> much simpler.  Would that work or am I missing something?<br>
<br>
</div></div>I think it should work, although I wonder if this is better. This is how<br>
I see this being implemented:<br>
<br>
1) Do the 64-bit addition. This requires to allocate a temp buffer for<br>
the 64-bit luminance values.<br>
2) Clamp the 64-bit buffer to 32-bit values. Check if the dst format is<br>
signed or not to decide if we need to do a signed or unsigned 32-bit<br>
clamp. We don't have 64-bit to 32-bit integer clamp functions at the<br>
moment, so those  should be added.<br>
3) If the dst type is 32-bit, then we copy that to dst.<br>
3) If the dst type is <32 bits, copy to dst and clamp (considering<br>
whether we need a signed or unsigned clamp again) => that means we need<br>
to consider 4 paths here (unsigned byte, signed byte, unsigned short,<br>
signed short)<br>
<br>
In the end we have the same paths and the only gain is that we can do<br>
without a macro to compute the additions but in exchange we need to<br>
allocate a temporary buffer in all the scenarios and clamp twice for<br>
types < 32-bit... so I wonder if this is really worth it in the end.<br>
Maybe there is a better way to do it that I am missing?<br></blockquote><div><br></div><div>Oh, I wasn't thinking a 64bit temporary at all.  Just cast to the appropreate 64-bit integer type, add, clamp and go back to 32 in one smooth motion in the original clampping function you had.  All of the malloc'd storage stays 32-bit, it just tweaks the math a bit.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5"><br>
>         > ><br>
>         > >         ><br>
>         > >         >         +      }<br>
>         > >         >         +      return;<br>
>         > >         >         +   case GL_LUMINANCE_ALPHA:<br>
>         > >         >         +      for (i = 0; i < n; i++) {<br>
>         > >         >         +         dst[2*i] = rgba[i][RCOMP] +<br>
>         rgba[i][GCOMP]<br>
>         > >         +<br>
>         > >         >         rgba[i][BCOMP];<br>
>         > >         >         +         dst[2*i+1] = rgba[i][ACOMP];<br>
>         > >         >         +      }<br>
>         > >         >         +      return;<br>
>         > >         >         +   default:<br>
>         > >         >         +      assert(!"Unsupported format");<br>
>         > >         >         +   }<br>
>         > >         >         +}<br>
>         > >         ><br>
>         > >         >         diff --git a/src/mesa/main/pack.h<br>
>         > >         b/src/mesa/main/pack.h<br>
>         > >         >         index 2173b65..2783f23 100644<br>
>         > >         >         --- a/src/mesa/main/pack.h<br>
>         > >         >         +++ b/src/mesa/main/pack.h<br>
>         > >         >         @@ -155,4 +155,13 @@<br>
>         _mesa_rebase_rgba_float(GLuint<br>
>         > >         n, GLfloat<br>
>         > >         >         rgba[][4], GLenum baseFormat);<br>
>         > >         >          extern void<br>
>         > >         >          _mesa_rebase_rgba_uint(GLuint n, GLuint<br>
>         rgba[][4],<br>
>         > >         GLenum<br>
>         > >         >         baseFormat);<br>
>         > >         ><br>
>         > >         >         +extern void<br>
>         > >         ><br>
>          +_mesa_pack_luminance_from_rgba_float(GLuint n,<br>
>         > >         GLfloat<br>
>         > >         >         rgba[][4],<br>
>         > >         >         +<br>
>          GLvoid<br>
>         > >         *dstAddr, GLenum<br>
>         > >         >         dst_format,<br>
>         > >         >         +<br>
>          GLbitfield<br>
>         > >         transferOps);<br>
>         > >         >         +<br>
>         > >         >         +extern void<br>
>         > >         ><br>
>          +_mesa_pack_luminance_from_rgba_integer(GLuint n,<br>
>         > >         GLuint<br>
>         > >         >         rgba[][4],<br>
>         > >         >         +<br>
>          GLvoid<br>
>         > >         *dstAddr,<br>
>         > >         >         GLenum dst_format);<br>
>         > >         >         +<br>
>         > >         >          #endif<br>
>         > >         >         --<br>
>         > >         >         1.9.1<br>
>         > >         ><br>
>         > >         ><br>
>          _______________________________________________<br>
>         > >         >         mesa-dev mailing list<br>
>         > >         >         <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
>         > >         ><br>
>         > ><br>
>         <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
>         > ><br>
>         > ><br>
>         > ><br>
>         ><br>
>         ><br>
>         > _______________________________________________<br>
>         > mesa-dev mailing list<br>
>         > <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
>         > <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
><br>
><br>
><br>
<br>
<br>
</div></div></blockquote></div></div></div>