<div dir="ltr"><div>After sending this review, I think it would be best (to avoid a gigantic merge snarl) for me to send another patch where I manually merge this with my patch <span style="font-weight:normal"><font>"[PATCH 29/41] main: Added entry point for glGetTextureImage."<br><br></font></span></div><span style="font-weight:normal"><font>Laura<br></font></span></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Dec 18, 2014 at 10:07 AM, Laura Ekstrand <span dir="ltr"><<a href="mailto:laura@jlekstrand.net" target="_blank">laura@jlekstrand.net</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>Brian,<br><br></div>I dealt with a lot of the TEXTURE_CUBE_MAP stuff when I implemented GetTextureImage (in my recent DSA textures patch series).<br><div><br>Ian and I have filed a bug on the spec for missing faces and mismatched formats/sizes. Right now, I am saying if (texObj->NumLayers < 6), throw invalid operation (not enough storage).  Moreover, I discovered Monday (12/15) that in the spec for GenerateMipmap there is a pre-existing idea of "cube completeness."  In section 8.14.4 of GL 4.5 spec, it defines cube completeness as having all the same formats/sizes on the faces.  So I am checking if the texObj is cube complete and throwing invalid operation if it is not.<br><br>So for now, I think invalid operation is the right plan.<br><br></div><div>I agree, this is an absolute mess.<span class="HOEnZb"><font color="#888888"><br><br></font></span></div><span class="HOEnZb"><font color="#888888"><div>Laura<br></div></font></span></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Dec 18, 2014 at 7:32 AM, Brian Paul <span dir="ltr"><<a href="mailto:brianp@vmware.com" target="_blank">brianp@vmware.com</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span>On 12/17/2014 05:03 PM, Laura Ekstrand wrote:<br>
</span><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span>
<br>
<br>
On Sat, Dec 13, 2014 at 6:42 AM, Brian Paul <<a href="mailto:brianp@vmware.com" target="_blank">brianp@vmware.com</a><br></span><div><div>
<mailto:<a href="mailto:brianp@vmware.com" target="_blank">brianp@vmware.com</a>>> wrote:<br>
<br>
    One of the two new functions in GL_ARB_get_texture_sub_image.<br>
    ---<br>
      src/mesa/main/texgetimage.c | 305<br>
    ++++++++++++++++++++++++++++++<u></u>++++++++------<br>
      src/mesa/main/texgetimage.h |   8 ++<br>
      2 files changed, 277 insertions(+), 36 deletions(-)<br>
<br>
    diff --git a/src/mesa/main/texgetimage.c b/src/mesa/main/texgetimage.c<br>
    index 71c25bb..e1f238b 100644<br>
    --- a/src/mesa/main/texgetimage.c<br>
    +++ b/src/mesa/main/texgetimage.c<br>
    @@ -44,6 +44,7 @@<br>
      #include "texcompress.h"<br>
      #include "texgetimage.h"<br>
      #include "teximage.h"<br>
    +#include "texobj.h"<br>
      #include "texstore.h"<br>
<br>
<br>
    @@ -803,41 +804,36 @@ legal_getteximage_target(<u></u>struct gl_context<br>
    *ctx, GLenum target)<br>
