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