<p dir="ltr"><br>
On Jan 9, 2015 6:33 AM, "Neil Roberts" <<a href="mailto:neil@linux.intel.com">neil@linux.intel.com</a>> wrote:<br>
><br>
> This patch looks really good. I have some comments below.<br>
><br>
> Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> writes:<br>
><br>
> > This meta path, designed for use with PBO's, creates a temporary texture<br>
> > out of the PBO and uses BlitFramebuffers to do the actual texture upload.<br>
> > ---<br>
> >  src/mesa/Makefile.sources                   |   1 +<br>
> >  src/mesa/drivers/common/meta.h              |   9 ++<br>
> >  src/mesa/drivers/common/meta_tex_subimage.c | 211 ++++++++++++++++++++++++++++<br>
> >  3 files changed, 221 insertions(+)<br>
> >  create mode 100644 src/mesa/drivers/common/meta_tex_subimage.c<br>
> ><br>
> > diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources<br>
> > index 44cfafa..3261b28 100644<br>
> > --- a/src/mesa/Makefile.sources<br>
> > +++ b/src/mesa/Makefile.sources<br>
> > @@ -585,6 +585,7 @@ COMMON_DRIVER_FILES =                     \<br>
> >       $(SRCDIR)drivers/common/meta_blit.c     \<br>
> >       $(SRCDIR)drivers/common/meta_copy_image.c       \<br>
> >       $(SRCDIR)drivers/common/meta_generate_mipmap.c  \<br>
> > +     $(SRCDIR)drivers/common/meta_tex_subimage.c     \<br>
> >       $(SRCDIR)drivers/common/meta.c \<br>
> >       $(SRCDIR)drivers/common/meta.h<br>
> ><br>
> > diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h<br>
> > index 6ecf3c0..90cbd55 100644<br>
> > --- a/src/mesa/drivers/common/meta.h<br>
> > +++ b/src/mesa/drivers/common/meta.h<br>
> > @@ -519,6 +519,15 @@ extern void<br>
> >  _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,<br>
> >                            struct gl_texture_object *texObj);<br>
> ><br>
> > +extern bool<br>
> > +_mesa_meta_TexSubImage(struct gl_context *ctx, GLuint dims,<br>
> > +                       struct gl_texture_image *tex_image,<br>
> > +                       int xoffset, int yoffset, int zoffset,<br>
> > +                       int width, int height, int depth,<br>
> > +                       GLenum format, GLenum type, const void *pixels,<br>
> > +                       bool allocate_storage, bool create_pbo,<br>
> > +                       const struct gl_pixelstore_attrib *packing);<br>
> > +<br>
> >  extern void<br>
> >  _mesa_meta_CopyTexSubImage(struct gl_context *ctx, GLuint dims,<br>
> >                             struct gl_texture_image *texImage,<br>
> > diff --git a/src/mesa/drivers/common/meta_tex_subimage.c b/src/mesa/drivers/common/meta_tex_subimage.c<br>
> > new file mode 100644<br>
> > index 0000000..195f600<br>
> > --- /dev/null<br>
> > +++ b/src/mesa/drivers/common/meta_tex_subimage.c<br>
> > @@ -0,0 +1,211 @@<br>
> > +/*<br>
> > + * Mesa 3-D graphics library<br>
> > + *<br>
> > + * Copyright (C) 2015 Intel Corporation.  All Rights Reserved.<br>
> > + *<br>
> > + * Permission is hereby granted, free of charge, to any person obtaining a<br>
> > + * copy of this software and associated documentation files (the "Software"),<br>
> > + * to deal in the Software without restriction, including without limitation<br>
> > + * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
> > + * and/or sell copies of the Software, and to permit persons to whom the<br>
> > + * Software is furnished to do so, subject to the following conditions:<br>
> > + *<br>
> > + * The above copyright notice and this permission notice shall be included<br>
> > + * in all copies or substantial portions of the Software.<br>
> > + *<br>
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS<br>
> > + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR<br>
> > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
> > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR<br>
> > + * OTHER DEALINGS IN THE SOFTWARE.<br>
> > + */<br>
> > +<br>
> > +#include "glheader.h"<br>
> > +#include "context.h"<br>
> > +#include "enums.h"<br>
> > +#include "imports.h"<br>
> > +#include "macros.h"<br>
> > +#include "teximage.h"<br>
> > +#include "texobj.h"<br>
> > +#include "fbobject.h"<br>
> > +#include "buffers.h"<br>
> > +#include "state.h"<br>
> > +<br>
> > +#include "bufferobj.h"<br>
> > +#include "pbo.h"<br>
> > +#include "meta.h"<br>
> > +#include "glformats.h"<br>
> > +#include "shaderapi.h"<br>
> > +#include "uniforms.h"<br>
> > +#include "texstate.h"<br>
> > +#include "varray.h"<br>
> > +<br>
> > +<br>
> > +bool<br>
> > +_mesa_meta_TexSubImage(struct gl_context *ctx, GLuint dims,<br>
> > +                       struct gl_texture_image *tex_image,<br>
> > +                       int xoffset, int yoffset, int zoffset,<br>
> > +                       int width, int height, int depth,<br>
> > +                       GLenum format, GLenum type, const void *pixels,<br>
> > +                       bool allocate_storage, bool create_pbo,<br>
> > +                       const struct gl_pixelstore_attrib *packing)<br>
> > +{<br>
> > +   uint32_t pbo_format;<br>
> > +   GLenum internal_format, status;<br>
> > +   GLuint pbo = 0, pbo_tex = 0, row_stride, size;<br>
> > +   GLuint fbos[2] = { 0, 0 };<br>
> > +   struct gl_texture_object *pbo_tex_obj;<br>
> > +   struct gl_texture_image *pbo_tex_image;<br>
> > +   struct gl_buffer_object *buffer_obj;<br>
> > +   bool success = false;<br>
> > +<br>
> > +   /* XXX: This should probably be passed in from somewhere */<br>
> > +   const char *where = "_mesa_meta_TexSubImage";<br>
> > +<br>
> > +   if (!_mesa_is_bufferobj(packing->BufferObj) && !create_pbo)<br>
> > +      return false;<br>
> > +<br>
> > +   if (format == GL_DEPTH_COMPONENT ||<br>
> > +       format == GL_DEPTH_STENCIL ||<br>
> > +       format == GL_STENCIL_INDEX ||<br>
> > +       format == GL_COLOR_INDEX)<br>
> > +      return false;<br>
> > +<br>
> > +   if (packing->Alignment > 4 ||<br>
> > +       packing->SkipPixels > 0 ||<br>
> > +       packing->SkipRows > 0 ||<br>
> > +       (packing->RowLength != 0 && packing->RowLength != width) ||<br>
> > +       packing->SwapBytes ||<br>
> > +       packing->LsbFirst ||<br>
> > +       packing->Invert)<br>
> > +      return false;<br>
><br>
> Is there any reason for all these restrictions on the row length,<br>
> alignment and skip offsets? If ‘pixels’ is already an arbitrary byte<br>
> offset we can use _mesa_image_offset to just add the skip values to the<br>
> offset.</p>
<p dir="ltr">No good one. We can't handle swapbytes or lsbfirst, but the pointer offset ones  and RowLength are totally doable.  I'll get that hooked up.</p>
<p dir="ltr">> These restrictions effectively make the texsubimage tests skip this code<br>
> path because they all use the skip offsets. I've made a little tweak to<br>
> the test cases here so that it will work:<br>
><br>
> <a href="https://github.com/bpeel/piglit/tree/test-texsubimage-no-skip">https://github.com/bpeel/piglit/tree/test-texsubimage-no-skip</a><br>
><br>
> With that branch the test fails when it needs to do a conversion such as<br>
> when it uploads RGBA/UNSIGNED_BYTE data to an internal format of<br>
> GL_RGB5. This might be something to do with having different rounding<br>
> when the hardware converts rather than whatever mesa does to convert<br>
> when no PBO is used. If that's the case I guess it's not really a<br>
> problem but it is a bit weird to have different results depending on<br>
> whether you upload via a PBO or not.<br>
><br>
> I don't like all the places in Mesa that try to restrict the possible<br>
> row stride values by checking Alignment and RowLength. For example if<br>
> the image is RGBA with a width of 2 then an alignment of 8 is equivalent<br>
> to an alignment of 1 and this check would needlessly disallow it. I<br>
> think it is better to just treat those values as a way to calculate the<br>
> row stride and then check for the restrictions based on the row stride<br>
> value instead. In this case I think it would be better to let the driver<br>
> check for limitations in the implementation of<br>
> SetTextureStorageForBufferObject instead. I think in this case because<br>
> the source buffer is not tiled the hardware doesn't even have any<br>
> limitations, does it?</p>
<p dir="ltr">Correct. I was just lazy and wanted to get stuff on the list so people like you could look at it.</p>
<p dir="ltr">><br>
> > +<br>
> > +   pbo_format = _mesa_format_from_format_and_type(format, type);<br>
> > +   if (_mesa_format_is_mesa_array_format(pbo_format))<br>
> > +      pbo_format = _mesa_format_from_array_format(pbo_format);<br>
> > +<br>
> > +   if (!pbo_format)<br>
> > +      return false;<br>
> > +<br>
> > +   if (!ctx->TextureFormatSupported[pbo_format])<br>
> > +      return false;<br>
> > +<br>
> > +   internal_format = _mesa_get_format_base_format(pbo_format);<br>
> > +   row_stride = _mesa_format_row_stride(pbo_format, width);<br>
> > +<br>
> > +   if (!_mesa_validate_pbo_access(dims, packing, width, height, depth,<br>
> > +                                  format, type, INT_MAX, pixels)) {<br>
> > +      _mesa_error(ctx, GL_INVALID_OPERATION,<br>
> > +                  "%s(out of bounds PBO access)", where);<br>
> > +      return true;<br>
> > +   }<br>
> > +<br>
> > +   if (_mesa_check_disallowed_mapping(packing->BufferObj)) {<br>
> > +      /* buffer is mapped - that's an error */<br>
> > +      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where);<br>
> > +      return true;<br>
> > +   }<br>
> > +<br>
> > +   if (allocate_storage)<br>
> > +      ctx->Driver.AllocTextureImageBuffer(ctx, tex_image);<br>
> > +<br>
> > +   /* Only stash the current FBO */<br>
> > +   _mesa_meta_begin(ctx, 0);<br>
> > +<br>
> > +   pbo = 0;<br>
> > +   if (_mesa_is_bufferobj(packing->BufferObj)) {<br>
> > +      buffer_obj = packing->BufferObj;<br>
> > +   } else {<br>
> > +      assert(create_pbo);<br>
> > +<br>
> > +      _mesa_GenBuffers(1, &pbo);<br>
> > +<br>
> > +      /* We know the client doesn't have this bound */<br>
> > +      _mesa_BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);<br>
> > +<br>
> > +      size = _mesa_format_image_size(pbo_format, width, height, depth);<br>
> > +      _mesa_BufferData(GL_PIXEL_UNPACK_BUFFER, size, pixels, GL_STREAM_DRAW);<br>
> > +<br>
> > +      buffer_obj = ctx->Unpack.BufferObj;<br>
> > +      pixels = NULL;<br>
> > +<br>
> > +      _mesa_BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);<br>
> > +   }<br>
> > +<br>
> > +   _mesa_GenTextures(1, &pbo_tex);<br>
> > +   pbo_tex_obj = _mesa_lookup_texture(ctx, pbo_tex);<br>
> > +   pbo_tex_obj->Target = depth > 2 ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;<br>
><br>
> Should that be depth > 1?<br>
><br>
> > +   pbo_tex_obj->Immutable = GL_TRUE;<br>
> > +   _mesa_initialize_texture_object(ctx, pbo_tex_obj, pbo_tex, GL_TEXTURE_2D);<br>
> > +<br>
> > +   pbo_tex_image = _mesa_get_tex_image(ctx, pbo_tex_obj,<br>
> > +                                       pbo_tex_obj->Target, 0);<br>
> > +   _mesa_init_teximage_fields(ctx, pbo_tex_image, width, height, depth,<br>
> > +                              0, internal_format, pbo_format);<br>
> > +<br>
> > +   if (!ctx->Driver.SetTextureStorageForBufferObject(ctx, pbo_tex_obj,<br>
> > +                                                     buffer_obj,<br>
> > +                                                     (intptr_t)pixels,<br>
> > +                                                     row_stride)) {<br>
> > +      goto fail;<br>
> > +   }<br>
> > +<br>
> > +   _mesa_GenFramebuffers(2, fbos);<br>
> > +   _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);<br>
> > +   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);<br>
> > +<br>
> > +   if (tex_image->TexObject->Target == GL_TEXTURE_1D_ARRAY) {<br>
> > +      assert(depth == 1);<br>
> > +      depth = height;<br>
> > +      height = 1;<br>
> > +   }<br>
> > +<br>
> > +   _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,<br>
> > +                             pbo_tex_image, 0);<br>
> > +   /* If this passes on the first layer it should pass on the others */<br>
> > +   status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);<br>
> > +   if (status != GL_FRAMEBUFFER_COMPLETE)<br>
> > +      goto fail;<br>
> > +<br>
> > +   _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,<br>
> > +                             tex_image, zoffset);<br>
> > +   /* If this passes on the first layer it should pass on the others */<br>
> > +   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);<br>
> > +   if (status != GL_FRAMEBUFFER_COMPLETE)<br>
> > +      goto fail;<br>
> > +<br>
> > +   _mesa_update_state(ctx);<br>
> > +<br>
> > +   if (_mesa_meta_BlitFramebuffer(ctx, 0, 0, width, height,<br>
> > +                                  xoffset, yoffset,<br>
> > +                                  xoffset + width, yoffset + height,<br>
> > +                                  GL_COLOR_BUFFER_BIT, GL_NEAREST))<br>
> > +      goto fail;<br>
><br>
> Is there a good reason to use _mesa_meta_BlitFramebuffer here and not<br>
> _mesa_BlitFramebuffer? The driver might have a faster blit<br>
> implementation than the meta path. intel_blit_framebuffer seems to<br>
> prefer the blorp blitter and then the BLT blitter over the meta path. I<br>
> guess the meta blitter might be faster but we should probably fix that<br>
> in intel_blit_framebuffer instead if that is the case.</p>
<p dir="ltr">Yes, that is a risk we face here. However, using the meta call explicitly guarantees that we never hit a software fallback.  Doing so would be worse than the regular upload path.  Also, for BDW+, we don't have blorp, so we wouldn't really get any benignity anyway.</p>
<p dir="ltr">> > +<br>
> > +   for (int z = 1; z < depth; z++) {<br>
> > +      _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,<br>
> > +                                pbo_tex_image, z);<br>
> > +      _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,<br>
> > +                                tex_image, zoffset + z);<br>
> > +<br>
> > +      _mesa_update_state(ctx);<br>
> > +<br>
> > +      _mesa_meta_BlitFramebuffer(ctx, 0, 0, width, height,<br>
> > +                                 xoffset, yoffset,<br>
> > +                                 xoffset + width, yoffset + height,<br>
> > +                                 GL_COLOR_BUFFER_BIT, GL_NEAREST);<br>
> > +   }<br>
> > +<br>
> > +   success = true;<br>
> > +<br>
> > +fail:<br>
> > +   _mesa_DeleteFramebuffers(2, fbos);<br>
> > +   _mesa_DeleteTextures(1, &pbo_tex);<br>
> > +   _mesa_DeleteBuffers(1, &pbo);<br>
> > +<br>
> > +   _mesa_meta_end(ctx);<br>
> > +<br>
> > +   return success;<br>
> > +}<br>
> > --<br>
> > 2.2.0<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">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</p>