<br>
In my work with DSA textures, I have discovered that it's more robust to<br>
pass in both the texture object and target.  I originally just passed in<br>
the texObj instead of the target in error checks and used<br>
texObj->Target, but I failed a number of Piglit tests afterwards.  This<br>
is because, for non-DSA texture objects, the target passed into the<br>
function and the texObj->Target don't always match (especially for proxy<br>
targets).<br>
<br>
      /**<br>
    - * Do error checking for a glGetTexImage() call.<br>
    + * Do error checking for a glGetTexImage() or<br>
    glGetTextureSubImage() call.<br>
       * \return GL_TRUE if any error, GL_FALSE if no errors.<br>
       */<br>
      static GLboolean<br>
    -getteximage_error_check(<u></u>struct gl_context *ctx, GLenum target,<br>
    GLint level,<br>
    +getteximage_error_check(<u></u>struct gl_context *ctx,<br>
    +                        struct gl_texture_object *texObj, GLint level,<br>
                              GLenum format, GLenum type, GLsizei<br>
    clientMemSize,<br>
    -                        GLvoid *pixels )<br>
    +                        GLvoid *pixels, const char *caller)<br>
      {<br>
    -   struct gl_texture_object *texObj;<br>
    +   GLenum target = texObj->Target;<br>
         struct gl_texture_image *texImage;<br>
         const GLint maxLevels = _mesa_max_texture_levels(ctx, target);<br>
    -   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;<br>
         GLenum baseFormat, err;<br>
<br>
    -   if (!legal_getteximage_target(<u></u>ctx, target)) {<br>
    -      _mesa_error(ctx, GL_INVALID_ENUM,<br>
    "glGetTexImage(target=0x%x)", target);<br>
    -      return GL_TRUE;<br>
    -   }<br>
    -<br>
         assert(maxLevels != 0);<br>
         if (level < 0 || level >= maxLevels) {<br>
    -      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", caller);<br>
            return GL_TRUE;<br>
         }<br>
<br>
         err = _mesa_error_check_format_and_<u></u>type(ctx, format, type);<br>
         if (err != GL_NO_ERROR) {<br>
    -      _mesa_error(ctx, err, "glGetTexImage(format/type)");<br>
    +      _mesa_error(ctx, err, "%s(format/type)", caller);<br>
            return GL_TRUE;<br>
         }<br>
<br>
         texObj = _mesa_get_current_tex_object(<u></u>ctx, target);<br>
<br>
         if (!texObj) {<br>
    -      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");<br>
    +      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);<br>
            return GL_TRUE;<br>
         }<br>
<br>
    @@ -854,64 +850,79 @@ getteximage_error_check(struct gl_context<br>
    *ctx, GLenum target, GLint level,<br>
          */<br>
         if (_mesa_is_color_format(format)<br>
             && !_mesa_is_color_format(<u></u>baseFormat)) {<br>
    -      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format<br>
    mismatch)");<br>
    +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)",<br>
    caller);<br>
            return GL_TRUE;<br>
         }<br>
         else if (_mesa_is_depth_format(format)<br>
                  && !_mesa_is_depth_format(<u></u>baseFormat)<br>
                  && !_mesa_is_depthstencil_format(<u></u>baseFormat)) {<br>
    -      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format<br>
    mismatch)");<br>
    +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)",<br>
    caller);<br>
            return GL_TRUE;<br>
         }<br>
         else if (_mesa_is_stencil_format(<u></u>format)<br>
                  && !ctx->Extensions.ARB_texture_<u></u>stencil8) {<br>
    -      _mesa_error(ctx, GL_INVALID_ENUM,<br>
    "glGetTexImage(format=GL_<u></u>STENCIL_INDEX)");<br>
    +      _mesa_error(ctx, GL_INVALID_ENUM,<br>
    "%s(format=GL_STENCIL_INDEX)", caller);<br>
            return GL_TRUE;<br>
         }<br>
         else if (_mesa_is_ycbcr_format(format)<br>
                  && !_mesa_is_ycbcr_format(<u></u>baseFormat)) {<br>
    -      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format<br>
    mismatch)");<br>
    +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)",<br>
    caller);<br>
            return GL_TRUE;<br>
         }<br>
         else if (_mesa_is_depthstencil_format(<u></u>format)<br>
                  && !_mesa_is_depthstencil_format(<u></u>baseFormat)) {<br>
    -      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format<br>
    mismatch)");<br>
    +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)",<br>
    caller);<br>
            return GL_TRUE;<br>
         }<br>
         else if (_mesa_is_enum_format_integer(<u></u>format) !=<br>
                  _mesa_is_format_integer(<u></u>texImage->TexFormat)) {<br>
    -      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format<br>
    mismatch)");<br>
    +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(format mismatch)",<br>
    caller);<br>
            return GL_TRUE;<br>
         }<br>
