19f464c52Smaya/*
27ec681f3Smrg * Copyright (C) 2019-2020 Collabora, Ltd.
39f464c52Smaya * © Copyright 2018 Alyssa Rosenzweig
47ec681f3Smrg * Copyright © 2014-2017 Broadcom
57ec681f3Smrg * Copyright (C) 2017 Intel Corporation
69f464c52Smaya *
79f464c52Smaya * Permission is hereby granted, free of charge, to any person obtaining a
89f464c52Smaya * copy of this software and associated documentation files (the "Software"),
99f464c52Smaya * to deal in the Software without restriction, including without limitation
109f464c52Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense,
119f464c52Smaya * and/or sell copies of the Software, and to permit persons to whom the
129f464c52Smaya * Software is furnished to do so, subject to the following conditions:
139f464c52Smaya *
149f464c52Smaya * The above copyright notice and this permission notice (including the next
159f464c52Smaya * paragraph) shall be included in all copies or substantial portions of the
169f464c52Smaya * Software.
179f464c52Smaya *
189f464c52Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
199f464c52Smaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
209f464c52Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
219f464c52Smaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
229f464c52Smaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
239f464c52Smaya * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
249f464c52Smaya * SOFTWARE.
259f464c52Smaya *
269f464c52Smaya */
279f464c52Smaya
289f464c52Smaya#include <sys/poll.h>
299f464c52Smaya#include <errno.h>
309f464c52Smaya
317ec681f3Smrg#include "pan_bo.h"
329f464c52Smaya#include "pan_context.h"
337ec681f3Smrg#include "pan_minmax_cache.h"
347ec681f3Smrg#include "panfrost-quirks.h"
359f464c52Smaya
369f464c52Smaya#include "util/macros.h"
377ec681f3Smrg#include "util/format/u_format.h"
389f464c52Smaya#include "util/u_inlines.h"
399f464c52Smaya#include "util/u_upload_mgr.h"
409f464c52Smaya#include "util/u_memory.h"
419f464c52Smaya#include "util/u_vbuf.h"
429f464c52Smaya#include "util/half_float.h"
439f464c52Smaya#include "util/u_helpers.h"
447ec681f3Smrg#include "util/format/u_format.h"
457ec681f3Smrg#include "util/u_prim.h"
467ec681f3Smrg#include "util/u_prim_restart.h"
479f464c52Smaya#include "tgsi/tgsi_parse.h"
487ec681f3Smrg#include "tgsi/tgsi_from_mesa.h"
499f464c52Smaya#include "util/u_math.h"
509f464c52Smaya
519f464c52Smaya#include "pan_screen.h"
529f464c52Smaya#include "pan_util.h"
537ec681f3Smrg#include "decode.h"
547ec681f3Smrg#include "util/pan_lower_framebuffer.h"
559f464c52Smaya
569f464c52Smayastatic void
577ec681f3Smrgpanfrost_clear(
587ec681f3Smrg        struct pipe_context *pipe,
597ec681f3Smrg        unsigned buffers,
607ec681f3Smrg        const struct pipe_scissor_state *scissor_state,
617ec681f3Smrg        const union pipe_color_union *color,
627ec681f3Smrg        double depth, unsigned stencil)
639f464c52Smaya{
647ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
659f464c52Smaya
667ec681f3Smrg        if (!panfrost_render_condition_check(ctx))
677ec681f3Smrg                return;
689f464c52Smaya
697ec681f3Smrg        /* TODO: panfrost_get_fresh_batch_for_fbo() instantiates a new batch if
707ec681f3Smrg         * the existing batch targeting this FBO has draws. We could probably
717ec681f3Smrg         * avoid that by replacing plain clears by quad-draws with a specific
727ec681f3Smrg         * color/depth/stencil value, thus avoiding the generation of extra
737ec681f3Smrg         * fragment jobs.
747ec681f3Smrg         */
757ec681f3Smrg        struct panfrost_batch *batch = panfrost_get_fresh_batch_for_fbo(ctx, "Clear");
767ec681f3Smrg        panfrost_batch_clear(batch, buffers, color, depth, stencil);
779f464c52Smaya}
789f464c52Smaya
797ec681f3Smrgbool
807ec681f3Smrgpanfrost_writes_point_size(struct panfrost_context *ctx)
819f464c52Smaya{
827ec681f3Smrg        assert(ctx->shader[PIPE_SHADER_VERTEX]);
837ec681f3Smrg        struct panfrost_shader_state *vs = panfrost_get_shader_state(ctx, PIPE_SHADER_VERTEX);
849f464c52Smaya
857ec681f3Smrg        return vs->info.vs.writes_point_size && ctx->active_prim == PIPE_PRIM_POINTS;
869f464c52Smaya}
879f464c52Smaya
889f464c52Smaya/* The entire frame is in memory -- send it off to the kernel! */
899f464c52Smaya
909f464c52Smayavoid
919f464c52Smayapanfrost_flush(
929f464c52Smaya        struct pipe_context *pipe,
939f464c52Smaya        struct pipe_fence_handle **fence,
949f464c52Smaya        unsigned flags)
959f464c52Smaya{
969f464c52Smaya        struct panfrost_context *ctx = pan_context(pipe);
977ec681f3Smrg        struct panfrost_device *dev = pan_device(pipe->screen);
989f464c52Smaya
999f464c52Smaya
1007ec681f3Smrg        /* Submit all pending jobs */
1017ec681f3Smrg        panfrost_flush_all_batches(ctx, NULL);
1029f464c52Smaya
1037ec681f3Smrg        if (fence) {
1047ec681f3Smrg                struct pipe_fence_handle *f = panfrost_fence_create(ctx);
1057ec681f3Smrg                pipe->screen->fence_reference(pipe->screen, fence, NULL);
1067ec681f3Smrg                *fence = f;
1079f464c52Smaya        }
1089f464c52Smaya
1097ec681f3Smrg        if (dev->debug & PAN_DBG_TRACE)
1107ec681f3Smrg                pandecode_next_frame();
1119f464c52Smaya}
1129f464c52Smaya
1137ec681f3Smrgstatic void
1147ec681f3Smrgpanfrost_texture_barrier(struct pipe_context *pipe, unsigned flags)
1159f464c52Smaya{
1167ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
1177ec681f3Smrg        panfrost_flush_all_batches(ctx, "Texture barrier");
1189f464c52Smaya}
1199f464c52Smaya
1209f464c52Smayastatic void
1217ec681f3Smrgpanfrost_set_frontend_noop(struct pipe_context *pipe, bool enable)
1229f464c52Smaya{
1239f464c52Smaya        struct panfrost_context *ctx = pan_context(pipe);
1247ec681f3Smrg        panfrost_flush_all_batches(ctx, "Frontend no-op change");
1257ec681f3Smrg        ctx->is_noop = enable;
1269f464c52Smaya}
1279f464c52Smaya
1289f464c52Smaya
1299f464c52Smayastatic void
1309f464c52Smayapanfrost_generic_cso_delete(struct pipe_context *pctx, void *hwcso)
1319f464c52Smaya{
1329f464c52Smaya        free(hwcso);
1339f464c52Smaya}
1349f464c52Smaya
1359f464c52Smayastatic void
1367ec681f3Smrgpanfrost_bind_blend_state(struct pipe_context *pipe, void *cso)
1379f464c52Smaya{
1387ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
1397ec681f3Smrg        ctx->blend = cso;
1407ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
1419f464c52Smaya}
1429f464c52Smaya
1439f464c52Smayastatic void
1447ec681f3Smrgpanfrost_set_blend_color(struct pipe_context *pipe,
1457ec681f3Smrg                         const struct pipe_blend_color *blend_color)
1469f464c52Smaya{
1477ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
1487ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
1499f464c52Smaya
1507ec681f3Smrg        if (blend_color)
1517ec681f3Smrg                ctx->blend_color = *blend_color;
1529f464c52Smaya}
1539f464c52Smaya
1547ec681f3Smrg/* Create a final blend given the context */
1559f464c52Smaya
1567ec681f3Smrgmali_ptr
1577ec681f3Smrgpanfrost_get_blend(struct panfrost_batch *batch, unsigned rti, struct panfrost_bo **bo, unsigned *shader_offset)
1589f464c52Smaya{
1597ec681f3Smrg        struct panfrost_context *ctx = batch->ctx;
1607ec681f3Smrg        struct panfrost_device *dev = pan_device(ctx->base.screen);
1617ec681f3Smrg        struct panfrost_blend_state *blend = ctx->blend;
1627ec681f3Smrg        struct pan_blend_info info = blend->info[rti];
1637ec681f3Smrg        struct pipe_surface *surf = batch->key.cbufs[rti];
1647ec681f3Smrg        enum pipe_format fmt = surf->format;
1659f464c52Smaya
1667ec681f3Smrg        /* Use fixed-function if the equation permits, the format is blendable,
1677ec681f3Smrg         * and no more than one unique constant is accessed */
1687ec681f3Smrg        if (info.fixed_function && panfrost_blendable_formats_v7[fmt].internal &&
1697ec681f3Smrg                        pan_blend_is_homogenous_constant(info.constant_mask,
1707ec681f3Smrg                                ctx->blend_color.color)) {
1717ec681f3Smrg                return 0;
1729f464c52Smaya        }
1739f464c52Smaya
1747ec681f3Smrg        /* Otherwise, we need to grab a shader */
1757ec681f3Smrg        struct pan_blend_state pan_blend = blend->pan;
1767ec681f3Smrg        unsigned nr_samples = surf->nr_samples ? : surf->texture->nr_samples;
1779f464c52Smaya
1787ec681f3Smrg        pan_blend.rts[rti].format = fmt;
1797ec681f3Smrg        pan_blend.rts[rti].nr_samples = nr_samples;
1807ec681f3Smrg        memcpy(pan_blend.constants, ctx->blend_color.color,
1817ec681f3Smrg               sizeof(pan_blend.constants));
1829f464c52Smaya
1837ec681f3Smrg        /* Upload the shader, sharing a BO */
1847ec681f3Smrg        if (!(*bo)) {
1857ec681f3Smrg                *bo = panfrost_batch_create_bo(batch, 4096, PAN_BO_EXECUTE,
1867ec681f3Smrg                                PIPE_SHADER_FRAGMENT, "Blend shader");
1879f464c52Smaya        }
1889f464c52Smaya
1897ec681f3Smrg        struct panfrost_shader_state *ss = panfrost_get_shader_state(ctx, PIPE_SHADER_FRAGMENT);
1909f464c52Smaya
1917ec681f3Smrg        /* Default for Midgard */
1927ec681f3Smrg        nir_alu_type col0_type = nir_type_float32;
1937ec681f3Smrg        nir_alu_type col1_type = nir_type_float32;
1949f464c52Smaya
1957ec681f3Smrg        /* Bifrost has per-output types, respect them */
1967ec681f3Smrg        if (pan_is_bifrost(dev)) {
1977ec681f3Smrg                col0_type = ss->info.bifrost.blend[rti].type;
1987ec681f3Smrg                col1_type = ss->info.bifrost.blend_src1_type;
1999f464c52Smaya        }
2009f464c52Smaya
2017ec681f3Smrg        pthread_mutex_lock(&dev->blend_shaders.lock);
2027ec681f3Smrg        struct pan_blend_shader_variant *shader =
2037ec681f3Smrg                pan_screen(ctx->base.screen)->vtbl.get_blend_shader(dev,
2047ec681f3Smrg                                                                    &pan_blend,
2057ec681f3Smrg                                                                    col0_type,
2067ec681f3Smrg                                                                    col1_type,
2077ec681f3Smrg                                                                    rti);
2089f464c52Smaya
2097ec681f3Smrg        /* Size check and upload */
2107ec681f3Smrg        unsigned offset = *shader_offset;
2117ec681f3Smrg        assert((offset + shader->binary.size) < 4096);
2127ec681f3Smrg        memcpy((*bo)->ptr.cpu + offset, shader->binary.data, shader->binary.size);
2137ec681f3Smrg        *shader_offset += shader->binary.size;
2147ec681f3Smrg        pthread_mutex_unlock(&dev->blend_shaders.lock);
2159f464c52Smaya
2167ec681f3Smrg        return ((*bo)->ptr.gpu + offset) | shader->first_tag;
2179f464c52Smaya}
2189f464c52Smaya
2199f464c52Smayastatic void
2207ec681f3Smrgpanfrost_bind_rasterizer_state(
2219f464c52Smaya        struct pipe_context *pctx,
2227ec681f3Smrg        void *hwcso)
2239f464c52Smaya{
2249f464c52Smaya        struct panfrost_context *ctx = pan_context(pctx);
2257ec681f3Smrg        ctx->rasterizer = hwcso;
2269f464c52Smaya
2277ec681f3Smrg        /* We can assume the renderer state descriptor is always dirty, the
2287ec681f3Smrg         * dependencies are too intricate to bother tracking in detail. However
2297ec681f3Smrg         * we could probably diff the renderers for viewport dirty tracking,
2307ec681f3Smrg         * that just cares about the scissor enable and the depth clips. */
2317ec681f3Smrg        ctx->dirty |= PAN_DIRTY_SCISSOR;
2327ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
2339f464c52Smaya}
2349f464c52Smaya
2359f464c52Smayastatic void
2367ec681f3Smrgpanfrost_set_shader_images(
2379f464c52Smaya        struct pipe_context *pctx,
2387ec681f3Smrg        enum pipe_shader_type shader,
2397ec681f3Smrg        unsigned start_slot, unsigned count, unsigned unbind_num_trailing_slots,
2407ec681f3Smrg        const struct pipe_image_view *iviews)
2419f464c52Smaya{
2429f464c52Smaya        struct panfrost_context *ctx = pan_context(pctx);
2437ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_IMAGE;
2449f464c52Smaya
2457ec681f3Smrg        /* Unbind start_slot...start_slot+count */
2467ec681f3Smrg        if (!iviews) {
2477ec681f3Smrg                for (int i = start_slot; i < start_slot + count + unbind_num_trailing_slots; i++) {
2487ec681f3Smrg                        pipe_resource_reference(&ctx->images[shader][i].resource, NULL);
2497ec681f3Smrg                }
2509f464c52Smaya
2517ec681f3Smrg                ctx->image_mask[shader] &= ~(((1ull << count) - 1) << start_slot);
2527ec681f3Smrg                return;
2539f464c52Smaya        }
2549f464c52Smaya
2557ec681f3Smrg        /* Bind start_slot...start_slot+count */
2567ec681f3Smrg        for (int i = 0; i < count; i++) {
2577ec681f3Smrg                const struct pipe_image_view *image = &iviews[i];
2587ec681f3Smrg                SET_BIT(ctx->image_mask[shader], 1 << (start_slot + i), image->resource);
2599f464c52Smaya
2607ec681f3Smrg                if (!image->resource) {
2617ec681f3Smrg                        util_copy_image_view(&ctx->images[shader][start_slot+i], NULL);
2627ec681f3Smrg                        continue;
2637ec681f3Smrg                }
2649f464c52Smaya
2657ec681f3Smrg                struct panfrost_resource *rsrc = pan_resource(image->resource);
2669f464c52Smaya
2677ec681f3Smrg                /* Images don't work with AFBC, since they require pixel-level granularity */
2687ec681f3Smrg                if (drm_is_afbc(rsrc->image.layout.modifier)) {
2697ec681f3Smrg                        pan_resource_modifier_convert(ctx, rsrc,
2707ec681f3Smrg                                        DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
2717ec681f3Smrg                                        "Shader image");
2727ec681f3Smrg                }
2739f464c52Smaya
2747ec681f3Smrg                util_copy_image_view(&ctx->images[shader][start_slot+i], image);
2759f464c52Smaya        }
2769f464c52Smaya
2777ec681f3Smrg        /* Unbind start_slot+count...start_slot+count+unbind_num_trailing_slots */
2787ec681f3Smrg        for (int i = 0; i < unbind_num_trailing_slots; i++) {
2797ec681f3Smrg                SET_BIT(ctx->image_mask[shader], 1 << (start_slot + count + i), NULL);
2807ec681f3Smrg                util_copy_image_view(&ctx->images[shader][start_slot+count+i], NULL);
2817ec681f3Smrg        }
2829f464c52Smaya}
2839f464c52Smaya
2849f464c52Smayastatic void
2857ec681f3Smrgpanfrost_bind_vertex_elements_state(
2869f464c52Smaya        struct pipe_context *pctx,
2877ec681f3Smrg        void *hwcso)
2889f464c52Smaya{
2899f464c52Smaya        struct panfrost_context *ctx = pan_context(pctx);
2907ec681f3Smrg        ctx->vertex = hwcso;
2919f464c52Smaya}
2929f464c52Smaya
2937ec681f3Smrgstatic void *
2947ec681f3Smrgpanfrost_create_shader_state(
2959f464c52Smaya        struct pipe_context *pctx,
2967ec681f3Smrg        const struct pipe_shader_state *cso,
2977ec681f3Smrg        enum pipe_shader_type stage)
2989f464c52Smaya{
2997ec681f3Smrg        struct panfrost_shader_variants *so = CALLOC_STRUCT(panfrost_shader_variants);
3007ec681f3Smrg        struct panfrost_device *dev = pan_device(pctx->screen);
3017ec681f3Smrg        so->base = *cso;
3029f464c52Smaya
3037ec681f3Smrg        simple_mtx_init(&so->lock, mtx_plain);
3049f464c52Smaya
3057ec681f3Smrg        /* Token deep copy to prevent memory corruption */
3069f464c52Smaya
3077ec681f3Smrg        if (cso->type == PIPE_SHADER_IR_TGSI)
3087ec681f3Smrg                so->base.tokens = tgsi_dup_tokens(so->base.tokens);
3099f464c52Smaya
3107ec681f3Smrg        /* Precompile for shader-db if we need to */
3117ec681f3Smrg        if (unlikely((dev->debug & PAN_DBG_PRECOMPILE) && cso->type == PIPE_SHADER_IR_NIR)) {
3127ec681f3Smrg                struct panfrost_context *ctx = pan_context(pctx);
3139f464c52Smaya
3147ec681f3Smrg                struct panfrost_shader_state state = { 0 };
3159f464c52Smaya
3167ec681f3Smrg                panfrost_shader_compile(pctx->screen,
3177ec681f3Smrg                                        &ctx->shaders, &ctx->descs,
3187ec681f3Smrg                                        PIPE_SHADER_IR_NIR,
3197ec681f3Smrg                                        so->base.ir.nir,
3207ec681f3Smrg                                        tgsi_processor_to_shader_stage(stage),
3217ec681f3Smrg                                        &state);
3227ec681f3Smrg        }
3239f464c52Smaya
3247ec681f3Smrg        return so;
3257ec681f3Smrg}
3269f464c52Smaya
3277ec681f3Smrgstatic void
3287ec681f3Smrgpanfrost_delete_shader_state(
3297ec681f3Smrg        struct pipe_context *pctx,
3307ec681f3Smrg        void *so)
3317ec681f3Smrg{
3327ec681f3Smrg        struct panfrost_shader_variants *cso = (struct panfrost_shader_variants *) so;
3339f464c52Smaya
3347ec681f3Smrg        if (!cso->is_compute && cso->base.type == PIPE_SHADER_IR_NIR)
3357ec681f3Smrg                ralloc_free(cso->base.ir.nir);
3369f464c52Smaya
3377ec681f3Smrg        if (cso->base.type == PIPE_SHADER_IR_TGSI)
3387ec681f3Smrg                tgsi_free_tokens(cso->base.tokens);
3399f464c52Smaya
3407ec681f3Smrg        for (unsigned i = 0; i < cso->variant_count; ++i) {
3417ec681f3Smrg                struct panfrost_shader_state *shader_state = &cso->variants[i];
3427ec681f3Smrg                panfrost_bo_unreference(shader_state->bin.bo);
3437ec681f3Smrg                panfrost_bo_unreference(shader_state->state.bo);
3447ec681f3Smrg                panfrost_bo_unreference(shader_state->linkage.bo);
3459f464c52Smaya        }
3469f464c52Smaya
3477ec681f3Smrg        simple_mtx_destroy(&cso->lock);
3487ec681f3Smrg
3497ec681f3Smrg        free(cso->variants);
3507ec681f3Smrg        free(so);
3517ec681f3Smrg}
3527ec681f3Smrg
3537ec681f3Smrgstatic void
3547ec681f3Smrgpanfrost_bind_sampler_states(
3557ec681f3Smrg        struct pipe_context *pctx,
3567ec681f3Smrg        enum pipe_shader_type shader,
3577ec681f3Smrg        unsigned start_slot, unsigned num_sampler,
3587ec681f3Smrg        void **sampler)
3597ec681f3Smrg{
3607ec681f3Smrg        assert(start_slot == 0);
3619f464c52Smaya
3627ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
3637ec681f3Smrg        ctx->dirty_shader[shader] |= PAN_DIRTY_STAGE_SAMPLER;
3649f464c52Smaya
3657ec681f3Smrg        ctx->sampler_count[shader] = sampler ? num_sampler : 0;
3667ec681f3Smrg        if (sampler)
3677ec681f3Smrg                memcpy(ctx->samplers[shader], sampler, num_sampler * sizeof (void *));
3687ec681f3Smrg}
3699f464c52Smaya
3707ec681f3Smrgstatic bool
3717ec681f3Smrgpanfrost_variant_matches(
3727ec681f3Smrg        struct panfrost_context *ctx,
3737ec681f3Smrg        struct panfrost_shader_state *variant,
3747ec681f3Smrg        enum pipe_shader_type type)
3757ec681f3Smrg{
3767ec681f3Smrg        if (variant->info.stage == MESA_SHADER_FRAGMENT &&
3777ec681f3Smrg            variant->info.fs.outputs_read) {
3787ec681f3Smrg                struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
3799f464c52Smaya
3807ec681f3Smrg                unsigned i;
3817ec681f3Smrg                BITSET_FOREACH_SET(i, &variant->info.fs.outputs_read, 8) {
3827ec681f3Smrg                        enum pipe_format fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
3839f464c52Smaya
3847ec681f3Smrg                        if ((fb->nr_cbufs > i) && fb->cbufs[i])
3857ec681f3Smrg                                fmt = fb->cbufs[i]->format;
3869f464c52Smaya
3877ec681f3Smrg                        if (panfrost_blendable_formats_v6[fmt].internal)
3887ec681f3Smrg                                fmt = PIPE_FORMAT_NONE;
3899f464c52Smaya
3907ec681f3Smrg                        if (variant->rt_formats[i] != fmt)
3917ec681f3Smrg                                return false;
3927ec681f3Smrg                }
3937ec681f3Smrg        }
3949f464c52Smaya
3957ec681f3Smrg        if (variant->info.stage == MESA_SHADER_FRAGMENT &&
3967ec681f3Smrg            variant->nr_cbufs != ctx->pipe_framebuffer.nr_cbufs)
3977ec681f3Smrg                return false;
3989f464c52Smaya
3997ec681f3Smrg        /* Otherwise, we're good to go */
4007ec681f3Smrg        return true;
4019f464c52Smaya}
4029f464c52Smaya
4037ec681f3Smrg/**
4047ec681f3Smrg * Fix an uncompiled shader's stream output info, and produce a bitmask
4057ec681f3Smrg * of which VARYING_SLOT_* are captured for stream output.
4067ec681f3Smrg *
4077ec681f3Smrg * Core Gallium stores output->register_index as a "slot" number, where
4087ec681f3Smrg * slots are assigned consecutively to all outputs in info->outputs_written.
4097ec681f3Smrg * This naive packing of outputs doesn't work for us - we too have slots,
4107ec681f3Smrg * but the layout is defined by the VUE map, which we won't have until we
4117ec681f3Smrg * compile a specific shader variant.  So, we remap these and simply store
4127ec681f3Smrg * VARYING_SLOT_* in our copy's output->register_index fields.
4137ec681f3Smrg *
4147ec681f3Smrg * We then produce a bitmask of outputs which are used for SO.
4157ec681f3Smrg *
4167ec681f3Smrg * Implementation from iris.
4177ec681f3Smrg */
4189f464c52Smaya
4197ec681f3Smrgstatic uint64_t
4207ec681f3Smrgupdate_so_info(struct pipe_stream_output_info *so_info,
4217ec681f3Smrg               uint64_t outputs_written)
4227ec681f3Smrg{
4237ec681f3Smrg	uint64_t so_outputs = 0;
4247ec681f3Smrg	uint8_t reverse_map[64] = {0};
4257ec681f3Smrg	unsigned slot = 0;
4269f464c52Smaya
4277ec681f3Smrg	while (outputs_written)
4287ec681f3Smrg		reverse_map[slot++] = u_bit_scan64(&outputs_written);
4299f464c52Smaya
4307ec681f3Smrg	for (unsigned i = 0; i < so_info->num_outputs; i++) {
4317ec681f3Smrg		struct pipe_stream_output *output = &so_info->output[i];
4329f464c52Smaya
4337ec681f3Smrg		/* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */
4347ec681f3Smrg		output->register_index = reverse_map[output->register_index];
4359f464c52Smaya
4367ec681f3Smrg		so_outputs |= 1ull << output->register_index;
4377ec681f3Smrg	}
4389f464c52Smaya
4397ec681f3Smrg	return so_outputs;
4409f464c52Smaya}
4419f464c52Smaya
4429f464c52Smayastatic void
4437ec681f3Smrgpanfrost_bind_shader_state(
4447ec681f3Smrg        struct pipe_context *pctx,
4457ec681f3Smrg        void *hwcso,
4467ec681f3Smrg        enum pipe_shader_type type)
4479f464c52Smaya{
4489f464c52Smaya        struct panfrost_context *ctx = pan_context(pctx);
4497ec681f3Smrg        ctx->shader[type] = hwcso;
4509f464c52Smaya
4517ec681f3Smrg        ctx->dirty |= PAN_DIRTY_TLS_SIZE;
4527ec681f3Smrg        ctx->dirty_shader[type] |= PAN_DIRTY_STAGE_RENDERER;
4539f464c52Smaya
4547ec681f3Smrg        if (!hwcso) return;
4559f464c52Smaya
4567ec681f3Smrg        /* Match the appropriate variant */
4579f464c52Smaya
4587ec681f3Smrg        signed variant = -1;
4597ec681f3Smrg        struct panfrost_shader_variants *variants = (struct panfrost_shader_variants *) hwcso;
4609f464c52Smaya
4617ec681f3Smrg        simple_mtx_lock(&variants->lock);
4629f464c52Smaya
4637ec681f3Smrg        for (unsigned i = 0; i < variants->variant_count; ++i) {
4647ec681f3Smrg                if (panfrost_variant_matches(ctx, &variants->variants[i], type)) {
4657ec681f3Smrg                        variant = i;
4667ec681f3Smrg                        break;
4679f464c52Smaya                }
4687ec681f3Smrg        }
4699f464c52Smaya
4707ec681f3Smrg        if (variant == -1) {
4717ec681f3Smrg                /* No variant matched, so create a new one */
4727ec681f3Smrg                variant = variants->variant_count++;
4739f464c52Smaya
4747ec681f3Smrg                if (variants->variant_count > variants->variant_space) {
4757ec681f3Smrg                        unsigned old_space = variants->variant_space;
4769f464c52Smaya
4777ec681f3Smrg                        variants->variant_space *= 2;
4787ec681f3Smrg                        if (variants->variant_space == 0)
4797ec681f3Smrg                                variants->variant_space = 1;
4809f464c52Smaya
4817ec681f3Smrg                        /* Arbitrary limit to stop runaway programs from
4827ec681f3Smrg                         * creating an unbounded number of shader variants. */
4837ec681f3Smrg                        assert(variants->variant_space < 1024);
4849f464c52Smaya
4857ec681f3Smrg                        unsigned msize = sizeof(struct panfrost_shader_state);
4867ec681f3Smrg                        variants->variants = realloc(variants->variants,
4877ec681f3Smrg                                                     variants->variant_space * msize);
4889f464c52Smaya
4897ec681f3Smrg                        memset(&variants->variants[old_space], 0,
4907ec681f3Smrg                               (variants->variant_space - old_space) * msize);
4919f464c52Smaya                }
4929f464c52Smaya
4937ec681f3Smrg                struct panfrost_shader_state *v =
4947ec681f3Smrg                                &variants->variants[variant];
4959f464c52Smaya
4967ec681f3Smrg                if (type == PIPE_SHADER_FRAGMENT) {
4977ec681f3Smrg                        struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;
4987ec681f3Smrg                        v->nr_cbufs = fb->nr_cbufs;
4999f464c52Smaya
5007ec681f3Smrg                        for (unsigned i = 0; i < fb->nr_cbufs; ++i) {
5017ec681f3Smrg                                enum pipe_format fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
5029f464c52Smaya
5037ec681f3Smrg                                if ((fb->nr_cbufs > i) && fb->cbufs[i])
5047ec681f3Smrg                                        fmt = fb->cbufs[i]->format;
5059f464c52Smaya
5067ec681f3Smrg                                if (panfrost_blendable_formats_v6[fmt].internal)
5077ec681f3Smrg                                        fmt = PIPE_FORMAT_NONE;
5089f464c52Smaya
5097ec681f3Smrg                                v->rt_formats[i] = fmt;
5109f464c52Smaya                        }
5119f464c52Smaya                }
5129f464c52Smaya        }
5139f464c52Smaya
5147ec681f3Smrg        /* Select this variant */
5157ec681f3Smrg        variants->active_variant = variant;
5169f464c52Smaya
5177ec681f3Smrg        struct panfrost_shader_state *shader_state = &variants->variants[variant];
5187ec681f3Smrg        assert(panfrost_variant_matches(ctx, shader_state, type));
5199f464c52Smaya
5207ec681f3Smrg        /* We finally have a variant, so compile it */
5219f464c52Smaya
5227ec681f3Smrg        if (!shader_state->compiled) {
5237ec681f3Smrg                panfrost_shader_compile(ctx->base.screen,
5247ec681f3Smrg                                        &ctx->shaders, &ctx->descs,
5257ec681f3Smrg                                        variants->base.type,
5267ec681f3Smrg                                        variants->base.type == PIPE_SHADER_IR_NIR ?
5277ec681f3Smrg                                        variants->base.ir.nir :
5287ec681f3Smrg                                        variants->base.tokens,
5297ec681f3Smrg                                        tgsi_processor_to_shader_stage(type),
5307ec681f3Smrg                                        shader_state);
5319f464c52Smaya
5327ec681f3Smrg                shader_state->compiled = true;
5339f464c52Smaya
5347ec681f3Smrg                /* Fixup the stream out information */
5357ec681f3Smrg                shader_state->stream_output = variants->base.stream_output;
5367ec681f3Smrg                shader_state->so_mask =
5377ec681f3Smrg                        update_so_info(&shader_state->stream_output,
5387ec681f3Smrg                                       shader_state->info.outputs_written);
5397ec681f3Smrg        }
5409f464c52Smaya
5417ec681f3Smrg        /* TODO: it would be more efficient to release the lock before
5427ec681f3Smrg         * compiling instead of after, but that can race if thread A compiles a
5437ec681f3Smrg         * variant while thread B searches for that same variant */
5447ec681f3Smrg        simple_mtx_unlock(&variants->lock);
5459f464c52Smaya}
5469f464c52Smaya
5477ec681f3Smrgstatic void *
5487ec681f3Smrgpanfrost_create_vs_state(struct pipe_context *pctx, const struct pipe_shader_state *hwcso)
5499f464c52Smaya{
5507ec681f3Smrg        return panfrost_create_shader_state(pctx, hwcso, PIPE_SHADER_VERTEX);
5517ec681f3Smrg}
5529f464c52Smaya
5537ec681f3Smrgstatic void *
5547ec681f3Smrgpanfrost_create_fs_state(struct pipe_context *pctx, const struct pipe_shader_state *hwcso)
5557ec681f3Smrg{
5567ec681f3Smrg        return panfrost_create_shader_state(pctx, hwcso, PIPE_SHADER_FRAGMENT);
5577ec681f3Smrg}
5589f464c52Smaya
5597ec681f3Smrgstatic void
5607ec681f3Smrgpanfrost_bind_vs_state(struct pipe_context *pctx, void *hwcso)
5617ec681f3Smrg{
5627ec681f3Smrg        panfrost_bind_shader_state(pctx, hwcso, PIPE_SHADER_VERTEX);
5639f464c52Smaya}
5649f464c52Smaya
5659f464c52Smayastatic void
5667ec681f3Smrgpanfrost_bind_fs_state(struct pipe_context *pctx, void *hwcso)
5679f464c52Smaya{
5687ec681f3Smrg        panfrost_bind_shader_state(pctx, hwcso, PIPE_SHADER_FRAGMENT);
5697ec681f3Smrg}
5709f464c52Smaya
5717ec681f3Smrgstatic void
5727ec681f3Smrgpanfrost_set_vertex_buffers(
5737ec681f3Smrg        struct pipe_context *pctx,
5747ec681f3Smrg        unsigned start_slot,
5757ec681f3Smrg        unsigned num_buffers,
5767ec681f3Smrg        unsigned unbind_num_trailing_slots,
5777ec681f3Smrg        bool take_ownership,
5787ec681f3Smrg        const struct pipe_vertex_buffer *buffers)
5797ec681f3Smrg{
5807ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
5819f464c52Smaya
5827ec681f3Smrg        util_set_vertex_buffers_mask(ctx->vertex_buffers, &ctx->vb_mask, buffers,
5837ec681f3Smrg                                     start_slot, num_buffers, unbind_num_trailing_slots,
5847ec681f3Smrg                                     take_ownership);
5859f464c52Smaya}
5869f464c52Smaya
5879f464c52Smayastatic void
5887ec681f3Smrgpanfrost_set_constant_buffer(
5897ec681f3Smrg        struct pipe_context *pctx,
5907ec681f3Smrg        enum pipe_shader_type shader, uint index, bool take_ownership,
5917ec681f3Smrg        const struct pipe_constant_buffer *buf)
5929f464c52Smaya{
5937ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
5947ec681f3Smrg        struct panfrost_constant_buffer *pbuf = &ctx->constant_buffer[shader];
5959f464c52Smaya
5967ec681f3Smrg        util_copy_constant_buffer(&pbuf->cb[index], buf, take_ownership);
5979f464c52Smaya
5987ec681f3Smrg        unsigned mask = (1 << index);
5999f464c52Smaya
6007ec681f3Smrg        if (unlikely(!buf)) {
6017ec681f3Smrg                pbuf->enabled_mask &= ~mask;
6027ec681f3Smrg                return;
6039f464c52Smaya        }
6047ec681f3Smrg
6057ec681f3Smrg        pbuf->enabled_mask |= mask;
6067ec681f3Smrg        ctx->dirty_shader[shader] |= PAN_DIRTY_STAGE_CONST;
6079f464c52Smaya}
6089f464c52Smaya
6097ec681f3Smrgstatic void
6107ec681f3Smrgpanfrost_set_stencil_ref(
6117ec681f3Smrg        struct pipe_context *pctx,
6127ec681f3Smrg        const struct pipe_stencil_ref ref)
6139f464c52Smaya{
6147ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
6157ec681f3Smrg        ctx->stencil_ref = ref;
6167ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
6179f464c52Smaya}
6189f464c52Smaya
6199f464c52Smayastatic void
6207ec681f3Smrgpanfrost_set_sampler_views(
6217ec681f3Smrg        struct pipe_context *pctx,
6227ec681f3Smrg        enum pipe_shader_type shader,
6237ec681f3Smrg        unsigned start_slot, unsigned num_views,
6247ec681f3Smrg        unsigned unbind_num_trailing_slots,
6257ec681f3Smrg        bool take_ownership,
6267ec681f3Smrg        struct pipe_sampler_view **views)
6279f464c52Smaya{
6287ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
6297ec681f3Smrg        ctx->dirty_shader[shader] |= PAN_DIRTY_STAGE_TEXTURE;
6309f464c52Smaya
6317ec681f3Smrg        unsigned new_nr = 0;
6327ec681f3Smrg        unsigned i;
6337ec681f3Smrg
6347ec681f3Smrg        assert(start_slot == 0);
6357ec681f3Smrg
6367ec681f3Smrg        if (!views)
6377ec681f3Smrg                num_views = 0;
6389f464c52Smaya
6397ec681f3Smrg        for (i = 0; i < num_views; ++i) {
6407ec681f3Smrg                if (views[i])
6417ec681f3Smrg                        new_nr = i + 1;
6427ec681f3Smrg                if (take_ownership) {
6437ec681f3Smrg                        pipe_sampler_view_reference((struct pipe_sampler_view **)&ctx->sampler_views[shader][i],
6447ec681f3Smrg                                                    NULL);
6457ec681f3Smrg                        ctx->sampler_views[shader][i] = (struct panfrost_sampler_view *)views[i];
6467ec681f3Smrg                } else {
6477ec681f3Smrg                        pipe_sampler_view_reference((struct pipe_sampler_view **)&ctx->sampler_views[shader][i],
6487ec681f3Smrg                                                    views[i]);
6497ec681f3Smrg                }
6507ec681f3Smrg        }
6519f464c52Smaya
6527ec681f3Smrg        for (; i < ctx->sampler_view_count[shader]; i++) {
6537ec681f3Smrg		pipe_sampler_view_reference((struct pipe_sampler_view **)&ctx->sampler_views[shader][i],
6547ec681f3Smrg		                            NULL);
6559f464c52Smaya        }
6567ec681f3Smrg        ctx->sampler_view_count[shader] = new_nr;
6577ec681f3Smrg}
6589f464c52Smaya
6597ec681f3Smrgstatic void
6607ec681f3Smrgpanfrost_set_shader_buffers(
6617ec681f3Smrg        struct pipe_context *pctx,
6627ec681f3Smrg        enum pipe_shader_type shader,
6637ec681f3Smrg        unsigned start, unsigned count,
6647ec681f3Smrg        const struct pipe_shader_buffer *buffers,
6657ec681f3Smrg        unsigned writable_bitmask)
6667ec681f3Smrg{
6677ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
6689f464c52Smaya
6697ec681f3Smrg        util_set_shader_buffers_mask(ctx->ssbo[shader], &ctx->ssbo_mask[shader],
6707ec681f3Smrg                        buffers, start, count);
6717ec681f3Smrg}
6729f464c52Smaya
6737ec681f3Smrgstatic void
6747ec681f3Smrgpanfrost_set_framebuffer_state(struct pipe_context *pctx,
6757ec681f3Smrg                               const struct pipe_framebuffer_state *fb)
6767ec681f3Smrg{
6777ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
6789f464c52Smaya
6797ec681f3Smrg        util_copy_framebuffer_state(&ctx->pipe_framebuffer, fb);
6807ec681f3Smrg        ctx->batch = NULL;
6819f464c52Smaya
6827ec681f3Smrg        /* Hot draw call path needs the mask of active render targets */
6837ec681f3Smrg        ctx->fb_rt_mask = 0;
6849f464c52Smaya
6857ec681f3Smrg        for (unsigned i = 0; i < ctx->pipe_framebuffer.nr_cbufs; ++i) {
6867ec681f3Smrg                if (ctx->pipe_framebuffer.cbufs[i])
6877ec681f3Smrg                        ctx->fb_rt_mask |= BITFIELD_BIT(i);
6887ec681f3Smrg        }
6899f464c52Smaya
6907ec681f3Smrg        /* We may need to generate a new variant if the fragment shader is
6917ec681f3Smrg         * keyed to the framebuffer format or render target count */
6927ec681f3Smrg        struct panfrost_shader_variants *fs = ctx->shader[PIPE_SHADER_FRAGMENT];
6939f464c52Smaya
6947ec681f3Smrg        if (fs && fs->variant_count)
6957ec681f3Smrg                ctx->base.bind_fs_state(&ctx->base, fs);
6969f464c52Smaya}
6979f464c52Smaya
6989f464c52Smayastatic void
6997ec681f3Smrgpanfrost_bind_depth_stencil_state(struct pipe_context *pipe,
7007ec681f3Smrg                                  void *cso)
7019f464c52Smaya{
7027ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
7037ec681f3Smrg        ctx->depth_stencil = cso;
7047ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
7059f464c52Smaya}
7069f464c52Smaya
7079f464c52Smayastatic void
7089f464c52Smayapanfrost_set_sample_mask(struct pipe_context *pipe,
7099f464c52Smaya                         unsigned sample_mask)
7109f464c52Smaya{
7117ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
7127ec681f3Smrg        ctx->sample_mask = sample_mask;
7137ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
7147ec681f3Smrg}
7157ec681f3Smrg
7167ec681f3Smrgstatic void
7177ec681f3Smrgpanfrost_set_min_samples(struct pipe_context *pipe,
7187ec681f3Smrg                         unsigned min_samples)
7197ec681f3Smrg{
7207ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
7217ec681f3Smrg        ctx->min_samples = min_samples;
7227ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
7239f464c52Smaya}
7249f464c52Smaya
7259f464c52Smayastatic void
7269f464c52Smayapanfrost_set_clip_state(struct pipe_context *pipe,
7279f464c52Smaya                        const struct pipe_clip_state *clip)
7289f464c52Smaya{
7299f464c52Smaya        //struct panfrost_context *panfrost = pan_context(pipe);
7309f464c52Smaya}
7319f464c52Smaya
7329f464c52Smayastatic void
7339f464c52Smayapanfrost_set_viewport_states(struct pipe_context *pipe,
7349f464c52Smaya                             unsigned start_slot,
7359f464c52Smaya                             unsigned num_viewports,
7369f464c52Smaya                             const struct pipe_viewport_state *viewports)
7379f464c52Smaya{
7389f464c52Smaya        struct panfrost_context *ctx = pan_context(pipe);
7399f464c52Smaya
7409f464c52Smaya        assert(start_slot == 0);
7419f464c52Smaya        assert(num_viewports == 1);
7429f464c52Smaya
7439f464c52Smaya        ctx->pipe_viewport = *viewports;
7447ec681f3Smrg        ctx->dirty |= PAN_DIRTY_VIEWPORT;
7459f464c52Smaya}
7469f464c52Smaya
7479f464c52Smayastatic void
7489f464c52Smayapanfrost_set_scissor_states(struct pipe_context *pipe,
7499f464c52Smaya                            unsigned start_slot,
7509f464c52Smaya                            unsigned num_scissors,
7519f464c52Smaya                            const struct pipe_scissor_state *scissors)
7529f464c52Smaya{
7539f464c52Smaya        struct panfrost_context *ctx = pan_context(pipe);
7549f464c52Smaya
7559f464c52Smaya        assert(start_slot == 0);
7569f464c52Smaya        assert(num_scissors == 1);
7579f464c52Smaya
7589f464c52Smaya        ctx->scissor = *scissors;
7597ec681f3Smrg        ctx->dirty |= PAN_DIRTY_SCISSOR;
7609f464c52Smaya}
7619f464c52Smaya
7629f464c52Smayastatic void
7639f464c52Smayapanfrost_set_polygon_stipple(struct pipe_context *pipe,
7649f464c52Smaya                             const struct pipe_poly_stipple *stipple)
7659f464c52Smaya{
7669f464c52Smaya        //struct panfrost_context *panfrost = pan_context(pipe);
7679f464c52Smaya}
7689f464c52Smaya
7699f464c52Smayastatic void
7709f464c52Smayapanfrost_set_active_query_state(struct pipe_context *pipe,
7717ec681f3Smrg                                bool enable)
7729f464c52Smaya{
7737ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
7747ec681f3Smrg        ctx->active_queries = enable;
7757ec681f3Smrg        ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
7767ec681f3Smrg}
7777ec681f3Smrg
7787ec681f3Smrgstatic void
7797ec681f3Smrgpanfrost_render_condition(struct pipe_context *pipe,
7807ec681f3Smrg                          struct pipe_query *query,
7817ec681f3Smrg                          bool condition,
7827ec681f3Smrg                          enum pipe_render_cond_flag mode)
7837ec681f3Smrg{
7847ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
7857ec681f3Smrg
7867ec681f3Smrg        ctx->cond_query = (struct panfrost_query *)query;
7877ec681f3Smrg        ctx->cond_cond = condition;
7887ec681f3Smrg        ctx->cond_mode = mode;
7899f464c52Smaya}
7909f464c52Smaya
7919f464c52Smayastatic void
7929f464c52Smayapanfrost_destroy(struct pipe_context *pipe)
7939f464c52Smaya{
7949f464c52Smaya        struct panfrost_context *panfrost = pan_context(pipe);
7957ec681f3Smrg
7967ec681f3Smrg        _mesa_hash_table_destroy(panfrost->writers, NULL);
7979f464c52Smaya
7989f464c52Smaya        if (panfrost->blitter)
7999f464c52Smaya                util_blitter_destroy(panfrost->blitter);
8009f464c52Smaya
8017ec681f3Smrg        util_unreference_framebuffer_state(&panfrost->pipe_framebuffer);
8027ec681f3Smrg        u_upload_destroy(pipe->stream_uploader);
8037ec681f3Smrg
8047ec681f3Smrg        panfrost_pool_cleanup(&panfrost->descs);
8057ec681f3Smrg        panfrost_pool_cleanup(&panfrost->shaders);
8067ec681f3Smrg
8077ec681f3Smrg        ralloc_free(pipe);
8089f464c52Smaya}
8099f464c52Smaya
8109f464c52Smayastatic struct pipe_query *
8117ec681f3Smrgpanfrost_create_query(struct pipe_context *pipe,
8127ec681f3Smrg                      unsigned type,
8137ec681f3Smrg                      unsigned index)
8149f464c52Smaya{
8157ec681f3Smrg        struct panfrost_query *q = rzalloc(pipe, struct panfrost_query);
8169f464c52Smaya
8179f464c52Smaya        q->type = type;
8189f464c52Smaya        q->index = index;
8199f464c52Smaya
8209f464c52Smaya        return (struct pipe_query *) q;
8219f464c52Smaya}
8229f464c52Smaya
8239f464c52Smayastatic void
8249f464c52Smayapanfrost_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
8259f464c52Smaya{
8267ec681f3Smrg        struct panfrost_query *query = (struct panfrost_query *) q;
8277ec681f3Smrg
8287ec681f3Smrg        if (query->rsrc)
8297ec681f3Smrg                pipe_resource_reference(&query->rsrc, NULL);
8307ec681f3Smrg
8317ec681f3Smrg        ralloc_free(q);
8329f464c52Smaya}
8339f464c52Smaya
8347ec681f3Smrgstatic bool
8359f464c52Smayapanfrost_begin_query(struct pipe_context *pipe, struct pipe_query *q)
8369f464c52Smaya{
8379f464c52Smaya        struct panfrost_context *ctx = pan_context(pipe);
8387ec681f3Smrg        struct panfrost_device *dev = pan_device(ctx->base.screen);
8399f464c52Smaya        struct panfrost_query *query = (struct panfrost_query *) q;
8409f464c52Smaya
8419f464c52Smaya        switch (query->type) {
8427ec681f3Smrg        case PIPE_QUERY_OCCLUSION_COUNTER:
8437ec681f3Smrg        case PIPE_QUERY_OCCLUSION_PREDICATE:
8447ec681f3Smrg        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: {
8457ec681f3Smrg                unsigned size = sizeof(uint64_t) * dev->core_count;
8467ec681f3Smrg
8477ec681f3Smrg                /* Allocate a resource for the query results to be stored */
8487ec681f3Smrg                if (!query->rsrc) {
8497ec681f3Smrg                        query->rsrc = pipe_buffer_create(ctx->base.screen,
8507ec681f3Smrg                                        PIPE_BIND_QUERY_BUFFER, 0, size);
8517ec681f3Smrg                }
8529f464c52Smaya
8537ec681f3Smrg                /* Default to 0 if nothing at all drawn. */
8547ec681f3Smrg                uint8_t *zeroes = alloca(size);
8557ec681f3Smrg                memset(zeroes, 0, size);
8567ec681f3Smrg                pipe_buffer_write(pipe, query->rsrc, 0, size, zeroes);
8579f464c52Smaya
8587ec681f3Smrg                query->msaa = (ctx->pipe_framebuffer.samples > 1);
8597ec681f3Smrg                ctx->occlusion_query = query;
8607ec681f3Smrg                ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
8617ec681f3Smrg                break;
8627ec681f3Smrg        }
8639f464c52Smaya
8647ec681f3Smrg        /* Geometry statistics are computed in the driver. XXX: geom/tess
8657ec681f3Smrg         * shaders.. */
8667ec681f3Smrg
8677ec681f3Smrg        case PIPE_QUERY_PRIMITIVES_GENERATED:
8687ec681f3Smrg                query->start = ctx->prims_generated;
8697ec681f3Smrg                break;
8707ec681f3Smrg        case PIPE_QUERY_PRIMITIVES_EMITTED:
8717ec681f3Smrg                query->start = ctx->tf_prims_generated;
8727ec681f3Smrg                break;
8737ec681f3Smrg
8747ec681f3Smrg        default:
8757ec681f3Smrg                /* TODO: timestamp queries, etc? */
8767ec681f3Smrg                break;
8779f464c52Smaya        }
8789f464c52Smaya
8799f464c52Smaya        return true;
8809f464c52Smaya}
8819f464c52Smaya
8829f464c52Smayastatic bool
8839f464c52Smayapanfrost_end_query(struct pipe_context *pipe, struct pipe_query *q)
8849f464c52Smaya{
8859f464c52Smaya        struct panfrost_context *ctx = pan_context(pipe);
8867ec681f3Smrg        struct panfrost_query *query = (struct panfrost_query *) q;
8877ec681f3Smrg
8887ec681f3Smrg        switch (query->type) {
8897ec681f3Smrg        case PIPE_QUERY_OCCLUSION_COUNTER:
8907ec681f3Smrg        case PIPE_QUERY_OCCLUSION_PREDICATE:
8917ec681f3Smrg        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
8927ec681f3Smrg                ctx->occlusion_query = NULL;
8937ec681f3Smrg                ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;
8947ec681f3Smrg                break;
8957ec681f3Smrg        case PIPE_QUERY_PRIMITIVES_GENERATED:
8967ec681f3Smrg                query->end = ctx->prims_generated;
8977ec681f3Smrg                break;
8987ec681f3Smrg        case PIPE_QUERY_PRIMITIVES_EMITTED:
8997ec681f3Smrg                query->end = ctx->tf_prims_generated;
9007ec681f3Smrg                break;
9017ec681f3Smrg        }
9027ec681f3Smrg
9039f464c52Smaya        return true;
9049f464c52Smaya}
9059f464c52Smaya
9067ec681f3Smrgstatic bool
9077ec681f3Smrgpanfrost_get_query_result(struct pipe_context *pipe,
9089f464c52Smaya                          struct pipe_query *q,
9097ec681f3Smrg                          bool wait,
9109f464c52Smaya                          union pipe_query_result *vresult)
9119f464c52Smaya{
9129f464c52Smaya        struct panfrost_query *query = (struct panfrost_query *) q;
9137ec681f3Smrg        struct panfrost_context *ctx = pan_context(pipe);
9147ec681f3Smrg        struct panfrost_device *dev = pan_device(ctx->base.screen);
9157ec681f3Smrg        struct panfrost_resource *rsrc = pan_resource(query->rsrc);
9169f464c52Smaya
9177ec681f3Smrg        switch (query->type) {
9187ec681f3Smrg        case PIPE_QUERY_OCCLUSION_COUNTER:
9197ec681f3Smrg        case PIPE_QUERY_OCCLUSION_PREDICATE:
9207ec681f3Smrg        case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
9217ec681f3Smrg                panfrost_flush_writer(ctx, rsrc, "Occlusion query");
9227ec681f3Smrg                panfrost_bo_wait(rsrc->image.data.bo, INT64_MAX, false);
9239f464c52Smaya
9247ec681f3Smrg                /* Read back the query results */
9257ec681f3Smrg                uint64_t *result = (uint64_t *) rsrc->image.data.bo->ptr.cpu;
9269f464c52Smaya
9277ec681f3Smrg                if (query->type == PIPE_QUERY_OCCLUSION_COUNTER) {
9287ec681f3Smrg                        uint64_t passed = 0;
9297ec681f3Smrg                        for (int i = 0; i < dev->core_count; ++i)
9307ec681f3Smrg                                passed += result[i];
9319f464c52Smaya
9327ec681f3Smrg                        if (!pan_is_bifrost(dev) && !query->msaa)
9337ec681f3Smrg                                passed /= 4;
9347ec681f3Smrg
9357ec681f3Smrg                        vresult->u64 = passed;
9367ec681f3Smrg                } else {
9377ec681f3Smrg                        vresult->b = !!result[0];
9389f464c52Smaya                }
9397ec681f3Smrg
9407ec681f3Smrg                break;
9417ec681f3Smrg
9427ec681f3Smrg        case PIPE_QUERY_PRIMITIVES_GENERATED:
9437ec681f3Smrg        case PIPE_QUERY_PRIMITIVES_EMITTED:
9447ec681f3Smrg                panfrost_flush_all_batches(ctx, "Primitive count query");
9457ec681f3Smrg                vresult->u64 = query->end - query->start;
9467ec681f3Smrg                break;
9477ec681f3Smrg
9487ec681f3Smrg        default:
9497ec681f3Smrg                /* TODO: more queries */
9507ec681f3Smrg                break;
9519f464c52Smaya        }
9529f464c52Smaya
9539f464c52Smaya        return true;
9549f464c52Smaya}
9559f464c52Smaya
9567ec681f3Smrgbool
9577ec681f3Smrgpanfrost_render_condition_check(struct panfrost_context *ctx)
9587ec681f3Smrg{
9597ec681f3Smrg	if (!ctx->cond_query)
9607ec681f3Smrg		return true;
9617ec681f3Smrg
9627ec681f3Smrg        perf_debug_ctx(ctx, "Implementing conditional rendering on the CPU");
9637ec681f3Smrg
9647ec681f3Smrg	union pipe_query_result res = { 0 };
9657ec681f3Smrg	bool wait =
9667ec681f3Smrg		ctx->cond_mode != PIPE_RENDER_COND_NO_WAIT &&
9677ec681f3Smrg		ctx->cond_mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT;
9687ec681f3Smrg
9697ec681f3Smrg        struct pipe_query *pq = (struct pipe_query *)ctx->cond_query;
9707ec681f3Smrg
9717ec681f3Smrg        if (panfrost_get_query_result(&ctx->base, pq, wait, &res))
9727ec681f3Smrg                return res.u64 != ctx->cond_cond;
9737ec681f3Smrg
9747ec681f3Smrg	return true;
9757ec681f3Smrg}
9767ec681f3Smrg
9779f464c52Smayastatic struct pipe_stream_output_target *
9789f464c52Smayapanfrost_create_stream_output_target(struct pipe_context *pctx,
9797ec681f3Smrg                                     struct pipe_resource *prsc,
9807ec681f3Smrg                                     unsigned buffer_offset,
9817ec681f3Smrg                                     unsigned buffer_size)
9829f464c52Smaya{
9839f464c52Smaya        struct pipe_stream_output_target *target;
9849f464c52Smaya
9857ec681f3Smrg        target = &rzalloc(pctx, struct panfrost_streamout_target)->base;
9869f464c52Smaya
9879f464c52Smaya        if (!target)
9889f464c52Smaya                return NULL;
9899f464c52Smaya
9909f464c52Smaya        pipe_reference_init(&target->reference, 1);
9919f464c52Smaya        pipe_resource_reference(&target->buffer, prsc);
9929f464c52Smaya
9939f464c52Smaya        target->context = pctx;
9949f464c52Smaya        target->buffer_offset = buffer_offset;
9959f464c52Smaya        target->buffer_size = buffer_size;
9969f464c52Smaya
9979f464c52Smaya        return target;
9989f464c52Smaya}
9999f464c52Smaya
10009f464c52Smayastatic void
10019f464c52Smayapanfrost_stream_output_target_destroy(struct pipe_context *pctx,
10027ec681f3Smrg                                      struct pipe_stream_output_target *target)
10039f464c52Smaya{
10049f464c52Smaya        pipe_resource_reference(&target->buffer, NULL);
10057ec681f3Smrg        ralloc_free(target);
10069f464c52Smaya}
10079f464c52Smaya
10089f464c52Smayastatic void
10099f464c52Smayapanfrost_set_stream_output_targets(struct pipe_context *pctx,
10107ec681f3Smrg                                   unsigned num_targets,
10117ec681f3Smrg                                   struct pipe_stream_output_target **targets,
10127ec681f3Smrg                                   const unsigned *offsets)
10139f464c52Smaya{
10147ec681f3Smrg        struct panfrost_context *ctx = pan_context(pctx);
10157ec681f3Smrg        struct panfrost_streamout *so = &ctx->streamout;
10169f464c52Smaya
10177ec681f3Smrg        assert(num_targets <= ARRAY_SIZE(so->targets));
10189f464c52Smaya
10197ec681f3Smrg        for (unsigned i = 0; i < num_targets; i++) {
10207ec681f3Smrg                if (offsets[i] != -1)
10217ec681f3Smrg                        pan_so_target(targets[i])->offset = offsets[i];
10229f464c52Smaya
10237ec681f3Smrg                pipe_so_target_reference(&so->targets[i], targets[i]);
10249f464c52Smaya        }
10259f464c52Smaya
10267ec681f3Smrg        for (unsigned i = 0; i < so->num_targets; i++)
10277ec681f3Smrg                pipe_so_target_reference(&so->targets[i], NULL);
10289f464c52Smaya
10297ec681f3Smrg        so->num_targets = num_targets;
10309f464c52Smaya}
10319f464c52Smaya
10329f464c52Smayastruct pipe_context *
10339f464c52Smayapanfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
10349f464c52Smaya{
10357ec681f3Smrg        struct panfrost_context *ctx = rzalloc(screen, struct panfrost_context);
10369f464c52Smaya        struct pipe_context *gallium = (struct pipe_context *) ctx;
10377ec681f3Smrg        struct panfrost_device *dev = pan_device(screen);
10389f464c52Smaya
10399f464c52Smaya        gallium->screen = screen;
10409f464c52Smaya
10419f464c52Smaya        gallium->destroy = panfrost_destroy;
10429f464c52Smaya
10439f464c52Smaya        gallium->set_framebuffer_state = panfrost_set_framebuffer_state;
10449f464c52Smaya
10459f464c52Smaya        gallium->flush = panfrost_flush;
10469f464c52Smaya        gallium->clear = panfrost_clear;
10477ec681f3Smrg        gallium->texture_barrier = panfrost_texture_barrier;
10487ec681f3Smrg        gallium->set_frontend_noop = panfrost_set_frontend_noop;
10499f464c52Smaya
10509f464c52Smaya        gallium->set_vertex_buffers = panfrost_set_vertex_buffers;
10519f464c52Smaya        gallium->set_constant_buffer = panfrost_set_constant_buffer;
10527ec681f3Smrg        gallium->set_shader_buffers = panfrost_set_shader_buffers;
10537ec681f3Smrg        gallium->set_shader_images = panfrost_set_shader_images;
10549f464c52Smaya
10559f464c52Smaya        gallium->set_stencil_ref = panfrost_set_stencil_ref;
10569f464c52Smaya
10579f464c52Smaya        gallium->set_sampler_views = panfrost_set_sampler_views;
10589f464c52Smaya
10599f464c52Smaya        gallium->bind_rasterizer_state = panfrost_bind_rasterizer_state;
10609f464c52Smaya        gallium->delete_rasterizer_state = panfrost_generic_cso_delete;
10619f464c52Smaya
10629f464c52Smaya        gallium->bind_vertex_elements_state = panfrost_bind_vertex_elements_state;
10637ec681f3Smrg        gallium->delete_vertex_elements_state = panfrost_generic_cso_delete;
10649f464c52Smaya
10657ec681f3Smrg        gallium->create_fs_state = panfrost_create_fs_state;
10669f464c52Smaya        gallium->delete_fs_state = panfrost_delete_shader_state;
10679f464c52Smaya        gallium->bind_fs_state = panfrost_bind_fs_state;
10689f464c52Smaya
10697ec681f3Smrg        gallium->create_vs_state = panfrost_create_vs_state;
10709f464c52Smaya        gallium->delete_vs_state = panfrost_delete_shader_state;
10719f464c52Smaya        gallium->bind_vs_state = panfrost_bind_vs_state;
10729f464c52Smaya
10739f464c52Smaya        gallium->delete_sampler_state = panfrost_generic_cso_delete;
10749f464c52Smaya        gallium->bind_sampler_states = panfrost_bind_sampler_states;
10759f464c52Smaya
10769f464c52Smaya        gallium->bind_depth_stencil_alpha_state   = panfrost_bind_depth_stencil_state;
10777ec681f3Smrg        gallium->delete_depth_stencil_alpha_state = panfrost_generic_cso_delete;
10789f464c52Smaya
10799f464c52Smaya        gallium->set_sample_mask = panfrost_set_sample_mask;
10807ec681f3Smrg        gallium->set_min_samples = panfrost_set_min_samples;
10819f464c52Smaya
10829f464c52Smaya        gallium->set_clip_state = panfrost_set_clip_state;
10839f464c52Smaya        gallium->set_viewport_states = panfrost_set_viewport_states;
10849f464c52Smaya        gallium->set_scissor_states = panfrost_set_scissor_states;
10859f464c52Smaya        gallium->set_polygon_stipple = panfrost_set_polygon_stipple;
10869f464c52Smaya        gallium->set_active_query_state = panfrost_set_active_query_state;
10877ec681f3Smrg        gallium->render_condition = panfrost_render_condition;
10889f464c52Smaya
10899f464c52Smaya        gallium->create_query = panfrost_create_query;
10909f464c52Smaya        gallium->destroy_query = panfrost_destroy_query;
10919f464c52Smaya        gallium->begin_query = panfrost_begin_query;
10929f464c52Smaya        gallium->end_query = panfrost_end_query;
10939f464c52Smaya        gallium->get_query_result = panfrost_get_query_result;
10949f464c52Smaya
10959f464c52Smaya        gallium->create_stream_output_target = panfrost_create_stream_output_target;
10969f464c52Smaya        gallium->stream_output_target_destroy = panfrost_stream_output_target_destroy;
10979f464c52Smaya        gallium->set_stream_output_targets = panfrost_set_stream_output_targets;
10989f464c52Smaya
10997ec681f3Smrg        gallium->bind_blend_state   = panfrost_bind_blend_state;
11007ec681f3Smrg        gallium->delete_blend_state = panfrost_generic_cso_delete;
11019f464c52Smaya
11027ec681f3Smrg        gallium->set_blend_color = panfrost_set_blend_color;
11037ec681f3Smrg
11047ec681f3Smrg        pan_screen(screen)->vtbl.context_init(gallium);
11059f464c52Smaya
11067ec681f3Smrg        panfrost_resource_context_init(gallium);
11077ec681f3Smrg        panfrost_compute_context_init(gallium);
11089f464c52Smaya
11099f464c52Smaya        gallium->stream_uploader = u_upload_create_default(gallium);
11109f464c52Smaya        gallium->const_uploader = gallium->stream_uploader;
11119f464c52Smaya
11127ec681f3Smrg        panfrost_pool_init(&ctx->descs, ctx, dev,
11137ec681f3Smrg                        0, 4096, "Descriptors", true, false);
11149f464c52Smaya
11157ec681f3Smrg        panfrost_pool_init(&ctx->shaders, ctx, dev,
11167ec681f3Smrg                        PAN_BO_EXECUTE, 4096, "Shaders", true, false);
11179f464c52Smaya
11189f464c52Smaya        ctx->blitter = util_blitter_create(gallium);
11197ec681f3Smrg
11207ec681f3Smrg        ctx->writers = _mesa_hash_table_create(gallium, _mesa_hash_pointer,
11217ec681f3Smrg                                                        _mesa_key_pointer_equal);
11227ec681f3Smrg
11239f464c52Smaya        assert(ctx->blitter);
11249f464c52Smaya
11259f464c52Smaya        /* Prepare for render! */
11269f464c52Smaya
11277ec681f3Smrg        /* By default mask everything on */
11287ec681f3Smrg        ctx->sample_mask = ~0;
11297ec681f3Smrg        ctx->active_queries = true;
11307ec681f3Smrg
11317ec681f3Smrg        int ASSERTED ret;
11327ec681f3Smrg
11337ec681f3Smrg        /* Create a syncobj in a signaled state. Will be updated to point to the
11347ec681f3Smrg         * last queued job out_sync every time we submit a new job.
11357ec681f3Smrg         */
11367ec681f3Smrg        ret = drmSyncobjCreate(dev->fd, DRM_SYNCOBJ_CREATE_SIGNALED, &ctx->syncobj);
11377ec681f3Smrg        assert(!ret && ctx->syncobj);
11389f464c52Smaya
11399f464c52Smaya        return gallium;
11409f464c52Smaya}
1141