<div dir="ltr"><div>[snip]<br>>> +static unsigned<br>>> +tc_improve_map_buffer_flags(struct threaded_context *tc,<br>>> +                            struct threaded_resource *tres, unsigned<br>>> usage,<br>>> +                            unsigned offset, unsigned size)<br>>> +{<br>>> +   /* Handle CPU reads trivially. */<br>>> +   if (usage & PIPE_TRANSFER_READ) {<br>>> +      /* Driver aren't allowed to do buffer invalidations. */<br>>> +      return (usage & ~PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) |<br>>> +             TC_TRANSFER_MAP_NO_INVALIDATE |<br>>> +             TC_TRANSFER_MAP_IGNORE_VALID_RANGE;<br>>> +   }<br>>> +<br>>> +   /* Sparse buffers can't be mapped directly. Use a staging buffer. */<br>>> +   if (tres->b.flags & PIPE_RESOURCE_FLAG_SPARSE) {<br>>> +      return (usage & ~(PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE |<br>>> +                        PIPE_TRANSFER_UNSYNCHRONIZED)) |<br>>> +             PIPE_TRANSFER_DISCARD_RANGE |<br>><br>><br>> Why are we allowed to discard here? Even when a range is mapped only for<br>> writing, we can't just assume that the whole range will be written by the<br>> application.<br>><br>> Also, why do we clear the unsynchronized flag? As I understand the code, we<br>> do need to synchronize the threads because we're going to use a staging<br>> buffer. But theoretically, if the driver had a way to do the staging copy<br>> without waiting for previously submitted draws, it could do so. So... I<br>> don't think it has a visible effect right now, but I'd rather not remove the<br>> unsynchronized flag here.<br>><br>> This may need a bit of clarification in the big comment in the header file.<br><br>That code was indeed completely wrong. I've changed it to this and I moved this block to the beginning of the function (before the READ handling):<br><br>   /* Sparse buffers can't be mapped directly and can't be reallocated<br>    * (fully invalidated). That may just be a radeonsi limitation, but<br>    * the threaded context must obey it with radeonsi.<br>    */<br>   if (tres->b.flags & PIPE_RESOURCE_FLAG_SPARSE) {<br>      /* We can use DISCARD_RANGE instead of full discard. This is the only<br>       * fast path for sparse buffers that doesn't need thread synchronization.<br>       */<br>      if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)<br>         usage |= PIPE_TRANSFER_DISCARD_RANGE;<br><br>      /* Allow DISCARD_WHOLE_RESOURCE and infering UNSYNCHRONIZED in drivers.<br>       * The threaded context doesn't do unsychronized mappings and invalida-<br>       * tions of sparse buffers, therefore a correct driver behavior won't<br>       * result in an incorrect behavior with the threaded context.<br>       */<br>      return usage;<br>   }<br><br><br><br>><br>><br>><br>>> +             TC_TRANSFER_MAP_NO_INVALIDATE |<br>>> +             TC_TRANSFER_MAP_IGNORE_VALID_RANGE;<br>>> +   }<br></div><br>[snip]<br><div>>> +         ttrans->b.level = 0;<br>>> +         ttrans->b.usage = usage;<br>>> +         ttrans->b.box = *box;<br>>> +         ttrans->b.stride = 0;<br>>> +         ttrans->b.layer_stride = 0;<br>>> +         *transfer = &ttrans->b;<br>>> +         return map + (box->x % tc->map_buffer_alignment);<br>>> +      }<br>>> +   }<br>>> +<br>>> +   /* Unsychronized buffer mappings don't have to synchronize the thread.<br>>> */<br>>> +   if (!(usage & TC_TRANSFER_MAP_THREADED_UNSYNC))<br>>> +      tc_sync_msg(tc, resource->target != PIPE_BUFFER ? "  texture" :<br>>> +                      usage & PIPE_TRANSFER_DISCARD_RANGE ? "<br>>> discard_range" :<br>>> +                      usage & PIPE_TRANSFER_READ ? "  read" : "  ??");<br>>> +<br>>> +   return pipe->transfer_map(pipe, tres->latest ? tres->latest :<br>>> resource,<br>>> +                             level, usage, box, transfer);<br>><br>><br>> The ternary operator here should be unnecessary -- tres->latest should<br>> always be non-NULL.<br><br></div><div>It's necessary because this codepath is also used by textures where tres->latest == NULL because it's not initialized explicitly.<br></div><div><br></div><div>[snip]<br></div><div>>> +<br>>> +static boolean<br>>> +tc_generate_mipmap(struct pipe_context *_pipe,<br>>> +                   struct pipe_resource *res,<br>>> +                   enum pipe_format format,<br>>> +                   unsigned base_level,<br>>> +                   unsigned last_level,<br>>> +                   unsigned first_layer,<br>>> +                   unsigned last_layer)<br>>> +{<br>>> +   struct threaded_context *tc = threaded_context(_pipe);<br>>> +   struct pipe_context *pipe = tc->pipe;<br>>> +   struct pipe_screen *screen = pipe->screen;<br>>> +   unsigned bind = PIPE_BIND_SAMPLER_VIEW;<br>>> +<br>>> +   if (util_format_is_depth_or_stencil(format))<br>>> +      bind = PIPE_BIND_DEPTH_STENCIL;<br>>> +   else<br>>> +      bind = PIPE_BIND_RENDER_TARGET;<br>>> +<br>>> +   if (!screen->is_format_supported(screen, format, res->target,<br>>> +                                    res->nr_samples, bind))<br>>> +      return false;<br>><br>><br>> This feels like the kind of thing the state tracker should be checking<br>> before it calls this function...<br><br></div><div>True, but the Gallium interface is currently defined such that drivers do it.<br><br></div><div>Marek</div><br></div>