<br>
    -   if (!_mesa_validate_pbo_access(<u></u>dimensions, &ctx->Pack,<br>
    texImage->Width,<br>
    -                                  texImage->Height, texImage->Depth,<br>
    -                                  format, type, clientMemSize,<br>
    pixels)) {<br>
    +   return GL_FALSE;<br>
    +}<br>
    +<br>
    +<br>
    +/**<br>
    + * Do error checking related to the PBO and image size.<br>
    + */<br>
    +static bool<br>
    +pbo_error_check(struct gl_context *ctx, GLenum target,<br>
    +                GLenum format, GLenum type,<br>
    +                GLsizei width, GLsizei height, GLsizei depth,<br>
    +                GLsizei bufferSize, void *pixels,<br>
    +                const char *caller)<br>
    +{<br>
    +   const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;<br>
    +<br>
    +   if (!_mesa_validate_pbo_access(<u></u>dimensions, &ctx->Pack,<br>
    +                                  width, height, depth,<br>
    +                                  format, type, bufferSize, pixels)) {<br>
            if (_mesa_is_bufferobj(ctx->Pack.<u></u>BufferObj)) {<br>
               _mesa_error(ctx, GL_INVALID_OPERATION,<br>
    -                     "glGetTexImage(out of bounds PBO access)");<br>
    +                     "%s(out of bounds PBO access)", caller);<br>
            } else {<br>
               _mesa_error(ctx, GL_INVALID_OPERATION,<br>
    -                     "glGetnTexImageARB(out of bounds access:"<br>
    -                     " bufSize (%d) is too small)", clientMemSize);<br>
    +                     "%s(out of bounds access: bufSize (%d) is too<br>
    small)",<br>
    +                     caller, bufferSize);<br>
            }<br>
    -      return GL_TRUE;<br>
    +      return true;<br>
         }<br>
<br>
         if (_mesa_is_bufferobj(ctx->Pack.<u></u>BufferObj)) {<br>
            /* PBO should not be mapped */<br>
            if (_mesa_check_disallowed_<u></u>mapping(ctx->Pack.BufferObj)) {<br>
               _mesa_error(ctx, GL_INVALID_OPERATION,<br>
    -                     "glGetTexImage(PBO is mapped)");<br>
    -         return GL_TRUE;<br>
    +                     "%s(PBO is mapped)", caller);<br>
    +         return true;<br>
            }<br>
         }<br>
<br>
    -   return GL_FALSE;<br>
    +   return false;<br>
      }<br>
<br>
<br>
    -<br>
      /**<br>
       * Get texture image.  Called by glGetTexImage.<br>
       *<br>
    @@ -932,21 +943,36 @@ _mesa_GetnTexImageARB( GLenum target, GLint<br>
    level, GLenum format,<br>
<br>
         FLUSH_VERTICES(ctx, 0);<br>
<br>
    -   if (getteximage_error_check(ctx, target, level, format, type,<br>
    -                               bufSize, pixels)) {<br>
    +   if (!legal_getteximage_target(<u></u>ctx, target)) {<br>
    +      _mesa_error(ctx, GL_INVALID_ENUM,<br>
    "glGetTexImage(target=0x%x)", target);<br>
            return;<br>
         }<br>
<br>
    -   if (!_mesa_is_bufferobj(ctx-><u></u>Pack.BufferObj) && !pixels) {<br>
    -      /* not an error, do nothing */<br>
    +   texObj = _mesa_get_current_tex_object(<u></u>ctx, target);<br>
    +<br>
    +   if (getteximage_error_check(ctx, texObj, level, format, type,<br>
    +                               bufSize, pixels, "glGet[n]TexImage")) {<br>
            return;<br>
         }<br>
<br>
    -   texObj = _mesa_get_current_tex_object(<u></u>ctx, target);<br>
         texImage = _mesa_select_tex_image(ctx, texObj, target, level);<br>
    +   if (!texImage) {<br>
    +      return;  /* no texture image */<br>
    +   }<br>
