1af69d88dSmrg/*
2af69d88dSmrg * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
3af69d88dSmrg *
4af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5af69d88dSmrg * copy of this software and associated documentation files (the "Software"),
6af69d88dSmrg * to deal in the Software without restriction, including without limitation
7af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9af69d88dSmrg * Software is furnished to do so, subject to the following conditions:
10af69d88dSmrg *
11af69d88dSmrg * The above copyright notice and this permission notice (including the next
12af69d88dSmrg * paragraph) shall be included in all copies or substantial portions of the
13af69d88dSmrg * Software.
14af69d88dSmrg *
15af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16af69d88dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19af69d88dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20af69d88dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21af69d88dSmrg * SOFTWARE.
22af69d88dSmrg *
23af69d88dSmrg * Authors:
24af69d88dSmrg *    Rob Clark <robclark@freedesktop.org>
25af69d88dSmrg */
26af69d88dSmrg
27af69d88dSmrg#include "pipe/p_state.h"
2801e04c3fSmrg#include "util/u_dual_blend.h"
29af69d88dSmrg#include "util/u_helpers.h"
307ec681f3Smrg#include "util/u_memory.h"
317ec681f3Smrg#include "util/u_string.h"
32af69d88dSmrg
33af69d88dSmrg#include "freedreno_context.h"
34af69d88dSmrg#include "freedreno_gmem.h"
3501e04c3fSmrg#include "freedreno_query_hw.h"
367ec681f3Smrg#include "freedreno_resource.h"
377ec681f3Smrg#include "freedreno_state.h"
387ec681f3Smrg#include "freedreno_texture.h"
39af69d88dSmrg#include "freedreno_util.h"
40af69d88dSmrg
417ec681f3Smrg#define get_safe(ptr, field) ((ptr) ? (ptr)->field : 0)
427ec681f3Smrg
43af69d88dSmrg/* All the generic state handling.. In case of CSO's that are specific
44af69d88dSmrg * to the GPU version, when the bind and the delete are common they can
45af69d88dSmrg * go in here.
46af69d88dSmrg */
47af69d88dSmrg
487ec681f3Smrgstatic void
497ec681f3Smrgupdate_draw_cost(struct fd_context *ctx) assert_dt
507ec681f3Smrg{
517ec681f3Smrg   struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
527ec681f3Smrg
537ec681f3Smrg   ctx->draw_cost = pfb->nr_cbufs;
547ec681f3Smrg   for (unsigned i = 0; i < pfb->nr_cbufs; i++)
557ec681f3Smrg      if (fd_blend_enabled(ctx, i))
567ec681f3Smrg         ctx->draw_cost++;
577ec681f3Smrg   if (fd_depth_enabled(ctx))
587ec681f3Smrg      ctx->draw_cost++;
597ec681f3Smrg   if (fd_depth_write_enabled(ctx))
607ec681f3Smrg      ctx->draw_cost++;
617ec681f3Smrg}
627ec681f3Smrg
63af69d88dSmrgstatic void
64af69d88dSmrgfd_set_blend_color(struct pipe_context *pctx,
657ec681f3Smrg                   const struct pipe_blend_color *blend_color) in_dt
66af69d88dSmrg{
677ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
687ec681f3Smrg   ctx->blend_color = *blend_color;
697ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_BLEND_COLOR);
70af69d88dSmrg}
71af69d88dSmrg
72af69d88dSmrgstatic void
73af69d88dSmrgfd_set_stencil_ref(struct pipe_context *pctx,
747ec681f3Smrg                   const struct pipe_stencil_ref stencil_ref) in_dt
75af69d88dSmrg{
767ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
777ec681f3Smrg   ctx->stencil_ref = stencil_ref;
787ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_STENCIL_REF);
79af69d88dSmrg}
80af69d88dSmrg
81af69d88dSmrgstatic void
82af69d88dSmrgfd_set_clip_state(struct pipe_context *pctx,
837ec681f3Smrg                  const struct pipe_clip_state *clip) in_dt
84af69d88dSmrg{
857ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
867ec681f3Smrg   ctx->ucp = *clip;
877ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_UCP);
88af69d88dSmrg}
89af69d88dSmrg
90af69d88dSmrgstatic void
917ec681f3Smrgfd_set_sample_mask(struct pipe_context *pctx, unsigned sample_mask) in_dt
92af69d88dSmrg{
937ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
947ec681f3Smrg   ctx->sample_mask = (uint16_t)sample_mask;
957ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_SAMPLE_MASK);
96af69d88dSmrg}
97af69d88dSmrg
989f464c52Smayastatic void
997ec681f3Smrgfd_set_min_samples(struct pipe_context *pctx, unsigned min_samples) in_dt
1009f464c52Smaya{
1017ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
1027ec681f3Smrg   ctx->min_samples = min_samples;
1037ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_MIN_SAMPLES);
1049f464c52Smaya}
1059f464c52Smaya
106af69d88dSmrg/* notes from calim on #dri-devel:
107af69d88dSmrg * index==0 will be non-UBO (ie. glUniformXYZ()) all packed together padded
108af69d88dSmrg * out to vec4's
109af69d88dSmrg * I should be able to consider that I own the user_ptr until the next
110af69d88dSmrg * set_constant_buffer() call, at which point I don't really care about the
111af69d88dSmrg * previous values.
112af69d88dSmrg * index>0 will be UBO's.. well, I'll worry about that later
113af69d88dSmrg */
114af69d88dSmrgstatic void
1157ec681f3Smrgfd_set_constant_buffer(struct pipe_context *pctx, enum pipe_shader_type shader,
1167ec681f3Smrg                       uint index, bool take_ownership,
1177ec681f3Smrg                       const struct pipe_constant_buffer *cb) in_dt
118af69d88dSmrg{
1197ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
1207ec681f3Smrg   struct fd_constbuf_stateobj *so = &ctx->constbuf[shader];
12101e04c3fSmrg
1227ec681f3Smrg   util_copy_constant_buffer(&so->cb[index], cb, take_ownership);
12301e04c3fSmrg
1247ec681f3Smrg   /* Note that gallium frontends can unbind constant buffers by
1257ec681f3Smrg    * passing NULL here.
1267ec681f3Smrg    */
1277ec681f3Smrg   if (unlikely(!cb)) {
1287ec681f3Smrg      so->enabled_mask &= ~(1 << index);
1297ec681f3Smrg      return;
1307ec681f3Smrg   }
13101e04c3fSmrg
1327ec681f3Smrg   so->enabled_mask |= 1 << index;
13301e04c3fSmrg
1347ec681f3Smrg   fd_context_dirty_shader(ctx, shader, FD_DIRTY_SHADER_CONST);
1357ec681f3Smrg   fd_resource_set_usage(cb->buffer, FD_DIRTY_CONST);
13601e04c3fSmrg
1377ec681f3Smrg   if (index > 0) {
1387ec681f3Smrg      assert(!cb->user_buffer);
1397ec681f3Smrg      ctx->dirty |= FD_DIRTY_RESOURCE;
1407ec681f3Smrg   }
1417ec681f3Smrg}
14201e04c3fSmrg
1437ec681f3Smrgstatic void
1447ec681f3Smrgfd_set_shader_buffers(struct pipe_context *pctx, enum pipe_shader_type shader,
1457ec681f3Smrg                      unsigned start, unsigned count,
1467ec681f3Smrg                      const struct pipe_shader_buffer *buffers,
1477ec681f3Smrg                      unsigned writable_bitmask) in_dt
1487ec681f3Smrg{
1497ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
1507ec681f3Smrg   struct fd_shaderbuf_stateobj *so = &ctx->shaderbuf[shader];
1517ec681f3Smrg   const unsigned modified_bits = u_bit_consecutive(start, count);
1527ec681f3Smrg
1537ec681f3Smrg   so->enabled_mask &= ~modified_bits;
1547ec681f3Smrg   so->writable_mask &= ~modified_bits;
1557ec681f3Smrg   so->writable_mask |= writable_bitmask << start;
1567ec681f3Smrg
1577ec681f3Smrg   for (unsigned i = 0; i < count; i++) {
1587ec681f3Smrg      unsigned n = i + start;
1597ec681f3Smrg      struct pipe_shader_buffer *buf = &so->sb[n];
1607ec681f3Smrg
1617ec681f3Smrg      if (buffers && buffers[i].buffer) {
1627ec681f3Smrg         if ((buf->buffer == buffers[i].buffer) &&
1637ec681f3Smrg             (buf->buffer_offset == buffers[i].buffer_offset) &&
1647ec681f3Smrg             (buf->buffer_size == buffers[i].buffer_size))
1657ec681f3Smrg            continue;
1667ec681f3Smrg
1677ec681f3Smrg         buf->buffer_offset = buffers[i].buffer_offset;
1687ec681f3Smrg         buf->buffer_size = buffers[i].buffer_size;
1697ec681f3Smrg         pipe_resource_reference(&buf->buffer, buffers[i].buffer);
1707ec681f3Smrg
1717ec681f3Smrg         fd_resource_set_usage(buffers[i].buffer, FD_DIRTY_SSBO);
1727ec681f3Smrg
1737ec681f3Smrg         so->enabled_mask |= BIT(n);
1747ec681f3Smrg
1757ec681f3Smrg         if (writable_bitmask & BIT(i)) {
1767ec681f3Smrg            struct fd_resource *rsc = fd_resource(buf->buffer);
1777ec681f3Smrg            util_range_add(&rsc->b.b, &rsc->valid_buffer_range,
1787ec681f3Smrg                           buf->buffer_offset,
1797ec681f3Smrg                           buf->buffer_offset + buf->buffer_size);
1807ec681f3Smrg         }
1817ec681f3Smrg      } else {
1827ec681f3Smrg         pipe_resource_reference(&buf->buffer, NULL);
1837ec681f3Smrg      }
1847ec681f3Smrg   }
1857ec681f3Smrg
1867ec681f3Smrg   fd_context_dirty_shader(ctx, shader, FD_DIRTY_SHADER_SSBO);
1877ec681f3Smrg}
18801e04c3fSmrg
1897ec681f3Smrgvoid
1907ec681f3Smrgfd_set_shader_images(struct pipe_context *pctx, enum pipe_shader_type shader,
1917ec681f3Smrg                     unsigned start, unsigned count,
1927ec681f3Smrg                     unsigned unbind_num_trailing_slots,
1937ec681f3Smrg                     const struct pipe_image_view *images) in_dt
1947ec681f3Smrg{
1957ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
1967ec681f3Smrg   struct fd_shaderimg_stateobj *so = &ctx->shaderimg[shader];
19701e04c3fSmrg
1987ec681f3Smrg   unsigned mask = 0;
19901e04c3fSmrg
2007ec681f3Smrg   if (images) {
2017ec681f3Smrg      for (unsigned i = 0; i < count; i++) {
2027ec681f3Smrg         unsigned n = i + start;
2037ec681f3Smrg         struct pipe_image_view *buf = &so->si[n];
20401e04c3fSmrg
2057ec681f3Smrg         if ((buf->resource == images[i].resource) &&
2067ec681f3Smrg             (buf->format == images[i].format) &&
2077ec681f3Smrg             (buf->access == images[i].access) &&
2087ec681f3Smrg             !memcmp(&buf->u, &images[i].u, sizeof(buf->u)))
2097ec681f3Smrg            continue;
21001e04c3fSmrg
2117ec681f3Smrg         mask |= BIT(n);
2127ec681f3Smrg         util_copy_image_view(buf, &images[i]);
21301e04c3fSmrg
2147ec681f3Smrg         if (buf->resource) {
2157ec681f3Smrg            fd_resource_set_usage(buf->resource, FD_DIRTY_IMAGE);
2167ec681f3Smrg            so->enabled_mask |= BIT(n);
21701e04c3fSmrg
2187ec681f3Smrg            if ((buf->access & PIPE_IMAGE_ACCESS_WRITE) &&
2197ec681f3Smrg                (buf->resource->target == PIPE_BUFFER)) {
22001e04c3fSmrg
2217ec681f3Smrg               struct fd_resource *rsc = fd_resource(buf->resource);
2227ec681f3Smrg               util_range_add(&rsc->b.b, &rsc->valid_buffer_range,
2237ec681f3Smrg                              buf->u.buf.offset,
2247ec681f3Smrg                              buf->u.buf.offset + buf->u.buf.size);
2257ec681f3Smrg            }
2267ec681f3Smrg         } else {
2277ec681f3Smrg            so->enabled_mask &= ~BIT(n);
2287ec681f3Smrg         }
2297ec681f3Smrg      }
2307ec681f3Smrg   } else {
2317ec681f3Smrg      mask = (BIT(count) - 1) << start;
23201e04c3fSmrg
2337ec681f3Smrg      for (unsigned i = 0; i < count; i++) {
2347ec681f3Smrg         unsigned n = i + start;
2357ec681f3Smrg         struct pipe_image_view *img = &so->si[n];
23601e04c3fSmrg
2377ec681f3Smrg         pipe_resource_reference(&img->resource, NULL);
2387ec681f3Smrg      }
23901e04c3fSmrg
2407ec681f3Smrg      so->enabled_mask &= ~mask;
2417ec681f3Smrg   }
24201e04c3fSmrg
2437ec681f3Smrg   for (unsigned i = 0; i < unbind_num_trailing_slots; i++)
2447ec681f3Smrg      pipe_resource_reference(&so->si[i + start + count].resource, NULL);
24501e04c3fSmrg
2467ec681f3Smrg   so->enabled_mask &=
2477ec681f3Smrg      ~(BITFIELD_MASK(unbind_num_trailing_slots) << (start + count));
24801e04c3fSmrg
2497ec681f3Smrg   fd_context_dirty_shader(ctx, shader, FD_DIRTY_SHADER_IMAGE);
250af69d88dSmrg}
251af69d88dSmrg
2527ec681f3Smrgvoid
253af69d88dSmrgfd_set_framebuffer_state(struct pipe_context *pctx,
2547ec681f3Smrg                         const struct pipe_framebuffer_state *framebuffer)
255af69d88dSmrg{
2567ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
2577ec681f3Smrg   struct pipe_framebuffer_state *cso;
258af69d88dSmrg
2597ec681f3Smrg   DBG("%ux%u, %u layers, %u samples", framebuffer->width, framebuffer->height,
2607ec681f3Smrg       framebuffer->layers, framebuffer->samples);
261af69d88dSmrg
2627ec681f3Smrg   cso = &ctx->framebuffer;
26301e04c3fSmrg
2647ec681f3Smrg   if (util_framebuffer_state_equal(cso, framebuffer))
2657ec681f3Smrg      return;
266af69d88dSmrg
2677ec681f3Smrg   /* Do this *after* checking that the framebuffer state is actually
2687ec681f3Smrg    * changing.  In the fd_blitter_clear() path, we get a pfb update
2697ec681f3Smrg    * to restore the current pfb state, which should not trigger us
2707ec681f3Smrg    * to flush (as that can cause the batch to be freed at a point
2717ec681f3Smrg    * before fd_clear() returns, but after the point where it expects
2727ec681f3Smrg    * flushes to potentially happen.
2737ec681f3Smrg    */
2747ec681f3Smrg   fd_context_switch_from(ctx);
275af69d88dSmrg
2767ec681f3Smrg   util_copy_framebuffer_state(cso, framebuffer);
27701e04c3fSmrg
2787ec681f3Smrg   cso->samples = util_framebuffer_get_num_samples(cso);
27901e04c3fSmrg
2807ec681f3Smrg   if (ctx->screen->reorder) {
2817ec681f3Smrg      struct fd_batch *old_batch = NULL;
28201e04c3fSmrg
2837ec681f3Smrg      fd_batch_reference(&old_batch, ctx->batch);
28401e04c3fSmrg
2857ec681f3Smrg      if (likely(old_batch))
2867ec681f3Smrg         fd_batch_finish_queries(old_batch);
28701e04c3fSmrg
2887ec681f3Smrg      fd_batch_reference(&ctx->batch, NULL);
2897ec681f3Smrg      fd_context_all_dirty(ctx);
2907ec681f3Smrg      ctx->update_active_queries = true;
29101e04c3fSmrg
2927ec681f3Smrg      fd_batch_reference(&old_batch, NULL);
2937ec681f3Smrg   } else if (ctx->batch) {
2947ec681f3Smrg      DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->batch->needs_flush,
2957ec681f3Smrg          framebuffer->cbufs[0], framebuffer->zsbuf);
2967ec681f3Smrg      fd_batch_flush(ctx->batch);
2977ec681f3Smrg   }
298af69d88dSmrg
2997ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_FRAMEBUFFER);
300af69d88dSmrg
3017ec681f3Smrg   ctx->disabled_scissor.minx = 0;
3027ec681f3Smrg   ctx->disabled_scissor.miny = 0;
3037ec681f3Smrg   ctx->disabled_scissor.maxx = cso->width;
3047ec681f3Smrg   ctx->disabled_scissor.maxy = cso->height;
305af69d88dSmrg
3067ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_SCISSOR);
3077ec681f3Smrg   update_draw_cost(ctx);
308af69d88dSmrg}
309af69d88dSmrg
310af69d88dSmrgstatic void
311af69d88dSmrgfd_set_polygon_stipple(struct pipe_context *pctx,
3127ec681f3Smrg                       const struct pipe_poly_stipple *stipple) in_dt
313af69d88dSmrg{
3147ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
3157ec681f3Smrg   ctx->stipple = *stipple;
3167ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_STIPPLE);
317af69d88dSmrg}
318af69d88dSmrg
319af69d88dSmrgstatic void
3207ec681f3Smrgfd_set_scissor_states(struct pipe_context *pctx, unsigned start_slot,
3217ec681f3Smrg                      unsigned num_scissors,
3227ec681f3Smrg                      const struct pipe_scissor_state *scissor) in_dt
323af69d88dSmrg{
3247ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
325af69d88dSmrg
3267ec681f3Smrg   ctx->scissor = *scissor;
3277ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_SCISSOR);
328af69d88dSmrg}
329af69d88dSmrg
330af69d88dSmrgstatic void
3317ec681f3Smrgfd_set_viewport_states(struct pipe_context *pctx, unsigned start_slot,
3327ec681f3Smrg                       unsigned num_viewports,
3337ec681f3Smrg                       const struct pipe_viewport_state *viewport) in_dt
334af69d88dSmrg{
3357ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
3367ec681f3Smrg   struct pipe_scissor_state *scissor = &ctx->viewport_scissor;
3377ec681f3Smrg   float minx, miny, maxx, maxy;
3387ec681f3Smrg
3397ec681f3Smrg   ctx->viewport = *viewport;
3407ec681f3Smrg
3417ec681f3Smrg   /* see si_get_scissor_from_viewport(): */
3427ec681f3Smrg
3437ec681f3Smrg   /* Convert (-1, -1) and (1, 1) from clip space into window space. */
3447ec681f3Smrg   minx = -viewport->scale[0] + viewport->translate[0];
3457ec681f3Smrg   miny = -viewport->scale[1] + viewport->translate[1];
3467ec681f3Smrg   maxx = viewport->scale[0] + viewport->translate[0];
3477ec681f3Smrg   maxy = viewport->scale[1] + viewport->translate[1];
3487ec681f3Smrg
3497ec681f3Smrg   /* Handle inverted viewports. */
3507ec681f3Smrg   if (minx > maxx) {
3517ec681f3Smrg      swap(minx, maxx);
3527ec681f3Smrg   }
3537ec681f3Smrg   if (miny > maxy) {
3547ec681f3Smrg      swap(miny, maxy);
3557ec681f3Smrg   }
3567ec681f3Smrg
3577ec681f3Smrg   const float max_dims = ctx->screen->gen >= 4 ? 16384.f : 4096.f;
3587ec681f3Smrg
3597ec681f3Smrg   /* Clamp, convert to integer and round up the max bounds. */
3607ec681f3Smrg   scissor->minx = CLAMP(minx, 0.f, max_dims);
3617ec681f3Smrg   scissor->miny = CLAMP(miny, 0.f, max_dims);
3627ec681f3Smrg   scissor->maxx = CLAMP(ceilf(maxx), 0.f, max_dims);
3637ec681f3Smrg   scissor->maxy = CLAMP(ceilf(maxy), 0.f, max_dims);
3647ec681f3Smrg
3657ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_VIEWPORT);
366af69d88dSmrg}
367af69d88dSmrg
368af69d88dSmrgstatic void
3697ec681f3Smrgfd_set_vertex_buffers(struct pipe_context *pctx, unsigned start_slot,
3707ec681f3Smrg                      unsigned count, unsigned unbind_num_trailing_slots,
3717ec681f3Smrg                      bool take_ownership,
3727ec681f3Smrg                      const struct pipe_vertex_buffer *vb) in_dt
373af69d88dSmrg{
3747ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
3757ec681f3Smrg   struct fd_vertexbuf_stateobj *so = &ctx->vtx.vertexbuf;
3767ec681f3Smrg   int i;
3777ec681f3Smrg
3787ec681f3Smrg   /* on a2xx, pitch is encoded in the vtx fetch instruction, so
3797ec681f3Smrg    * we need to mark VTXSTATE as dirty as well to trigger patching
3807ec681f3Smrg    * and re-emitting the vtx shader:
3817ec681f3Smrg    */
3827ec681f3Smrg   if (ctx->screen->gen < 3) {
3837ec681f3Smrg      for (i = 0; i < count; i++) {
3847ec681f3Smrg         bool new_enabled = vb && vb[i].buffer.resource;
3857ec681f3Smrg         bool old_enabled = so->vb[i].buffer.resource != NULL;
3867ec681f3Smrg         uint32_t new_stride = vb ? vb[i].stride : 0;
3877ec681f3Smrg         uint32_t old_stride = so->vb[i].stride;
3887ec681f3Smrg         if ((new_enabled != old_enabled) || (new_stride != old_stride)) {
3897ec681f3Smrg            fd_context_dirty(ctx, FD_DIRTY_VTXSTATE);
3907ec681f3Smrg            break;
3917ec681f3Smrg         }
3927ec681f3Smrg      }
3937ec681f3Smrg   }
3947ec681f3Smrg
3957ec681f3Smrg   util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot,
3967ec681f3Smrg                                count, unbind_num_trailing_slots,
3977ec681f3Smrg                                take_ownership);
3987ec681f3Smrg   so->count = util_last_bit(so->enabled_mask);
3997ec681f3Smrg
4007ec681f3Smrg   if (!vb)
4017ec681f3Smrg      return;
4027ec681f3Smrg
4037ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_VTXBUF);
4047ec681f3Smrg
4057ec681f3Smrg   for (unsigned i = 0; i < count; i++) {
4067ec681f3Smrg      assert(!vb[i].is_user_buffer);
4077ec681f3Smrg      fd_resource_set_usage(vb[i].buffer.resource, FD_DIRTY_VTXBUF);
4087ec681f3Smrg   }
409af69d88dSmrg}
410af69d88dSmrg
411af69d88dSmrgstatic void
4127ec681f3Smrgfd_blend_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
413af69d88dSmrg{
4147ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
4157ec681f3Smrg   struct pipe_blend_state *cso = hwcso;
4167ec681f3Smrg   bool old_is_dual = ctx->blend ? ctx->blend->rt[0].blend_enable &&
4177ec681f3Smrg                                      util_blend_state_is_dual(ctx->blend, 0)
4187ec681f3Smrg                                 : false;
4197ec681f3Smrg   bool new_is_dual =
4207ec681f3Smrg      cso ? cso->rt[0].blend_enable && util_blend_state_is_dual(cso, 0) : false;
4217ec681f3Smrg   ctx->blend = hwcso;
4227ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_BLEND);
4237ec681f3Smrg   if (old_is_dual != new_is_dual)
4247ec681f3Smrg      fd_context_dirty(ctx, FD_DIRTY_BLEND_DUAL);
4257ec681f3Smrg   update_draw_cost(ctx);
426af69d88dSmrg}
427af69d88dSmrg
428af69d88dSmrgstatic void
4297ec681f3Smrgfd_blend_state_delete(struct pipe_context *pctx, void *hwcso) in_dt
430af69d88dSmrg{
4317ec681f3Smrg   FREE(hwcso);
432af69d88dSmrg}
433af69d88dSmrg
434af69d88dSmrgstatic void
4357ec681f3Smrgfd_rasterizer_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
436af69d88dSmrg{
4377ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
4387ec681f3Smrg   struct pipe_scissor_state *old_scissor = fd_context_get_scissor(ctx);
4397ec681f3Smrg   bool discard = get_safe(ctx->rasterizer, rasterizer_discard);
4407ec681f3Smrg   unsigned clip_plane_enable = get_safe(ctx->rasterizer, clip_plane_enable);
4417ec681f3Smrg
4427ec681f3Smrg   ctx->rasterizer = hwcso;
4437ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_RASTERIZER);
4447ec681f3Smrg
4457ec681f3Smrg   if (ctx->rasterizer && ctx->rasterizer->scissor) {
4467ec681f3Smrg      ctx->current_scissor = &ctx->scissor;
4477ec681f3Smrg   } else {
4487ec681f3Smrg      ctx->current_scissor = &ctx->disabled_scissor;
4497ec681f3Smrg   }
4507ec681f3Smrg
4517ec681f3Smrg   /* if scissor enable bit changed we need to mark scissor
4527ec681f3Smrg    * state as dirty as well:
4537ec681f3Smrg    * NOTE: we can do a shallow compare, since we only care
4547ec681f3Smrg    * if it changed to/from &ctx->disable_scissor
4557ec681f3Smrg    */
4567ec681f3Smrg   if (old_scissor != fd_context_get_scissor(ctx))
4577ec681f3Smrg      fd_context_dirty(ctx, FD_DIRTY_SCISSOR);
4587ec681f3Smrg
4597ec681f3Smrg   if (discard != get_safe(ctx->rasterizer, rasterizer_discard))
4607ec681f3Smrg      fd_context_dirty(ctx, FD_DIRTY_RASTERIZER_DISCARD);
4617ec681f3Smrg
4627ec681f3Smrg   if (clip_plane_enable != get_safe(ctx->rasterizer, clip_plane_enable))
4637ec681f3Smrg      fd_context_dirty(ctx, FD_DIRTY_RASTERIZER_CLIP_PLANE_ENABLE);
464af69d88dSmrg}
465af69d88dSmrg
466af69d88dSmrgstatic void
4677ec681f3Smrgfd_rasterizer_state_delete(struct pipe_context *pctx, void *hwcso) in_dt
468af69d88dSmrg{
4697ec681f3Smrg   FREE(hwcso);
470af69d88dSmrg}
471af69d88dSmrg
472af69d88dSmrgstatic void
4737ec681f3Smrgfd_zsa_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
474af69d88dSmrg{
4757ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
4767ec681f3Smrg   ctx->zsa = hwcso;
4777ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_ZSA);
4787ec681f3Smrg   update_draw_cost(ctx);
479af69d88dSmrg}
480af69d88dSmrg
481af69d88dSmrgstatic void
4827ec681f3Smrgfd_zsa_state_delete(struct pipe_context *pctx, void *hwcso) in_dt
483af69d88dSmrg{
4847ec681f3Smrg   FREE(hwcso);
485af69d88dSmrg}
486af69d88dSmrg
487af69d88dSmrgstatic void *
488af69d88dSmrgfd_vertex_state_create(struct pipe_context *pctx, unsigned num_elements,
4897ec681f3Smrg                       const struct pipe_vertex_element *elements)
490af69d88dSmrg{
4917ec681f3Smrg   struct fd_vertex_stateobj *so = CALLOC_STRUCT(fd_vertex_stateobj);
492af69d88dSmrg
4937ec681f3Smrg   if (!so)
4947ec681f3Smrg      return NULL;
495af69d88dSmrg
4967ec681f3Smrg   memcpy(so->pipe, elements, sizeof(*elements) * num_elements);
4977ec681f3Smrg   so->num_elements = num_elements;
498af69d88dSmrg
4997ec681f3Smrg   return so;
500af69d88dSmrg}
501af69d88dSmrg
502af69d88dSmrgstatic void
5037ec681f3Smrgfd_vertex_state_delete(struct pipe_context *pctx, void *hwcso) in_dt
504af69d88dSmrg{
5057ec681f3Smrg   FREE(hwcso);
506af69d88dSmrg}
507af69d88dSmrg
508af69d88dSmrgstatic void
5097ec681f3Smrgfd_vertex_state_bind(struct pipe_context *pctx, void *hwcso) in_dt
510af69d88dSmrg{
5117ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
5127ec681f3Smrg   ctx->vtx.vtx = hwcso;
5137ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_VTXSTATE);
514af69d88dSmrg}
515af69d88dSmrg
51601e04c3fSmrgstatic struct pipe_stream_output_target *
51701e04c3fSmrgfd_create_stream_output_target(struct pipe_context *pctx,
5187ec681f3Smrg                               struct pipe_resource *prsc,
5197ec681f3Smrg                               unsigned buffer_offset, unsigned buffer_size)
52001e04c3fSmrg{
5217ec681f3Smrg   struct fd_stream_output_target *target;
5227ec681f3Smrg   struct fd_resource *rsc = fd_resource(prsc);
5237ec681f3Smrg
5247ec681f3Smrg   target = CALLOC_STRUCT(fd_stream_output_target);
5257ec681f3Smrg   if (!target)
5267ec681f3Smrg      return NULL;
52701e04c3fSmrg
5287ec681f3Smrg   pipe_reference_init(&target->base.reference, 1);
5297ec681f3Smrg   pipe_resource_reference(&target->base.buffer, prsc);
53001e04c3fSmrg
5317ec681f3Smrg   target->base.context = pctx;
5327ec681f3Smrg   target->base.buffer_offset = buffer_offset;
5337ec681f3Smrg   target->base.buffer_size = buffer_size;
53401e04c3fSmrg
5357ec681f3Smrg   target->offset_buf = pipe_buffer_create(
5367ec681f3Smrg      pctx->screen, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, sizeof(uint32_t));
53701e04c3fSmrg
5387ec681f3Smrg   assert(rsc->b.b.target == PIPE_BUFFER);
5397ec681f3Smrg   util_range_add(&rsc->b.b, &rsc->valid_buffer_range, buffer_offset,
5407ec681f3Smrg                  buffer_offset + buffer_size);
54101e04c3fSmrg
5427ec681f3Smrg   return &target->base;
54301e04c3fSmrg}
54401e04c3fSmrg
54501e04c3fSmrgstatic void
54601e04c3fSmrgfd_stream_output_target_destroy(struct pipe_context *pctx,
5477ec681f3Smrg                                struct pipe_stream_output_target *target)
54801e04c3fSmrg{
5497ec681f3Smrg   struct fd_stream_output_target *cso = fd_stream_output_target(target);
5507ec681f3Smrg
5517ec681f3Smrg   pipe_resource_reference(&cso->base.buffer, NULL);
5527ec681f3Smrg   pipe_resource_reference(&cso->offset_buf, NULL);
5537ec681f3Smrg
5547ec681f3Smrg   FREE(target);
55501e04c3fSmrg}
55601e04c3fSmrg
55701e04c3fSmrgstatic void
5587ec681f3Smrgfd_set_stream_output_targets(struct pipe_context *pctx, unsigned num_targets,
5597ec681f3Smrg                             struct pipe_stream_output_target **targets,
5607ec681f3Smrg                             const unsigned *offsets) in_dt
56101e04c3fSmrg{
5627ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
5637ec681f3Smrg   struct fd_streamout_stateobj *so = &ctx->streamout;
5647ec681f3Smrg   unsigned i;
5657ec681f3Smrg
5667ec681f3Smrg   debug_assert(num_targets <= ARRAY_SIZE(so->targets));
56701e04c3fSmrg
5687ec681f3Smrg   /* Older targets need sw stats enabled for streamout emulation in VS: */
5697ec681f3Smrg   if (ctx->screen->gen < 5) {
5707ec681f3Smrg      if (num_targets && !so->num_targets) {
5717ec681f3Smrg         ctx->stats_users++;
5727ec681f3Smrg      } else if (so->num_targets && !num_targets) {
5737ec681f3Smrg         ctx->stats_users--;
5747ec681f3Smrg      }
5757ec681f3Smrg   }
57601e04c3fSmrg
5777ec681f3Smrg   for (i = 0; i < num_targets; i++) {
5787ec681f3Smrg      boolean changed = targets[i] != so->targets[i];
5797ec681f3Smrg      boolean reset = (offsets[i] != (unsigned)-1);
58001e04c3fSmrg
5817ec681f3Smrg      so->reset |= (reset << i);
58201e04c3fSmrg
5837ec681f3Smrg      if (!changed && !reset)
5847ec681f3Smrg         continue;
58501e04c3fSmrg
5867ec681f3Smrg      /* Note that all SO targets will be reset at once at a
5877ec681f3Smrg       * BeginTransformFeedback().
5887ec681f3Smrg       */
5897ec681f3Smrg      if (reset) {
5907ec681f3Smrg         so->offsets[i] = offsets[i];
5917ec681f3Smrg         ctx->streamout.verts_written = 0;
5927ec681f3Smrg      }
59301e04c3fSmrg
5947ec681f3Smrg      pipe_so_target_reference(&so->targets[i], targets[i]);
5957ec681f3Smrg   }
59601e04c3fSmrg
5977ec681f3Smrg   for (; i < so->num_targets; i++) {
5987ec681f3Smrg      pipe_so_target_reference(&so->targets[i], NULL);
5997ec681f3Smrg   }
60001e04c3fSmrg
6017ec681f3Smrg   so->num_targets = num_targets;
6027ec681f3Smrg
6037ec681f3Smrg   fd_context_dirty(ctx, FD_DIRTY_STREAMOUT);
60401e04c3fSmrg}
60501e04c3fSmrg
60601e04c3fSmrgstatic void
6077ec681f3Smrgfd_bind_compute_state(struct pipe_context *pctx, void *state) in_dt
60801e04c3fSmrg{
6097ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
6107ec681f3Smrg   ctx->compute = state;
6117ec681f3Smrg   /* NOTE: Don't mark FD_DIRTY_PROG for compute specific state */
6127ec681f3Smrg   ctx->dirty_shader[PIPE_SHADER_COMPUTE] |= FD_DIRTY_SHADER_PROG;
61301e04c3fSmrg}
61401e04c3fSmrg
61501e04c3fSmrgstatic void
6167ec681f3Smrgfd_set_compute_resources(struct pipe_context *pctx, unsigned start,
6177ec681f3Smrg                         unsigned count, struct pipe_surface **prscs) in_dt
61801e04c3fSmrg{
6197ec681f3Smrg   // TODO
62001e04c3fSmrg}
62101e04c3fSmrg
62201e04c3fSmrg/* used by clover to bind global objects, returning the bo address
62301e04c3fSmrg * via handles[n]
62401e04c3fSmrg */
62501e04c3fSmrgstatic void
6267ec681f3Smrgfd_set_global_binding(struct pipe_context *pctx, unsigned first, unsigned count,
6277ec681f3Smrg                      struct pipe_resource **prscs, uint32_t **handles) in_dt
62801e04c3fSmrg{
6297ec681f3Smrg   struct fd_context *ctx = fd_context(pctx);
6307ec681f3Smrg   struct fd_global_bindings_stateobj *so = &ctx->global_bindings;
6317ec681f3Smrg   unsigned mask = 0;
6327ec681f3Smrg
6337ec681f3Smrg   if (prscs) {
6347ec681f3Smrg      for (unsigned i = 0; i < count; i++) {
6357ec681f3Smrg         unsigned n = i + first;
6367ec681f3Smrg
6377ec681f3Smrg         mask |= BIT(n);
6387ec681f3Smrg
6397ec681f3Smrg         pipe_resource_reference(&so->buf[n], prscs[i]);
6407ec681f3Smrg
6417ec681f3Smrg         if (so->buf[n]) {
6427ec681f3Smrg            struct fd_resource *rsc = fd_resource(so->buf[n]);
6437ec681f3Smrg            uint64_t iova = fd_bo_get_iova(rsc->bo);
6447ec681f3Smrg            // TODO need to scream if iova > 32b or fix gallium API..
6457ec681f3Smrg            *handles[i] += iova;
6467ec681f3Smrg         }
6477ec681f3Smrg
6487ec681f3Smrg         if (prscs[i])
6497ec681f3Smrg            so->enabled_mask |= BIT(n);
6507ec681f3Smrg         else
6517ec681f3Smrg            so->enabled_mask &= ~BIT(n);
6527ec681f3Smrg      }
6537ec681f3Smrg   } else {
6547ec681f3Smrg      mask = (BIT(count) - 1) << first;
6557ec681f3Smrg
6567ec681f3Smrg      for (unsigned i = 0; i < count; i++) {
6577ec681f3Smrg         unsigned n = i + first;
6587ec681f3Smrg         pipe_resource_reference(&so->buf[n], NULL);
6597ec681f3Smrg      }
6607ec681f3Smrg
6617ec681f3Smrg      so->enabled_mask &= ~mask;
6627ec681f3Smrg   }
66301e04c3fSmrg}
66401e04c3fSmrg
665af69d88dSmrgvoid
666af69d88dSmrgfd_state_init(struct pipe_context *pctx)
667af69d88dSmrg{
6687ec681f3Smrg   pctx->set_blend_color = fd_set_blend_color;
6697ec681f3Smrg   pctx->set_stencil_ref = fd_set_stencil_ref;
6707ec681f3Smrg   pctx->set_clip_state = fd_set_clip_state;
6717ec681f3Smrg   pctx->set_sample_mask = fd_set_sample_mask;
6727ec681f3Smrg   pctx->set_min_samples = fd_set_min_samples;
6737ec681f3Smrg   pctx->set_constant_buffer = fd_set_constant_buffer;
6747ec681f3Smrg   pctx->set_shader_buffers = fd_set_shader_buffers;
6757ec681f3Smrg   pctx->set_shader_images = fd_set_shader_images;
6767ec681f3Smrg   pctx->set_framebuffer_state = fd_set_framebuffer_state;
6777ec681f3Smrg   pctx->set_polygon_stipple = fd_set_polygon_stipple;
6787ec681f3Smrg   pctx->set_scissor_states = fd_set_scissor_states;
6797ec681f3Smrg   pctx->set_viewport_states = fd_set_viewport_states;
6807ec681f3Smrg
6817ec681f3Smrg   pctx->set_vertex_buffers = fd_set_vertex_buffers;
6827ec681f3Smrg
6837ec681f3Smrg   pctx->bind_blend_state = fd_blend_state_bind;
6847ec681f3Smrg   pctx->delete_blend_state = fd_blend_state_delete;
6857ec681f3Smrg
6867ec681f3Smrg   pctx->bind_rasterizer_state = fd_rasterizer_state_bind;
6877ec681f3Smrg   pctx->delete_rasterizer_state = fd_rasterizer_state_delete;
6887ec681f3Smrg
6897ec681f3Smrg   pctx->bind_depth_stencil_alpha_state = fd_zsa_state_bind;
6907ec681f3Smrg   pctx->delete_depth_stencil_alpha_state = fd_zsa_state_delete;
6917ec681f3Smrg
6927ec681f3Smrg   if (!pctx->create_vertex_elements_state)
6937ec681f3Smrg      pctx->create_vertex_elements_state = fd_vertex_state_create;
6947ec681f3Smrg   pctx->delete_vertex_elements_state = fd_vertex_state_delete;
6957ec681f3Smrg   pctx->bind_vertex_elements_state = fd_vertex_state_bind;
6967ec681f3Smrg
6977ec681f3Smrg   pctx->create_stream_output_target = fd_create_stream_output_target;
6987ec681f3Smrg   pctx->stream_output_target_destroy = fd_stream_output_target_destroy;
6997ec681f3Smrg   pctx->set_stream_output_targets = fd_set_stream_output_targets;
7007ec681f3Smrg
7017ec681f3Smrg   if (has_compute(fd_screen(pctx->screen))) {
7027ec681f3Smrg      pctx->bind_compute_state = fd_bind_compute_state;
7037ec681f3Smrg      pctx->set_compute_resources = fd_set_compute_resources;
7047ec681f3Smrg      pctx->set_global_binding = fd_set_global_binding;
7057ec681f3Smrg   }
706af69d88dSmrg}
707