Path: blob/21.2-virgl/src/gallium/drivers/freedreno/freedreno_state.c
4570 views
/*1* Copyright (C) 2012 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include "pipe/p_state.h"27#include "util/u_dual_blend.h"28#include "util/u_helpers.h"29#include "util/u_memory.h"30#include "util/u_string.h"3132#include "freedreno_context.h"33#include "freedreno_gmem.h"34#include "freedreno_query_hw.h"35#include "freedreno_resource.h"36#include "freedreno_state.h"37#include "freedreno_texture.h"38#include "freedreno_util.h"3940/* All the generic state handling.. In case of CSO's that are specific41* to the GPU version, when the bind and the delete are common they can42* go in here.43*/4445static void46update_draw_cost(struct fd_context *ctx) assert_dt47{48struct pipe_framebuffer_state *pfb = &ctx->framebuffer;4950ctx->draw_cost = pfb->nr_cbufs;51for (unsigned i = 0; i < pfb->nr_cbufs; i++)52if (fd_blend_enabled(ctx, i))53ctx->draw_cost++;54if (fd_depth_enabled(ctx))55ctx->draw_cost++;56if (fd_depth_write_enabled(ctx))57ctx->draw_cost++;58}5960static void61fd_set_blend_color(struct pipe_context *pctx,62const struct pipe_blend_color *blend_color) in_dt63{64struct fd_context *ctx = fd_context(pctx);65ctx->blend_color = *blend_color;66fd_context_dirty(ctx, FD_DIRTY_BLEND_COLOR);67}6869static void70fd_set_stencil_ref(struct pipe_context *pctx,71const struct pipe_stencil_ref stencil_ref) in_dt72{73struct fd_context *ctx = fd_context(pctx);74ctx->stencil_ref = stencil_ref;75fd_context_dirty(ctx, FD_DIRTY_STENCIL_REF);76}7778static void79fd_set_clip_state(struct pipe_context *pctx,80const struct pipe_clip_state *clip) in_dt81{82struct fd_context *ctx = fd_context(pctx);83ctx->ucp = *clip;84fd_context_dirty(ctx, FD_DIRTY_UCP);85}8687static void88fd_set_sample_mask(struct pipe_context *pctx, unsigned sample_mask) in_dt89{90struct fd_context *ctx = fd_context(pctx);91ctx->sample_mask = (uint16_t)sample_mask;92fd_context_dirty(ctx, FD_DIRTY_SAMPLE_MASK);93}9495static void96fd_set_min_samples(struct pipe_context *pctx, unsigned min_samples) in_dt97{98struct fd_context *ctx = fd_context(pctx);99ctx->min_samples = min_samples;100fd_context_dirty(ctx, FD_DIRTY_MIN_SAMPLES);101}102103/* notes from calim on #dri-devel:104* index==0 will be non-UBO (ie. glUniformXYZ()) all packed together padded105* out to vec4's106* I should be able to consider that I own the user_ptr until the next107* set_constant_buffer() call, at which point I don't really care about the108* previous values.109* index>0 will be UBO's.. well, I'll worry about that later110*/111static void112fd_set_constant_buffer(struct pipe_context *pctx, enum pipe_shader_type shader,113uint index, bool take_ownership,114const struct pipe_constant_buffer *cb) in_dt115{116struct fd_context *ctx = fd_context(pctx);117struct fd_constbuf_stateobj *so = &ctx->constbuf[shader];118119util_copy_constant_buffer(&so->cb[index], cb, take_ownership);120121/* Note that gallium frontends can unbind constant buffers by122* passing NULL here.123*/124if (unlikely(!cb)) {125so->enabled_mask &= ~(1 << index);126return;127}128129so->enabled_mask |= 1 << index;130131fd_context_dirty_shader(ctx, shader, FD_DIRTY_SHADER_CONST);132fd_resource_set_usage(cb->buffer, FD_DIRTY_CONST);133134if (index > 0) {135assert(!cb->user_buffer);136ctx->dirty |= FD_DIRTY_RESOURCE;137}138}139140static void141fd_set_shader_buffers(struct pipe_context *pctx, enum pipe_shader_type shader,142unsigned start, unsigned count,143const struct pipe_shader_buffer *buffers,144unsigned writable_bitmask) in_dt145{146struct fd_context *ctx = fd_context(pctx);147struct fd_shaderbuf_stateobj *so = &ctx->shaderbuf[shader];148const unsigned modified_bits = u_bit_consecutive(start, count);149150so->enabled_mask &= ~modified_bits;151so->writable_mask &= ~modified_bits;152so->writable_mask |= writable_bitmask << start;153154for (unsigned i = 0; i < count; i++) {155unsigned n = i + start;156struct pipe_shader_buffer *buf = &so->sb[n];157158if (buffers && buffers[i].buffer) {159if ((buf->buffer == buffers[i].buffer) &&160(buf->buffer_offset == buffers[i].buffer_offset) &&161(buf->buffer_size == buffers[i].buffer_size))162continue;163164buf->buffer_offset = buffers[i].buffer_offset;165buf->buffer_size = buffers[i].buffer_size;166pipe_resource_reference(&buf->buffer, buffers[i].buffer);167168fd_resource_set_usage(buffers[i].buffer, FD_DIRTY_SSBO);169170so->enabled_mask |= BIT(n);171172if (writable_bitmask & BIT(i)) {173struct fd_resource *rsc = fd_resource(buf->buffer);174util_range_add(&rsc->b.b, &rsc->valid_buffer_range,175buf->buffer_offset,176buf->buffer_offset + buf->buffer_size);177}178} else {179pipe_resource_reference(&buf->buffer, NULL);180}181}182183fd_context_dirty_shader(ctx, shader, FD_DIRTY_SHADER_SSBO);184}185186void187fd_set_shader_images(struct pipe_context *pctx, enum pipe_shader_type shader,188unsigned start, unsigned count,189unsigned unbind_num_trailing_slots,190const struct pipe_image_view *images) in_dt191{192struct fd_context *ctx = fd_context(pctx);193struct fd_shaderimg_stateobj *so = &ctx->shaderimg[shader];194195unsigned mask = 0;196197if (images) {198for (unsigned i = 0; i < count; i++) {199unsigned n = i + start;200struct pipe_image_view *buf = &so->si[n];201202if ((buf->resource == images[i].resource) &&203(buf->format == images[i].format) &&204(buf->access == images[i].access) &&205!memcmp(&buf->u, &images[i].u, sizeof(buf->u)))206continue;207208mask |= BIT(n);209util_copy_image_view(buf, &images[i]);210211if (buf->resource) {212fd_resource_set_usage(buf->resource, FD_DIRTY_IMAGE);213so->enabled_mask |= BIT(n);214215if ((buf->access & PIPE_IMAGE_ACCESS_WRITE) &&216(buf->resource->target == PIPE_BUFFER)) {217218struct fd_resource *rsc = fd_resource(buf->resource);219util_range_add(&rsc->b.b, &rsc->valid_buffer_range,220buf->u.buf.offset,221buf->u.buf.offset + buf->u.buf.size);222}223} else {224so->enabled_mask &= ~BIT(n);225}226}227} else {228mask = (BIT(count) - 1) << start;229230for (unsigned i = 0; i < count; i++) {231unsigned n = i + start;232struct pipe_image_view *img = &so->si[n];233234pipe_resource_reference(&img->resource, NULL);235}236237so->enabled_mask &= ~mask;238}239240for (unsigned i = 0; i < unbind_num_trailing_slots; i++)241pipe_resource_reference(&so->si[i + start + count].resource, NULL);242243so->enabled_mask &=244~(BITFIELD_MASK(unbind_num_trailing_slots) << (start + count));245246fd_context_dirty_shader(ctx, shader, FD_DIRTY_SHADER_IMAGE);247}248249void250fd_set_framebuffer_state(struct pipe_context *pctx,251const struct pipe_framebuffer_state *framebuffer)252{253struct fd_context *ctx = fd_context(pctx);254struct pipe_framebuffer_state *cso;255256DBG("%ux%u, %u layers, %u samples", framebuffer->width, framebuffer->height,257framebuffer->layers, framebuffer->samples);258259cso = &ctx->framebuffer;260261if (util_framebuffer_state_equal(cso, framebuffer))262return;263264/* Do this *after* checking that the framebuffer state is actually265* changing. In the fd_blitter_clear() path, we get a pfb update266* to restore the current pfb state, which should not trigger us267* to flush (as that can cause the batch to be freed at a point268* before fd_clear() returns, but after the point where it expects269* flushes to potentially happen.270*/271fd_context_switch_from(ctx);272273util_copy_framebuffer_state(cso, framebuffer);274275cso->samples = util_framebuffer_get_num_samples(cso);276277if (ctx->screen->reorder) {278struct fd_batch *old_batch = NULL;279280fd_batch_reference(&old_batch, ctx->batch);281282if (likely(old_batch))283fd_batch_finish_queries(old_batch);284285fd_batch_reference(&ctx->batch, NULL);286fd_context_all_dirty(ctx);287ctx->update_active_queries = true;288289fd_batch_reference(&old_batch, NULL);290} else if (ctx->batch) {291DBG("%d: cbufs[0]=%p, zsbuf=%p", ctx->batch->needs_flush,292framebuffer->cbufs[0], framebuffer->zsbuf);293fd_batch_flush(ctx->batch);294}295296fd_context_dirty(ctx, FD_DIRTY_FRAMEBUFFER);297298ctx->disabled_scissor.minx = 0;299ctx->disabled_scissor.miny = 0;300ctx->disabled_scissor.maxx = cso->width;301ctx->disabled_scissor.maxy = cso->height;302303fd_context_dirty(ctx, FD_DIRTY_SCISSOR);304update_draw_cost(ctx);305}306307static void308fd_set_polygon_stipple(struct pipe_context *pctx,309const struct pipe_poly_stipple *stipple) in_dt310{311struct fd_context *ctx = fd_context(pctx);312ctx->stipple = *stipple;313fd_context_dirty(ctx, FD_DIRTY_STIPPLE);314}315316static void317fd_set_scissor_states(struct pipe_context *pctx, unsigned start_slot,318unsigned num_scissors,319const struct pipe_scissor_state *scissor) in_dt320{321struct fd_context *ctx = fd_context(pctx);322323ctx->scissor = *scissor;324fd_context_dirty(ctx, FD_DIRTY_SCISSOR);325}326327static void328fd_set_viewport_states(struct pipe_context *pctx, unsigned start_slot,329unsigned num_viewports,330const struct pipe_viewport_state *viewport) in_dt331{332struct fd_context *ctx = fd_context(pctx);333struct pipe_scissor_state *scissor = &ctx->viewport_scissor;334float minx, miny, maxx, maxy;335336ctx->viewport = *viewport;337338/* see si_get_scissor_from_viewport(): */339340/* Convert (-1, -1) and (1, 1) from clip space into window space. */341minx = -viewport->scale[0] + viewport->translate[0];342miny = -viewport->scale[1] + viewport->translate[1];343maxx = viewport->scale[0] + viewport->translate[0];344maxy = viewport->scale[1] + viewport->translate[1];345346/* Handle inverted viewports. */347if (minx > maxx) {348swap(minx, maxx);349}350if (miny > maxy) {351swap(miny, maxy);352}353354const float max_dims = ctx->screen->gpu_id >= 400 ? 16384.f : 4096.f;355356/* Clamp, convert to integer and round up the max bounds. */357scissor->minx = CLAMP(minx, 0.f, max_dims);358scissor->miny = CLAMP(miny, 0.f, max_dims);359scissor->maxx = CLAMP(ceilf(maxx), 0.f, max_dims);360scissor->maxy = CLAMP(ceilf(maxy), 0.f, max_dims);361362fd_context_dirty(ctx, FD_DIRTY_VIEWPORT);363}364365static void366fd_set_vertex_buffers(struct pipe_context *pctx, unsigned start_slot,367unsigned count, unsigned unbind_num_trailing_slots,368bool take_ownership,369const struct pipe_vertex_buffer *vb) in_dt370{371struct fd_context *ctx = fd_context(pctx);372struct fd_vertexbuf_stateobj *so = &ctx->vtx.vertexbuf;373int i;374375/* on a2xx, pitch is encoded in the vtx fetch instruction, so376* we need to mark VTXSTATE as dirty as well to trigger patching377* and re-emitting the vtx shader:378*/379if (ctx->screen->gpu_id < 300) {380for (i = 0; i < count; i++) {381bool new_enabled = vb && vb[i].buffer.resource;382bool old_enabled = so->vb[i].buffer.resource != NULL;383uint32_t new_stride = vb ? vb[i].stride : 0;384uint32_t old_stride = so->vb[i].stride;385if ((new_enabled != old_enabled) || (new_stride != old_stride)) {386fd_context_dirty(ctx, FD_DIRTY_VTXSTATE);387break;388}389}390}391392util_set_vertex_buffers_mask(so->vb, &so->enabled_mask, vb, start_slot,393count, unbind_num_trailing_slots,394take_ownership);395so->count = util_last_bit(so->enabled_mask);396397if (!vb)398return;399400fd_context_dirty(ctx, FD_DIRTY_VTXBUF);401402for (unsigned i = 0; i < count; i++) {403assert(!vb[i].is_user_buffer);404fd_resource_set_usage(vb[i].buffer.resource, FD_DIRTY_VTXBUF);405}406}407408static void409fd_blend_state_bind(struct pipe_context *pctx, void *hwcso) in_dt410{411struct fd_context *ctx = fd_context(pctx);412struct pipe_blend_state *cso = hwcso;413bool old_is_dual = ctx->blend ? ctx->blend->rt[0].blend_enable &&414util_blend_state_is_dual(ctx->blend, 0)415: false;416bool new_is_dual =417cso ? cso->rt[0].blend_enable && util_blend_state_is_dual(cso, 0) : false;418ctx->blend = hwcso;419fd_context_dirty(ctx, FD_DIRTY_BLEND);420if (old_is_dual != new_is_dual)421fd_context_dirty(ctx, FD_DIRTY_BLEND_DUAL);422update_draw_cost(ctx);423}424425static void426fd_blend_state_delete(struct pipe_context *pctx, void *hwcso) in_dt427{428FREE(hwcso);429}430431static void432fd_rasterizer_state_bind(struct pipe_context *pctx, void *hwcso) in_dt433{434struct fd_context *ctx = fd_context(pctx);435struct pipe_scissor_state *old_scissor = fd_context_get_scissor(ctx);436bool discard = ctx->rasterizer && ctx->rasterizer->rasterizer_discard;437438ctx->rasterizer = hwcso;439fd_context_dirty(ctx, FD_DIRTY_RASTERIZER);440441if (ctx->rasterizer && ctx->rasterizer->scissor) {442ctx->current_scissor = &ctx->scissor;443} else {444ctx->current_scissor = &ctx->disabled_scissor;445}446447/* if scissor enable bit changed we need to mark scissor448* state as dirty as well:449* NOTE: we can do a shallow compare, since we only care450* if it changed to/from &ctx->disable_scissor451*/452if (old_scissor != fd_context_get_scissor(ctx))453fd_context_dirty(ctx, FD_DIRTY_SCISSOR);454455if (ctx->rasterizer && (discard != ctx->rasterizer->rasterizer_discard))456fd_context_dirty(ctx, FD_DIRTY_RASTERIZER_DISCARD);457}458459static void460fd_rasterizer_state_delete(struct pipe_context *pctx, void *hwcso) in_dt461{462FREE(hwcso);463}464465static void466fd_zsa_state_bind(struct pipe_context *pctx, void *hwcso) in_dt467{468struct fd_context *ctx = fd_context(pctx);469ctx->zsa = hwcso;470fd_context_dirty(ctx, FD_DIRTY_ZSA);471update_draw_cost(ctx);472}473474static void475fd_zsa_state_delete(struct pipe_context *pctx, void *hwcso) in_dt476{477FREE(hwcso);478}479480static void *481fd_vertex_state_create(struct pipe_context *pctx, unsigned num_elements,482const struct pipe_vertex_element *elements)483{484struct fd_vertex_stateobj *so = CALLOC_STRUCT(fd_vertex_stateobj);485486if (!so)487return NULL;488489memcpy(so->pipe, elements, sizeof(*elements) * num_elements);490so->num_elements = num_elements;491492return so;493}494495static void496fd_vertex_state_delete(struct pipe_context *pctx, void *hwcso) in_dt497{498FREE(hwcso);499}500501static void502fd_vertex_state_bind(struct pipe_context *pctx, void *hwcso) in_dt503{504struct fd_context *ctx = fd_context(pctx);505ctx->vtx.vtx = hwcso;506fd_context_dirty(ctx, FD_DIRTY_VTXSTATE);507}508509static struct pipe_stream_output_target *510fd_create_stream_output_target(struct pipe_context *pctx,511struct pipe_resource *prsc,512unsigned buffer_offset, unsigned buffer_size)513{514struct fd_stream_output_target *target;515struct fd_resource *rsc = fd_resource(prsc);516517target = CALLOC_STRUCT(fd_stream_output_target);518if (!target)519return NULL;520521pipe_reference_init(&target->base.reference, 1);522pipe_resource_reference(&target->base.buffer, prsc);523524target->base.context = pctx;525target->base.buffer_offset = buffer_offset;526target->base.buffer_size = buffer_size;527528target->offset_buf = pipe_buffer_create(529pctx->screen, PIPE_BIND_CUSTOM, PIPE_USAGE_IMMUTABLE, sizeof(uint32_t));530531assert(rsc->b.b.target == PIPE_BUFFER);532util_range_add(&rsc->b.b, &rsc->valid_buffer_range, buffer_offset,533buffer_offset + buffer_size);534535return &target->base;536}537538static void539fd_stream_output_target_destroy(struct pipe_context *pctx,540struct pipe_stream_output_target *target)541{542struct fd_stream_output_target *cso = fd_stream_output_target(target);543544pipe_resource_reference(&cso->base.buffer, NULL);545pipe_resource_reference(&cso->offset_buf, NULL);546547FREE(target);548}549550static void551fd_set_stream_output_targets(struct pipe_context *pctx, unsigned num_targets,552struct pipe_stream_output_target **targets,553const unsigned *offsets) in_dt554{555struct fd_context *ctx = fd_context(pctx);556struct fd_streamout_stateobj *so = &ctx->streamout;557unsigned i;558559debug_assert(num_targets <= ARRAY_SIZE(so->targets));560561/* Older targets need sw stats enabled for streamout emulation in VS: */562if (ctx->screen->gpu_id < 500) {563if (num_targets && !so->num_targets) {564ctx->stats_users++;565} else if (so->num_targets && !num_targets) {566ctx->stats_users--;567}568}569570for (i = 0; i < num_targets; i++) {571boolean changed = targets[i] != so->targets[i];572boolean reset = (offsets[i] != (unsigned)-1);573574so->reset |= (reset << i);575576if (!changed && !reset)577continue;578579/* Note that all SO targets will be reset at once at a580* BeginTransformFeedback().581*/582if (reset) {583so->offsets[i] = offsets[i];584ctx->streamout.verts_written = 0;585}586587pipe_so_target_reference(&so->targets[i], targets[i]);588}589590for (; i < so->num_targets; i++) {591pipe_so_target_reference(&so->targets[i], NULL);592}593594so->num_targets = num_targets;595596fd_context_dirty(ctx, FD_DIRTY_STREAMOUT);597}598599static void600fd_bind_compute_state(struct pipe_context *pctx, void *state) in_dt601{602struct fd_context *ctx = fd_context(pctx);603ctx->compute = state;604/* NOTE: Don't mark FD_DIRTY_PROG for compute specific state */605ctx->dirty_shader[PIPE_SHADER_COMPUTE] |= FD_DIRTY_SHADER_PROG;606}607608static void609fd_set_compute_resources(struct pipe_context *pctx, unsigned start,610unsigned count, struct pipe_surface **prscs) in_dt611{612// TODO613}614615/* used by clover to bind global objects, returning the bo address616* via handles[n]617*/618static void619fd_set_global_binding(struct pipe_context *pctx, unsigned first, unsigned count,620struct pipe_resource **prscs, uint32_t **handles) in_dt621{622struct fd_context *ctx = fd_context(pctx);623struct fd_global_bindings_stateobj *so = &ctx->global_bindings;624unsigned mask = 0;625626if (prscs) {627for (unsigned i = 0; i < count; i++) {628unsigned n = i + first;629630mask |= BIT(n);631632pipe_resource_reference(&so->buf[n], prscs[i]);633634if (so->buf[n]) {635struct fd_resource *rsc = fd_resource(so->buf[n]);636uint64_t iova = fd_bo_get_iova(rsc->bo);637// TODO need to scream if iova > 32b or fix gallium API..638*handles[i] += iova;639}640641if (prscs[i])642so->enabled_mask |= BIT(n);643else644so->enabled_mask &= ~BIT(n);645}646} else {647mask = (BIT(count) - 1) << first;648649for (unsigned i = 0; i < count; i++) {650unsigned n = i + first;651pipe_resource_reference(&so->buf[n], NULL);652}653654so->enabled_mask &= ~mask;655}656}657658void659fd_state_init(struct pipe_context *pctx)660{661pctx->set_blend_color = fd_set_blend_color;662pctx->set_stencil_ref = fd_set_stencil_ref;663pctx->set_clip_state = fd_set_clip_state;664pctx->set_sample_mask = fd_set_sample_mask;665pctx->set_min_samples = fd_set_min_samples;666pctx->set_constant_buffer = fd_set_constant_buffer;667pctx->set_shader_buffers = fd_set_shader_buffers;668pctx->set_shader_images = fd_set_shader_images;669pctx->set_framebuffer_state = fd_set_framebuffer_state;670pctx->set_polygon_stipple = fd_set_polygon_stipple;671pctx->set_scissor_states = fd_set_scissor_states;672pctx->set_viewport_states = fd_set_viewport_states;673674pctx->set_vertex_buffers = fd_set_vertex_buffers;675676pctx->bind_blend_state = fd_blend_state_bind;677pctx->delete_blend_state = fd_blend_state_delete;678679pctx->bind_rasterizer_state = fd_rasterizer_state_bind;680pctx->delete_rasterizer_state = fd_rasterizer_state_delete;681682pctx->bind_depth_stencil_alpha_state = fd_zsa_state_bind;683pctx->delete_depth_stencil_alpha_state = fd_zsa_state_delete;684685if (!pctx->create_vertex_elements_state)686pctx->create_vertex_elements_state = fd_vertex_state_create;687pctx->delete_vertex_elements_state = fd_vertex_state_delete;688pctx->bind_vertex_elements_state = fd_vertex_state_bind;689690pctx->create_stream_output_target = fd_create_stream_output_target;691pctx->stream_output_target_destroy = fd_stream_output_target_destroy;692pctx->set_stream_output_targets = fd_set_stream_output_targets;693694if (has_compute(fd_screen(pctx->screen))) {695pctx->bind_compute_state = fd_bind_compute_state;696pctx->set_compute_resources = fd_set_compute_resources;697pctx->set_global_binding = fd_set_global_binding;698}699}700701702