<br>
    -   if (_mesa_is_zero_size_texture(<u></u>texImage))<br>
    +   if (pbo_error_check(ctx, target, format, type,<br>
    +                       texImage->Width, texImage->Height,<br>
    texImage->Depth,<br>
    +                       bufSize, pixels, "glGet[n]TexImage")) {<br>
            return;<br>
    +   }<br>
    +<br>
    +   if (_mesa_is_zero_size_texture(<u></u>texImage)) {<br>
    +      return;  /* nothing to get */<br>
    +   }<br>
    +<br>
    +   if (!_mesa_is_bufferobj(ctx-><u></u>Pack.BufferObj) && !pixels) {<br>
    +      return;  /* not an error, do nothing */<br>
    +   }<br>
<br>
         if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) {<br>
            _mesa_debug(ctx, "glGetTexImage(tex %u) format = %s, w=%d,<br>
    h=%d,"<br>
    @@ -1110,3 +1136,210 @@ _mesa_GetCompressedTexImage(<u></u>GLenum target,<br>
    GLint level, GLvoid *img)<br>
      {<br>
         _mesa_<u></u>GetnCompressedTexImageARB(<u></u>target, level, INT_MAX, img);<br>
      }<br>
<br>
<br>
Note:  When this gets merged with my DSA work, the target should maybe<br>
get passed into this function.  This is because DSA and traditional<br>
functions share a backend function, and that backend function will have<br>
to resemble your GetTextureSubImage function (thus calling<br>
dimensions_error_check).  As aforementioned, not passing the target<br>
could cause trouble.<br>
<br>
    +<br>
    +<br>
    +<br>
    +/**<br>
    + * Error-check the offset and size arguments to<br>
    + * glGet[Compressed]<u></u>TextureSubImage().<br>
    + * \return true if error, false if no error.<br>
    + */<br>
    +static bool<br>
    +dimensions_error_check(struct gl_context *ctx,<br>
    +                       struct gl_texture_image *texImage,<br>
    +                       GLint xoffset, GLint yoffset, GLint zoffset,<br>
    +                       GLsizei width, GLsizei height, GLsizei depth)<br>
    +{<br>
    +   const GLenum target = texImage->TexObject->Target;<br>
    +<br>
    +   switch (target) {<br>
    +   case GL_TEXTURE_1D:<br>
    +      if (yoffset != 0) {<br>
    +         _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                     "glGetTextureSubImage(1D, yoffset = %d)\n",<br>
    yoffset);<br>
    +         return true;<br>
    +      }<br>
    +      if (height != 1) {<br>
    +         _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                     "glGetTextureSubImage(1D, height = %d)\n",<br>
    height);<br>
    +         return true;<br>
    +      }<br>
    +      /* fall-through */<br>
    +   case GL_TEXTURE_1D_ARRAY:<br>
    +   case GL_TEXTURE_2D:<br>
    +   case GL_TEXTURE_RECTANGLE:<br>
    +      if (zoffset != 0) {<br>
    +         _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                     "glGetTextureSubImage(zoffset = %d)\n", zoffset);<br>
    +         return true;<br>
    +      }<br>
    +      if (depth != 1) {<br>
    +         _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                     "glGetTextureSubImage(depth = %d)\n", depth);<br>
    +         return true;<br>
    +      }<br>
    +      break;<br>
    +   default:<br>
    +      ; /* nothing */<br>
    +   }<br>
    +<br>
    +   if (xoffset < 0) {<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                  "glGetTextureSubImage(xoffset = %d)\n", xoffset);<br>
    +      return true;<br>
    +   }<br>
    +<br>
    +   if (yoffset < 0) {<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                  "glGetTextureSubImage(yoffset = %d)\n", yoffset);<br>
    +      return true;<br>
    +   }<br>
    +<br>
    +   if (zoffset < 0) {<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                  "glGetTextureSubImage(zoffset = %d)\n", zoffset);<br>
    +      return true;<br>
    +   }<br>
    +<br>
