+static bool
+nvc0_bind_images_range(struct nvc0_context *nvc0, const unsigned s,
+ unsigned start, unsigned nr,
+ const struct pipe_image_view *pimages)
+{
+ const unsigned end = start + nr;
+ unsigned mask = 0;
+ unsigned i;
+
+ assert(s < 6);
+
+ if (pimages) {
+ for (i = start; i < end; ++i) {
+ struct pipe_image_view *img = &nvc0->images[s][i];
+ const unsigned p = i - start;
+
+ if (img->resource == pimages[p].resource &&
+ img->format == pimages[p].format &&
+ img->access == pimages[p].access) {
+ if (img->resource == NULL)
+ continue;
+ if (img->resource->target == PIPE_BUFFER &&
+ img->u.buf.offset == pimages[p].u.buf.offset &&
+ img->u.buf.size == pimages[p].u.buf.size)
+ continue;
+ if (img->resource->target != PIPE_BUFFER &&
+ img->u.tex.first_layer == pimages[p].u.tex.first_layer &&
+ img->u.tex.last_layer == pimages[p].u.tex.last_layer &&
+ img->u.tex.level == pimages[p].u.tex.level)
+ continue;
+ }
+
+ mask |= (1 << i);
+ if (pimages[p].resource)
+ nvc0->images_valid[s] |= (1 << i);
+ else
+ nvc0->images_valid[s] &= ~(1 << i);
+
+ img->format = pimages[p].format;
+ img->access = pimages[p].access;
+ if (pimages[p].resource && pimages[p].resource->target == PIPE_BUFFER)
+ img->u.buf = pimages[p].u.buf;
+ else
+ img->u.tex = pimages[p].u.tex;
+
+ pipe_resource_reference(
+ &img->resource, pimages[p].resource);
+
+ if (nvc0->screen->base.class_3d >= GM107_3D_CLASS) {
+ if (nvc0->images_tic[s][i]) {
+ struct nv50_tic_entry *old =
+ nv50_tic_entry(nvc0->images_tic[s][i]);
+ nvc0_screen_tic_unlock(nvc0->screen, old);
+ pipe_sampler_view_reference(&nvc0->images_tic[s][i], NULL);
+ }
+
+ nvc0->images_tic[s][i] =
+ gm107_create_texture_view_from_image(&nvc0->base.pipe,
+ &pimages[p]);
+ }
+ }
+ if (!mask)
+ return false;
+ } else {
+ mask = ((1 << nr) - 1) << start;
+ if (!(nvc0->images_valid[s] & mask))
+ return false;
+ for (i = start; i < end; ++i) {
+ pipe_resource_reference(&nvc0->images[s][i].resource, NULL);
+ if (nvc0->screen->base.class_3d >= GM107_3D_CLASS) {
+ struct nv50_tic_entry *old = nv50_tic_entry(nvc0->images_tic[s][i]);
+ if (old) {
+ nvc0_screen_tic_unlock(nvc0->screen, old);
+ pipe_sampler_view_reference(&nvc0->images_tic[s][i], NULL);
+ }
+ }
+ }
+ nvc0->images_valid[s] &= ~mask;
+ }
+ nvc0->images_dirty[s] |= mask;
+
+ if (s == 5)
+ nouveau_bufctx_reset(nvc0->bufctx_cp, NVC0_BIND_CP_SUF);
+ else
+ nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_SUF);
+
+ return true;
+}
+
+static void
+nvc0_set_shader_images(struct pipe_context *pipe,
+ enum pipe_shader_type shader,
+ unsigned start, unsigned nr,
+ const struct pipe_image_view *images)
+{
+ const unsigned s = nvc0_shader_stage(shader);
+ if (!nvc0_bind_images_range(nvc0_context(pipe), s, start, nr, images))
+ return;
+
+ if (s == 5)
+ nvc0_context(pipe)->dirty_cp |= NVC0_NEW_CP_SURFACES;
+ else
+ nvc0_context(pipe)->dirty_3d |= NVC0_NEW_3D_SURFACES;
+}
+
+static bool
+nvc0_bind_buffers_range(struct nvc0_context *nvc0, const unsigned t,
+ unsigned start, unsigned nr,
+ const struct pipe_shader_buffer *pbuffers)
+{
+ const unsigned end = start + nr;
+ unsigned mask = 0;
+ unsigned i;
+
+ assert(t < 6);
+
+ if (pbuffers) {
+ for (i = start; i < end; ++i) {
+ struct pipe_shader_buffer *buf = &nvc0->buffers[t][i];
+ const unsigned p = i - start;
+ if (buf->buffer == pbuffers[p].buffer &&
+ buf->buffer_offset == pbuffers[p].buffer_offset &&
+ buf->buffer_size == pbuffers[p].buffer_size)
+ continue;
+
+ mask |= (1 << i);
+ if (pbuffers[p].buffer)
+ nvc0->buffers_valid[t] |= (1 << i);
+ else
+ nvc0->buffers_valid[t] &= ~(1 << i);
+ buf->buffer_offset = pbuffers[p].buffer_offset;
+ buf->buffer_size = pbuffers[p].buffer_size;
+ pipe_resource_reference(&buf->buffer, pbuffers[p].buffer);
+ }
+ if (!mask)
+ return false;
+ } else {
+ mask = ((1 << nr) - 1) << start;
+ if (!(nvc0->buffers_valid[t] & mask))
+ return false;
+ for (i = start; i < end; ++i)
+ pipe_resource_reference(&nvc0->buffers[t][i].buffer, NULL);
+ nvc0->buffers_valid[t] &= ~mask;
+ }
+ nvc0->buffers_dirty[t] |= mask;
+
+ if (t == 5)
+ nouveau_bufctx_reset(nvc0->bufctx_cp, NVC0_BIND_CP_BUF);
+ else
+ nouveau_bufctx_reset(nvc0->bufctx_3d, NVC0_BIND_3D_BUF);
+
+ return true;
+}
+