<br>
Why didn't you put xoffset %d + width %d > image_width %u ?<br>
</div></div></blockquote>
<br>
IMHO, the error message has enough info to convey the problem.  If you feel strongly that this needs to be fixed, there's a bunch of similar instances (with more terse messages) in teximage.c that should be fixed as well.<div><div><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +   if (xoffset + width > texImage->Width) {<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                  "glGetTextureSubImage(xoffset %d + width %d > %u)\n",<br>
    +                  xoffset, width, texImage->Width);<br>
    +      return true;<br>
    +   }<br>
    +<br>
    +   if (yoffset + height > texImage->Height) {<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                  "glGetTextureSubImage(yoffset %d + height %d ><br>
    %u)\n",<br>
    +                  yoffset, height, texImage->Height);<br>
    +      return true;<br>
    +   }<br>
    +<br>
    +   if (zoffset + depth > texImage->Depth) {<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                  "glGetTextureSubImage(zoffset %d + depth %d > %u)\n",<br>
    +                  zoffset, depth, texImage->Depth);<br>
    +      return true;<br>
    +   }<br>
    +<br>
    +   /* Extra checks for compressed textures */<br>
    +   {<br>
    +      GLuint bw, bh;<br>
    +      _mesa_get_format_block_size(<u></u>texImage->TexFormat, &bw, &bh);<br>
<br>
    +      if (bw > 1 || bh > 1) {<br>
    +         /* offset must be multiple of block size */<br>
<br>
This should be an INVALID_VALUE error according to the GL 4.5 spec.<br>
</blockquote>
<br></div></div>
Fixed in v2.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +         if (xoffset % bw != 0) {<br>
    +            _mesa_error(ctx, GL_INVALID_OPERATION,<br>
    +                        "glGetTextureSubImage(xoffset = %d)", xoffset);<br>
    +            return true;<br>
    +         }<br>
    +         if (target != GL_TEXTURE_1D && target !=<br>
    GL_TEXTURE_1D_ARRAY) {<br>
<br>
This should be an INVALID_VALUE error according to the GL 4.5 spec.<br>
</blockquote>
<br></span>
Fixed in v2.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Also, shouldn't it be yoffset % bh != 0 ?  You have bw.<br>
</blockquote>
<br></span>
Fixed in v2.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +            if (yoffset % bw != 0) {<br>
    +               _mesa_error(ctx, GL_INVALID_OPERATION,<br>
    +                           "glGetTextureSubImage(yoffset = %d)",<br>
    yoffset);<br>
    +               return true;<br>
    +            }<br>
    +         }<br>
<br>
Why is there no similar zoffset check?  Is it because Mesa doesn't have<br>
a concept of block depth?<br>
</blockquote>
<br></span>
Correct.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +<br>
    +         /* The size must be a multiple of bw x bh, or we must be<br>
    using a<br>
    +          * offset+size that exactly hits the edge of the image.<br>
    +          */<br>
<br>
Note: xoffset + width != (GLint) texImage->Width is more permissive than<br>
the spec document, which says (xoffset != 0) || (width != (GLint)<br>
texImage->Width).<br>
</blockquote>
<br></span>
I believe there was discussion about this a few years ago and Mesa's behavior matches nvidia's driver.  The same logic is used in the glTexImage code.  It allows sub-regions of compressed textures to be read/written on block boundaries.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Again, the spec document says INVALID_VALUE.<br>
</blockquote>
<br></span>
Fixed.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +         if ((width % bw != 0) &&<br>
    +             (xoffset + width != (GLint) texImage->Width)) {<br>
    +            _mesa_error(ctx, GL_INVALID_OPERATION,<br>
    +                        "glGetTextureSubImage(width = %d)", width);<br>
    +            return true;<br>
    +         }<br>
    +<br>
<br>
Again, the spec document says INVALID_VALUE.<br>
</blockquote>
<br></span>
Fixed.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +         if ((height % bh != 0) &&<br>
    +             (yoffset + height != (GLint) texImage->Height)) {<br>
    +            _mesa_error(ctx, GL_INVALID_OPERATION,<br>
    +                        "glGetTextureSubImage(height = %d)", height);<br>
    +            return true;<br>
    +         }<br>
    +      }<br>
    +   }<br>
<br>
No depth check?<br>
</blockquote>
<br></span>
No.  We have no 3D compression formats.<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>
<br>
    +<br>
    +   if (width == 0 || height == 0 || depth == 0) {<br>
    +      /* Not an error, but nothing to do.  Return 'true' so that the<br>
    +       * caller simply returns.<br>
    +       */<br>
    +      return true;<br>
    +   }<br>
    +<br>
    +   return false;<br>
    +}<br>
    +<br>
    +<br>
    +<br>
    +void GLAPIENTRY<br>
    +_mesa_GetTextureSubImage(<u></u>GLuint texture, GLint level,<br>
    +                         GLint xoffset, GLint yoffset, GLint zoffset,<br>
    +                         GLsizei width, GLsizei height, GLsizei depth,<br>
    +                         GLenum format, GLenum type, GLsizei bufSize,<br>
    +                         void *pixels)<br>
    +{<br>
    +   struct gl_texture_object *texObj;<br>
    +   struct gl_texture_image *texImage;<br>
    +   GLenum target;<br>
    +<br>
    +   GET_CURRENT_CONTEXT(ctx);<br>
    +<br>
    +   texObj = _mesa_lookup_texture(ctx, texture);<br>
    +   if (!texObj) {<br>
<br>
<br>
I think this error might be a mistake in the spec.  According to<br>
<a href="https://www.opengl.org/registry/specs/ARB/get_texture_sub_image.txt" target="_blank">https://www.opengl.org/<u></u>registry/specs/ARB/get_<u></u>texture_sub_image.txt</a><br></div></div>
<<a href="https://urldefense.proofpoint.com/v2/url?u=https-3A__www.opengl.org_registry_specs_ARB_get-5Ftexture-5Fsub-5Fimage.txt&d=AwMFaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=T0t4QG7chq2ZwJo6wilkFznRSFy-8uDKartPGbomVj8&m=WWWcDPCoYwfOyILpH0kA7-k-qpSPTsIs1qycAmB5GNA&s=ZhWz0mRK6xg9KPHqEvdXdXdSYxLyX81SGDpO0VoV-nw&e=" target="_blank">https://urldefense.<u></u>proofpoint.com/v2/url?u=https-<u></u>3A__www.opengl.org_registry_<u></u>specs_ARB_get-5Ftexture-5Fsub-<u></u>5Fimage.txt&d=AwMFaQ&c=<u></u>Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-<u></u>YihVMNtXt-uEs&r=<u></u>T0t4QG7chq2ZwJo6wilkFznRSFy-<u></u>8uDKartPGbomVj8&m=<u></u>WWWcDPCoYwfOyILpH0kA7-k-<u></u>qpSPTsIs1qycAmB5GNA&s=<u></u>ZhWz0mRK6xg9KPHqEvdXdXdSYxLyX8<u></u>1SGDpO0VoV-nw&e=</a>>,<span><br>
it should be INVALID_OPERATION in the case where the user passed in an<br>
unknown texture name.  Oddly enough, the OpenGL 4.5 core spec<br>
(30.10.2014) has INVALID_VALUE (consistent with what you have here) in<br>
section 8.11 Texture Queries.  But that is very strange because all the<br>
DSA functions consistently throw INVALID_OPERATION for this error (such<br>
as GetTextureImage and TextureSubImage*D, etc.) in the OpenGL 4.5 spec.<br>
I'm not sure why they wouldn't agree.<br>
<br>
In my DSA patch series, I have a convenience function for throwing<br>
INVALID_OPERATION for an unknown texture name because this occurs<br>
absolutely everywhere (_mesa_lookup_texture_err).<br>
</span></blockquote>
<br>
Actually, a later patch in the series changed this to INVALID_OPERATION (and fixed the error string).  I'll move that bit into this patch.<br>
<br>
INVALID_OPERATION seems to be the right thing.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +      _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                  "glGetTextureSubImage(invalid texture ID %u\n",<br>
    texture);<br>
    +      return;<br>
    +   }<br>
    +<br>
    +   /* common error checking */<br>
    +   if (getteximage_error_check(ctx, texObj, level, format, type,<br>
    bufSize,<br>
    +                               pixels, "glGetTextureSubImage")) {<br>
    +      return;<br>
    +   }<br>
    +<br>
<br>
<br>
You forgot to call legal_getteximage_target.<br>
</blockquote>
<br></span>
I don't think that's needed since it's not possible for texObj->Target to be an invalid value at this point.<span><br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
    +   target = texObj->Target;<br>
<br>
<br>
This doesn't seem like it will return more than one face of the cube<br>
map.  In fact, it will throw INVALID_OPERATION if the user tries to do<br>
so (depth != 1).  But the GL 4.5 spec says the user should be able to<br>
get as many faces as he or she wants from GetTextureSubImage (up to all<br>
six).<br>
</blockquote>
<br></span>
Ugh, something got lost from my early versions of the GL_ARB_get_texture_sub_image spec to what's in the final spec, and the 4.5 spec.<br>
<br>
The problem is OpenGL doesn't disallow specifying different dimensions for each of the cube map faces.  For example, it's perfectly legal to<br>
create a cube map texture like this:<br>
<br>
glTexImage2D(POSITIVE_X, width=32, height=32)<br>
glTexImage2D(NEGATIVE_X, width=16, height=16)<br>
glTexImage2D(POSITIVE_Y, width=64, height=64)<br>
etc.<br>
<br>
You can even have different internal formats per face!<br>
<br>
The texture will be flagged as 'incomplete' and you can't render with it.  But you can create such a texture and you can query the face dimensions with glGetTexLevelParameter() and get back the per-face sizes.  Plus, glGetTexImage operates per-face.  (I should probably whip up a piglit test to verify this).<br>
<br>
So, what should happen with glGetTextureSubImage() if we try to get two or more mismatched-size faces at once?  I can't find any spec language about this.  Maybe just raise GL_INVALID_OPERATION??<br>
<br>
My first few drafts of the GL_ARB_get_texture_sub_image spec had a target parameter which only allowed GL_TEXTURE_CUBE_MAP_POSITIVE/<u></u>NEGATIVE_X/Y/Z so that this situation would be handled consistently.<br>
<br>
I didn't see that this got changed in the spec so I implemented what I originally intended (only allow getting one face/slice at a time).<br>
<br>
<br>
BTW, it would be nice in Mesa if we could treat GL_TEXTURE_CUBE_MAP textures more like GL_TEXTURE_CUBE_MAP_ARRAY textures.  That is, the faces would just be treated as slices in a depth=6 array.<br>
<br>
Ideally, gl_texture_object::Image[face]<u></u>[level] would become gl_texture_object::Image[<u></u>level].  But we can't really do that since according to the spec, we need to keep track of possibly different dimensions and formats for each face.<br>
<br>
This is a mess.  What do you think about the GL_INVALID_OPERATION idea?<br>
<br>
<br>
In any case, I'm on vacation after Friday so I probably won't have time to go further on this until the new year.<br>
<br>
-Brian<br>
<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div>
In my GetTextureImage patch, I just call the backend<br>
_mesa_get_texture_image multiple times.  When they are merged, the<br>
backend will be _mesa_get_texture_sub_image and GetTextureSubImage can<br>
call that multiple times in the same way.<br>
<br>
    +   if (target == GL_TEXTURE_CUBE_MAP) {<br>
    +      /* convert z to face/target */<br>
    +      if (zoffset >= 6) {<br>
    +         _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                     "glGetTextureSubImage(cube, zoffset = %d\n",<br>
    zoffset);<br>
    +         return;<br>
    +      }<br>
    +      if (depth != 1) {<br>
    +         _mesa_error(ctx, GL_INVALID_VALUE,<br>
    +                     "glGetTextureSubImage(cube, depth = %d\n", depth);<br>
    +         return;<br>
    +      }<br>
    +      target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + zoffset;<br>
    +   }<br>
    +<br>
    +   texImage = _mesa_select_tex_image(ctx, texObj, target, level);<br>
    +<br>
    +   /* check dimensions */<br>
    +   if (dimensions_error_check(ctx, texImage, xoffset, yoffset, zoffset,<br>
    +                              width, height, depth)) {<br>
    +      return;<br>
    +   }<br>
    +<br>
    +   if (pbo_error_check(ctx, target, format, type,<br>
    +                       width, height, depth,<br>
    +                       bufSize, pixels, "glGetTextureSubImage")) {<br>
    +      return;<br>
    +   }<br>
    +<br>
    +   if (_mesa_is_zero_size_texture(<u></u>texImage)) {<br>
    +      return;  /* nothing to get */<br>
    +   }<br>
    +<br>
    +   if (!_mesa_is_bufferobj(ctx-><u></u>Pack.BufferObj) && pixels == NULL) {<br>
    +      return;  /* not an error, do nothing */<br>
    +   }<br>
    +<br>
    +   _mesa_lock_texture(ctx, texObj);<br>
    +   {<br>
    +      ctx->Driver.GetTexSubImage(<u></u>ctx, xoffset, yoffset, zoffset,<br>
    width, height,<br>
    +                                 depth, format, type, pixels,<br>
    texImage);<br>
    +   }<br>
    +   _mesa_unlock_texture(ctx, texObj);<br>
    +}<br>
    diff --git a/src/mesa/main/texgetimage.h b/src/mesa/main/texgetimage.h<br>
    index c9af5b9..40f152c 100644<br>
    --- a/src/mesa/main/texgetimage.h<br>
    +++ b/src/mesa/main/texgetimage.h<br>
    @@ -65,4 +65,12 @@ extern void GLAPIENTRY<br>
      _mesa_<u></u>GetnCompressedTexImageARB(<u></u>GLenum target, GLint level,<br>
    GLsizei bufSize,<br>
                                      GLvoid *img);<br>
<br>
    +extern void GLAPIENTRY<br>
    +_mesa_GetTextureSubImage(<u></u>GLuint texture, GLint level,<br>
    +                         GLint xoffset, GLint yoffset, GLint zoffset,<br>
    +                         GLsizei width, GLsizei height, GLsizei depth,<br>
    +                         GLenum format, GLenum type, GLsizei bufSize,<br>
    +                         void *pixels);<br>
    +<br>
    +<br>
      #endif /* TEXGETIMAGE_H */<br>
    --<br>
    1.9.1<br>
<br>
    ______________________________<u></u>_________________<br>
    mesa-dev mailing list<br></div></div>
    <a href="mailto:mesa-dev@lists.freedesktop.org" target="_blank">mesa-dev@lists.freedesktop.org</a> <mailto:<a href="mailto:mesa-dev@lists.freedesktop.org" target="_blank">mesa-dev@lists.<u></u>freedesktop.org</a>><br>
    <a href="http://lists.freedesktop.org/mailman/listinfo/mesa-dev" target="_blank">http://lists.freedesktop.org/<u></u>mailman/listinfo/mesa-dev</a><br>
    <<a href="https://urldefense.proofpoint.com/v2/url?u=http-3A__lists.freedesktop.org_mailman_listinfo_mesa-2Ddev&d=AwMFaQ&c=Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-YihVMNtXt-uEs&r=T0t4QG7chq2ZwJo6wilkFznRSFy-8uDKartPGbomVj8&m=WWWcDPCoYwfOyILpH0kA7-k-qpSPTsIs1qycAmB5GNA&s=GrUeebJuM5x75DOASs1ezQdYEv5z61wojf4LHxr7Rvc&e=" target="_blank">https://urldefense.<u></u>proofpoint.com/v2/url?u=http-<u></u>3A__lists.freedesktop.org_<u></u>mailman_listinfo_mesa-2Ddev&d=<u></u>AwMFaQ&c=<u></u>Sqcl0Ez6M0X8aeM67LKIiDJAXVeAw-<u></u>YihVMNtXt-uEs&r=<u></u>T0t4QG7chq2ZwJo6wilkFznRSFy-<u></u>8uDKartPGbomVj8&m=<u></u>WWWcDPCoYwfOyILpH0kA7-k-<u></u>qpSPTsIs1qycAmB5GNA&s=<u></u>GrUeebJuM5x75DOASs1ezQdYEv5z61<u></u>wojf4LHxr7Rvc&e=</a>><br>
<br>
</blockquote>
<br>
</blockquote></div></div>
</div></div></blockquote></div></div>