Path: blob/21.2-virgl/src/gallium/drivers/panfrost/pan_context.c
4570 views
/*1* Copyright (C) 2019-2020 Collabora, Ltd.2* © Copyright 2018 Alyssa Rosenzweig3* Copyright © 2014-2017 Broadcom4* Copyright (C) 2017 Intel Corporation5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the "Software"),8* to deal in the Software without restriction, including without limitation9* the rights to use, copy, modify, merge, publish, distribute, sublicense,10* and/or sell copies of the Software, and to permit persons to whom the11* Software is furnished to do so, subject to the following conditions:12*13* The above copyright notice and this permission notice (including the next14* paragraph) shall be included in all copies or substantial portions of the15* Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL20* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER21* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,22* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE23* SOFTWARE.24*25*/2627#include <sys/poll.h>28#include <errno.h>2930#include "pan_bo.h"31#include "pan_context.h"32#include "pan_minmax_cache.h"33#include "panfrost-quirks.h"3435#include "util/macros.h"36#include "util/format/u_format.h"37#include "util/u_inlines.h"38#include "util/u_upload_mgr.h"39#include "util/u_memory.h"40#include "util/u_vbuf.h"41#include "util/half_float.h"42#include "util/u_helpers.h"43#include "util/format/u_format.h"44#include "util/u_prim.h"45#include "util/u_prim_restart.h"46#include "indices/u_primconvert.h"47#include "tgsi/tgsi_parse.h"48#include "tgsi/tgsi_from_mesa.h"49#include "util/u_math.h"5051#include "pan_screen.h"52#include "pan_util.h"53#include "decode.h"54#include "util/pan_lower_framebuffer.h"5556static void57panfrost_clear(58struct pipe_context *pipe,59unsigned buffers,60const struct pipe_scissor_state *scissor_state,61const union pipe_color_union *color,62double depth, unsigned stencil)63{64struct panfrost_context *ctx = pan_context(pipe);6566if (!panfrost_render_condition_check(ctx))67return;6869/* TODO: panfrost_get_fresh_batch_for_fbo() instantiates a new batch if70* the existing batch targeting this FBO has draws. We could probably71* avoid that by replacing plain clears by quad-draws with a specific72* color/depth/stencil value, thus avoiding the generation of extra73* fragment jobs.74*/75struct panfrost_batch *batch = panfrost_get_fresh_batch_for_fbo(ctx);76panfrost_batch_clear(batch, buffers, color, depth, stencil);77}7879bool80panfrost_writes_point_size(struct panfrost_context *ctx)81{82assert(ctx->shader[PIPE_SHADER_VERTEX]);83struct panfrost_shader_state *vs = panfrost_get_shader_state(ctx, PIPE_SHADER_VERTEX);8485return vs->info.vs.writes_point_size && ctx->active_prim == PIPE_PRIM_POINTS;86}8788/* The entire frame is in memory -- send it off to the kernel! */8990void91panfrost_flush(92struct pipe_context *pipe,93struct pipe_fence_handle **fence,94unsigned flags)95{96struct panfrost_context *ctx = pan_context(pipe);97struct panfrost_device *dev = pan_device(pipe->screen);9899100/* Submit all pending jobs */101panfrost_flush_all_batches(ctx);102103if (fence) {104struct pipe_fence_handle *f = panfrost_fence_create(ctx);105pipe->screen->fence_reference(pipe->screen, fence, NULL);106*fence = f;107}108109if (dev->debug & PAN_DBG_TRACE)110pandecode_next_frame();111}112113static void114panfrost_texture_barrier(struct pipe_context *pipe, unsigned flags)115{116struct panfrost_context *ctx = pan_context(pipe);117panfrost_flush_all_batches(ctx);118}119120static void121panfrost_set_frontend_noop(struct pipe_context *pipe, bool enable)122{123struct panfrost_context *ctx = pan_context(pipe);124panfrost_flush_all_batches(ctx);125ctx->is_noop = enable;126}127128129static void130panfrost_generic_cso_delete(struct pipe_context *pctx, void *hwcso)131{132free(hwcso);133}134135static void136panfrost_bind_blend_state(struct pipe_context *pipe, void *cso)137{138struct panfrost_context *ctx = pan_context(pipe);139ctx->blend = cso;140ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;141}142143static void144panfrost_set_blend_color(struct pipe_context *pipe,145const struct pipe_blend_color *blend_color)146{147struct panfrost_context *ctx = pan_context(pipe);148ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;149150if (blend_color)151ctx->blend_color = *blend_color;152}153154/* Create a final blend given the context */155156mali_ptr157panfrost_get_blend(struct panfrost_batch *batch, unsigned rti, struct panfrost_bo **bo, unsigned *shader_offset)158{159struct panfrost_context *ctx = batch->ctx;160struct panfrost_device *dev = pan_device(ctx->base.screen);161struct panfrost_blend_state *blend = ctx->blend;162struct pan_blend_info info = blend->info[rti];163struct pipe_surface *surf = batch->key.cbufs[rti];164enum pipe_format fmt = surf->format;165166/* Use fixed-function if the equation permits, the format is blendable,167* and no more than one unique constant is accessed */168if (info.fixed_function && panfrost_blendable_formats_v7[fmt].internal &&169pan_blend_is_homogenous_constant(info.constant_mask,170ctx->blend_color.color)) {171return 0;172}173174/* Otherwise, we need to grab a shader */175struct pan_blend_state pan_blend = blend->pan;176unsigned nr_samples = surf->nr_samples ? : surf->texture->nr_samples;177178pan_blend.rts[rti].format = fmt;179pan_blend.rts[rti].nr_samples = nr_samples;180memcpy(pan_blend.constants, ctx->blend_color.color,181sizeof(pan_blend.constants));182183/* Upload the shader, sharing a BO */184if (!(*bo)) {185*bo = panfrost_batch_create_bo(batch, 4096, PAN_BO_EXECUTE,186PIPE_SHADER_FRAGMENT, "Blend shader");187}188189struct panfrost_shader_state *ss = panfrost_get_shader_state(ctx, PIPE_SHADER_FRAGMENT);190191/* Default for Midgard */192nir_alu_type col0_type = nir_type_float32;193nir_alu_type col1_type = nir_type_float32;194195/* Bifrost has per-output types, respect them */196if (pan_is_bifrost(dev)) {197col0_type = ss->info.bifrost.blend[rti].type;198col1_type = ss->info.bifrost.blend_src1_type;199}200201pthread_mutex_lock(&dev->blend_shaders.lock);202struct pan_blend_shader_variant *shader =203pan_blend_get_shader_locked(dev, &pan_blend,204col0_type, col1_type, rti);205206/* Size check and upload */207unsigned offset = *shader_offset;208assert((offset + shader->binary.size) < 4096);209memcpy((*bo)->ptr.cpu + offset, shader->binary.data, shader->binary.size);210*shader_offset += shader->binary.size;211pthread_mutex_unlock(&dev->blend_shaders.lock);212213return ((*bo)->ptr.gpu + offset) | shader->first_tag;214}215216static void217panfrost_bind_rasterizer_state(218struct pipe_context *pctx,219void *hwcso)220{221struct panfrost_context *ctx = pan_context(pctx);222ctx->rasterizer = hwcso;223224/* We can assume the renderer state descriptor is always dirty, the225* dependencies are too intricate to bother tracking in detail. However226* we could probably diff the renderers for viewport dirty tracking,227* that just cares about the scissor enable and the depth clips. */228ctx->dirty |= PAN_DIRTY_SCISSOR;229ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;230}231232static void233panfrost_set_shader_images(234struct pipe_context *pctx,235enum pipe_shader_type shader,236unsigned start_slot, unsigned count, unsigned unbind_num_trailing_slots,237const struct pipe_image_view *iviews)238{239struct panfrost_context *ctx = pan_context(pctx);240ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_IMAGE;241242/* Unbind start_slot...start_slot+count */243if (!iviews) {244for (int i = start_slot; i < start_slot + count + unbind_num_trailing_slots; i++) {245pipe_resource_reference(&ctx->images[shader][i].resource, NULL);246}247248ctx->image_mask[shader] &= ~(((1ull << count) - 1) << start_slot);249return;250}251252/* Bind start_slot...start_slot+count */253for (int i = 0; i < count; i++) {254const struct pipe_image_view *image = &iviews[i];255SET_BIT(ctx->image_mask[shader], 1 << (start_slot + i), image->resource);256257if (!image->resource) {258util_copy_image_view(&ctx->images[shader][start_slot+i], NULL);259continue;260}261262struct panfrost_resource *rsrc = pan_resource(image->resource);263264/* Images don't work with AFBC, since they require pixel-level granularity */265if (drm_is_afbc(rsrc->image.layout.modifier)) {266pan_resource_modifier_convert(ctx, rsrc,267DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);268}269270util_copy_image_view(&ctx->images[shader][start_slot+i], image);271}272273/* Unbind start_slot+count...start_slot+count+unbind_num_trailing_slots */274for (int i = 0; i < unbind_num_trailing_slots; i++) {275SET_BIT(ctx->image_mask[shader], 1 << (start_slot + count + i), NULL);276util_copy_image_view(&ctx->images[shader][start_slot+count+i], NULL);277}278}279280static void281panfrost_bind_vertex_elements_state(282struct pipe_context *pctx,283void *hwcso)284{285struct panfrost_context *ctx = pan_context(pctx);286ctx->vertex = hwcso;287}288289static void *290panfrost_create_shader_state(291struct pipe_context *pctx,292const struct pipe_shader_state *cso,293enum pipe_shader_type stage)294{295struct panfrost_shader_variants *so = CALLOC_STRUCT(panfrost_shader_variants);296struct panfrost_device *dev = pan_device(pctx->screen);297so->base = *cso;298299/* Token deep copy to prevent memory corruption */300301if (cso->type == PIPE_SHADER_IR_TGSI)302so->base.tokens = tgsi_dup_tokens(so->base.tokens);303304/* Precompile for shader-db if we need to */305if (unlikely((dev->debug & PAN_DBG_PRECOMPILE) && cso->type == PIPE_SHADER_IR_NIR)) {306struct panfrost_context *ctx = pan_context(pctx);307308struct panfrost_shader_state state = { 0 };309310panfrost_shader_compile(pctx->screen,311&ctx->shaders, &ctx->descs,312PIPE_SHADER_IR_NIR,313so->base.ir.nir,314tgsi_processor_to_shader_stage(stage),315&state);316}317318return so;319}320321static void322panfrost_delete_shader_state(323struct pipe_context *pctx,324void *so)325{326struct panfrost_shader_variants *cso = (struct panfrost_shader_variants *) so;327328if (cso->base.type == PIPE_SHADER_IR_TGSI) {329/* TODO: leaks TGSI tokens! */330}331332for (unsigned i = 0; i < cso->variant_count; ++i) {333struct panfrost_shader_state *shader_state = &cso->variants[i];334panfrost_bo_unreference(shader_state->bin.bo);335panfrost_bo_unreference(shader_state->state.bo);336panfrost_bo_unreference(shader_state->linkage.bo);337}338339free(cso->variants);340free(so);341}342343static void344panfrost_bind_sampler_states(345struct pipe_context *pctx,346enum pipe_shader_type shader,347unsigned start_slot, unsigned num_sampler,348void **sampler)349{350assert(start_slot == 0);351352struct panfrost_context *ctx = pan_context(pctx);353ctx->dirty_shader[shader] |= PAN_DIRTY_STAGE_SAMPLER;354355ctx->sampler_count[shader] = sampler ? num_sampler : 0;356if (sampler)357memcpy(ctx->samplers[shader], sampler, num_sampler * sizeof (void *));358}359360static bool361panfrost_variant_matches(362struct panfrost_context *ctx,363struct panfrost_shader_state *variant,364enum pipe_shader_type type)365{366struct panfrost_device *dev = pan_device(ctx->base.screen);367368if (variant->info.stage == MESA_SHADER_FRAGMENT &&369variant->info.fs.outputs_read) {370struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;371372unsigned i;373BITSET_FOREACH_SET(i, &variant->info.fs.outputs_read, 8) {374enum pipe_format fmt = PIPE_FORMAT_R8G8B8A8_UNORM;375376if ((fb->nr_cbufs > i) && fb->cbufs[i])377fmt = fb->cbufs[i]->format;378379const struct util_format_description *desc =380util_format_description(fmt);381382if (pan_format_class_load(desc, dev->quirks) == PAN_FORMAT_NATIVE)383fmt = PIPE_FORMAT_NONE;384385if (variant->rt_formats[i] != fmt)386return false;387}388}389390if (variant->info.stage == MESA_SHADER_FRAGMENT &&391variant->nr_cbufs != ctx->pipe_framebuffer.nr_cbufs)392return false;393394/* Otherwise, we're good to go */395return true;396}397398/**399* Fix an uncompiled shader's stream output info, and produce a bitmask400* of which VARYING_SLOT_* are captured for stream output.401*402* Core Gallium stores output->register_index as a "slot" number, where403* slots are assigned consecutively to all outputs in info->outputs_written.404* This naive packing of outputs doesn't work for us - we too have slots,405* but the layout is defined by the VUE map, which we won't have until we406* compile a specific shader variant. So, we remap these and simply store407* VARYING_SLOT_* in our copy's output->register_index fields.408*409* We then produce a bitmask of outputs which are used for SO.410*411* Implementation from iris.412*/413414static uint64_t415update_so_info(struct pipe_stream_output_info *so_info,416uint64_t outputs_written)417{418uint64_t so_outputs = 0;419uint8_t reverse_map[64] = {0};420unsigned slot = 0;421422while (outputs_written)423reverse_map[slot++] = u_bit_scan64(&outputs_written);424425for (unsigned i = 0; i < so_info->num_outputs; i++) {426struct pipe_stream_output *output = &so_info->output[i];427428/* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */429output->register_index = reverse_map[output->register_index];430431so_outputs |= 1ull << output->register_index;432}433434return so_outputs;435}436437static void438panfrost_bind_shader_state(439struct pipe_context *pctx,440void *hwcso,441enum pipe_shader_type type)442{443struct panfrost_context *ctx = pan_context(pctx);444struct panfrost_device *dev = pan_device(ctx->base.screen);445ctx->shader[type] = hwcso;446447ctx->dirty |= PAN_DIRTY_TLS_SIZE;448ctx->dirty_shader[type] |= PAN_DIRTY_STAGE_RENDERER;449450if (!hwcso) return;451452/* Match the appropriate variant */453454signed variant = -1;455struct panfrost_shader_variants *variants = (struct panfrost_shader_variants *) hwcso;456457for (unsigned i = 0; i < variants->variant_count; ++i) {458if (panfrost_variant_matches(ctx, &variants->variants[i], type)) {459variant = i;460break;461}462}463464if (variant == -1) {465/* No variant matched, so create a new one */466variant = variants->variant_count++;467468if (variants->variant_count > variants->variant_space) {469unsigned old_space = variants->variant_space;470471variants->variant_space *= 2;472if (variants->variant_space == 0)473variants->variant_space = 1;474475/* Arbitrary limit to stop runaway programs from476* creating an unbounded number of shader variants. */477assert(variants->variant_space < 1024);478479unsigned msize = sizeof(struct panfrost_shader_state);480variants->variants = realloc(variants->variants,481variants->variant_space * msize);482483memset(&variants->variants[old_space], 0,484(variants->variant_space - old_space) * msize);485}486487struct panfrost_shader_state *v =488&variants->variants[variant];489490if (type == PIPE_SHADER_FRAGMENT) {491struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer;492v->nr_cbufs = fb->nr_cbufs;493494for (unsigned i = 0; i < fb->nr_cbufs; ++i) {495enum pipe_format fmt = PIPE_FORMAT_R8G8B8A8_UNORM;496497if ((fb->nr_cbufs > i) && fb->cbufs[i])498fmt = fb->cbufs[i]->format;499500const struct util_format_description *desc =501util_format_description(fmt);502503if (pan_format_class_load(desc, dev->quirks) == PAN_FORMAT_NATIVE)504fmt = PIPE_FORMAT_NONE;505506v->rt_formats[i] = fmt;507}508}509}510511/* Select this variant */512variants->active_variant = variant;513514struct panfrost_shader_state *shader_state = &variants->variants[variant];515assert(panfrost_variant_matches(ctx, shader_state, type));516517/* We finally have a variant, so compile it */518519if (!shader_state->compiled) {520panfrost_shader_compile(ctx->base.screen,521&ctx->shaders, &ctx->descs,522variants->base.type,523variants->base.type == PIPE_SHADER_IR_NIR ?524variants->base.ir.nir :525variants->base.tokens,526tgsi_processor_to_shader_stage(type),527shader_state);528529shader_state->compiled = true;530531/* Fixup the stream out information */532shader_state->stream_output = variants->base.stream_output;533shader_state->so_mask =534update_so_info(&shader_state->stream_output,535shader_state->info.outputs_written);536}537}538539static void *540panfrost_create_vs_state(struct pipe_context *pctx, const struct pipe_shader_state *hwcso)541{542return panfrost_create_shader_state(pctx, hwcso, PIPE_SHADER_VERTEX);543}544545static void *546panfrost_create_fs_state(struct pipe_context *pctx, const struct pipe_shader_state *hwcso)547{548return panfrost_create_shader_state(pctx, hwcso, PIPE_SHADER_FRAGMENT);549}550551static void552panfrost_bind_vs_state(struct pipe_context *pctx, void *hwcso)553{554panfrost_bind_shader_state(pctx, hwcso, PIPE_SHADER_VERTEX);555}556557static void558panfrost_bind_fs_state(struct pipe_context *pctx, void *hwcso)559{560panfrost_bind_shader_state(pctx, hwcso, PIPE_SHADER_FRAGMENT);561}562563static void564panfrost_set_vertex_buffers(565struct pipe_context *pctx,566unsigned start_slot,567unsigned num_buffers,568unsigned unbind_num_trailing_slots,569bool take_ownership,570const struct pipe_vertex_buffer *buffers)571{572struct panfrost_context *ctx = pan_context(pctx);573574util_set_vertex_buffers_mask(ctx->vertex_buffers, &ctx->vb_mask, buffers,575start_slot, num_buffers, unbind_num_trailing_slots,576take_ownership);577}578579static void580panfrost_set_constant_buffer(581struct pipe_context *pctx,582enum pipe_shader_type shader, uint index, bool take_ownership,583const struct pipe_constant_buffer *buf)584{585struct panfrost_context *ctx = pan_context(pctx);586struct panfrost_constant_buffer *pbuf = &ctx->constant_buffer[shader];587588util_copy_constant_buffer(&pbuf->cb[index], buf, take_ownership);589590unsigned mask = (1 << index);591592if (unlikely(!buf)) {593pbuf->enabled_mask &= ~mask;594return;595}596597pbuf->enabled_mask |= mask;598ctx->dirty_shader[shader] |= PAN_DIRTY_STAGE_CONST;599}600601static void602panfrost_set_stencil_ref(603struct pipe_context *pctx,604const struct pipe_stencil_ref ref)605{606struct panfrost_context *ctx = pan_context(pctx);607ctx->stencil_ref = ref;608ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;609}610611static void612panfrost_set_sampler_views(613struct pipe_context *pctx,614enum pipe_shader_type shader,615unsigned start_slot, unsigned num_views,616unsigned unbind_num_trailing_slots,617struct pipe_sampler_view **views)618{619struct panfrost_context *ctx = pan_context(pctx);620ctx->dirty_shader[shader] |= PAN_DIRTY_STAGE_TEXTURE;621622unsigned new_nr = 0;623unsigned i;624625assert(start_slot == 0);626627if (!views)628num_views = 0;629630for (i = 0; i < num_views; ++i) {631if (views[i])632new_nr = i + 1;633pipe_sampler_view_reference((struct pipe_sampler_view **)&ctx->sampler_views[shader][i],634views[i]);635}636637for (; i < ctx->sampler_view_count[shader]; i++) {638pipe_sampler_view_reference((struct pipe_sampler_view **)&ctx->sampler_views[shader][i],639NULL);640}641ctx->sampler_view_count[shader] = new_nr;642}643644static void645panfrost_sampler_view_destroy(646struct pipe_context *pctx,647struct pipe_sampler_view *pview)648{649struct panfrost_sampler_view *view = (struct panfrost_sampler_view *) pview;650651pipe_resource_reference(&pview->texture, NULL);652panfrost_bo_unreference(view->state.bo);653ralloc_free(view);654}655656static void657panfrost_set_shader_buffers(658struct pipe_context *pctx,659enum pipe_shader_type shader,660unsigned start, unsigned count,661const struct pipe_shader_buffer *buffers,662unsigned writable_bitmask)663{664struct panfrost_context *ctx = pan_context(pctx);665666util_set_shader_buffers_mask(ctx->ssbo[shader], &ctx->ssbo_mask[shader],667buffers, start, count);668}669670static void671panfrost_set_framebuffer_state(struct pipe_context *pctx,672const struct pipe_framebuffer_state *fb)673{674struct panfrost_context *ctx = pan_context(pctx);675676util_copy_framebuffer_state(&ctx->pipe_framebuffer, fb);677ctx->batch = NULL;678679/* Hot draw call path needs the mask of active render targets */680ctx->fb_rt_mask = 0;681682for (unsigned i = 0; i < ctx->pipe_framebuffer.nr_cbufs; ++i) {683if (ctx->pipe_framebuffer.cbufs[i])684ctx->fb_rt_mask |= BITFIELD_BIT(i);685}686687/* We may need to generate a new variant if the fragment shader is688* keyed to the framebuffer format (due to EXT_framebuffer_fetch) */689struct panfrost_shader_variants *fs = ctx->shader[PIPE_SHADER_FRAGMENT];690691if (fs && fs->variant_count &&692fs->variants[fs->active_variant].info.fs.outputs_read)693ctx->base.bind_fs_state(&ctx->base, fs);694}695696static void697panfrost_bind_depth_stencil_state(struct pipe_context *pipe,698void *cso)699{700struct panfrost_context *ctx = pan_context(pipe);701ctx->depth_stencil = cso;702ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;703}704705static void706panfrost_set_sample_mask(struct pipe_context *pipe,707unsigned sample_mask)708{709struct panfrost_context *ctx = pan_context(pipe);710ctx->sample_mask = sample_mask;711ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;712}713714static void715panfrost_set_min_samples(struct pipe_context *pipe,716unsigned min_samples)717{718struct panfrost_context *ctx = pan_context(pipe);719ctx->min_samples = min_samples;720ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;721}722723static void724panfrost_set_clip_state(struct pipe_context *pipe,725const struct pipe_clip_state *clip)726{727//struct panfrost_context *panfrost = pan_context(pipe);728}729730static void731panfrost_set_viewport_states(struct pipe_context *pipe,732unsigned start_slot,733unsigned num_viewports,734const struct pipe_viewport_state *viewports)735{736struct panfrost_context *ctx = pan_context(pipe);737738assert(start_slot == 0);739assert(num_viewports == 1);740741ctx->pipe_viewport = *viewports;742ctx->dirty |= PAN_DIRTY_VIEWPORT;743}744745static void746panfrost_set_scissor_states(struct pipe_context *pipe,747unsigned start_slot,748unsigned num_scissors,749const struct pipe_scissor_state *scissors)750{751struct panfrost_context *ctx = pan_context(pipe);752753assert(start_slot == 0);754assert(num_scissors == 1);755756ctx->scissor = *scissors;757ctx->dirty |= PAN_DIRTY_SCISSOR;758}759760static void761panfrost_set_polygon_stipple(struct pipe_context *pipe,762const struct pipe_poly_stipple *stipple)763{764//struct panfrost_context *panfrost = pan_context(pipe);765}766767static void768panfrost_set_active_query_state(struct pipe_context *pipe,769bool enable)770{771struct panfrost_context *ctx = pan_context(pipe);772ctx->active_queries = enable;773ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;774}775776static void777panfrost_render_condition(struct pipe_context *pipe,778struct pipe_query *query,779bool condition,780enum pipe_render_cond_flag mode)781{782struct panfrost_context *ctx = pan_context(pipe);783784ctx->cond_query = (struct panfrost_query *)query;785ctx->cond_cond = condition;786ctx->cond_mode = mode;787}788789static void790panfrost_destroy(struct pipe_context *pipe)791{792struct panfrost_context *panfrost = pan_context(pipe);793794if (panfrost->blitter)795util_blitter_destroy(panfrost->blitter);796797util_unreference_framebuffer_state(&panfrost->pipe_framebuffer);798u_upload_destroy(pipe->stream_uploader);799800panfrost_pool_cleanup(&panfrost->descs);801panfrost_pool_cleanup(&panfrost->shaders);802803ralloc_free(pipe);804}805806static struct pipe_query *807panfrost_create_query(struct pipe_context *pipe,808unsigned type,809unsigned index)810{811struct panfrost_query *q = rzalloc(pipe, struct panfrost_query);812813q->type = type;814q->index = index;815816return (struct pipe_query *) q;817}818819static void820panfrost_destroy_query(struct pipe_context *pipe, struct pipe_query *q)821{822struct panfrost_query *query = (struct panfrost_query *) q;823824if (query->rsrc)825pipe_resource_reference(&query->rsrc, NULL);826827ralloc_free(q);828}829830static bool831panfrost_begin_query(struct pipe_context *pipe, struct pipe_query *q)832{833struct panfrost_context *ctx = pan_context(pipe);834struct panfrost_device *dev = pan_device(ctx->base.screen);835struct panfrost_query *query = (struct panfrost_query *) q;836837switch (query->type) {838case PIPE_QUERY_OCCLUSION_COUNTER:839case PIPE_QUERY_OCCLUSION_PREDICATE:840case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: {841unsigned size = sizeof(uint64_t) * dev->core_count;842843/* Allocate a resource for the query results to be stored */844if (!query->rsrc) {845query->rsrc = pipe_buffer_create(ctx->base.screen,846PIPE_BIND_QUERY_BUFFER, 0, size);847}848849/* Default to 0 if nothing at all drawn. */850uint8_t *zeroes = alloca(size);851memset(zeroes, 0, size);852pipe_buffer_write(pipe, query->rsrc, 0, size, zeroes);853854query->msaa = (ctx->pipe_framebuffer.samples > 1);855ctx->occlusion_query = query;856ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;857break;858}859860/* Geometry statistics are computed in the driver. XXX: geom/tess861* shaders.. */862863case PIPE_QUERY_PRIMITIVES_GENERATED:864query->start = ctx->prims_generated;865break;866case PIPE_QUERY_PRIMITIVES_EMITTED:867query->start = ctx->tf_prims_generated;868break;869870default:871/* TODO: timestamp queries, etc? */872break;873}874875return true;876}877878static bool879panfrost_end_query(struct pipe_context *pipe, struct pipe_query *q)880{881struct panfrost_context *ctx = pan_context(pipe);882struct panfrost_query *query = (struct panfrost_query *) q;883884switch (query->type) {885case PIPE_QUERY_OCCLUSION_COUNTER:886case PIPE_QUERY_OCCLUSION_PREDICATE:887case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:888ctx->occlusion_query = NULL;889ctx->dirty_shader[PIPE_SHADER_FRAGMENT] |= PAN_DIRTY_STAGE_RENDERER;890break;891case PIPE_QUERY_PRIMITIVES_GENERATED:892query->end = ctx->prims_generated;893break;894case PIPE_QUERY_PRIMITIVES_EMITTED:895query->end = ctx->tf_prims_generated;896break;897}898899return true;900}901902static bool903panfrost_get_query_result(struct pipe_context *pipe,904struct pipe_query *q,905bool wait,906union pipe_query_result *vresult)907{908struct panfrost_query *query = (struct panfrost_query *) q;909struct panfrost_context *ctx = pan_context(pipe);910struct panfrost_device *dev = pan_device(ctx->base.screen);911struct panfrost_resource *rsrc = pan_resource(query->rsrc);912913switch (query->type) {914case PIPE_QUERY_OCCLUSION_COUNTER:915case PIPE_QUERY_OCCLUSION_PREDICATE:916case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:917panfrost_flush_writer(ctx, rsrc);918panfrost_bo_wait(rsrc->image.data.bo, INT64_MAX, false);919920/* Read back the query results */921uint64_t *result = (uint64_t *) rsrc->image.data.bo->ptr.cpu;922923if (query->type == PIPE_QUERY_OCCLUSION_COUNTER) {924uint64_t passed = 0;925for (int i = 0; i < dev->core_count; ++i)926passed += result[i];927928if (!pan_is_bifrost(dev) && !query->msaa)929passed /= 4;930931vresult->u64 = passed;932} else {933vresult->b = !!result[0];934}935936break;937938case PIPE_QUERY_PRIMITIVES_GENERATED:939case PIPE_QUERY_PRIMITIVES_EMITTED:940panfrost_flush_all_batches(ctx);941vresult->u64 = query->end - query->start;942break;943944default:945/* TODO: more queries */946break;947}948949return true;950}951952bool953panfrost_render_condition_check(struct panfrost_context *ctx)954{955if (!ctx->cond_query)956return true;957958union pipe_query_result res = { 0 };959bool wait =960ctx->cond_mode != PIPE_RENDER_COND_NO_WAIT &&961ctx->cond_mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT;962963struct pipe_query *pq = (struct pipe_query *)ctx->cond_query;964965if (panfrost_get_query_result(&ctx->base, pq, wait, &res))966return res.u64 != ctx->cond_cond;967968return true;969}970971static struct pipe_stream_output_target *972panfrost_create_stream_output_target(struct pipe_context *pctx,973struct pipe_resource *prsc,974unsigned buffer_offset,975unsigned buffer_size)976{977struct pipe_stream_output_target *target;978979target = &rzalloc(pctx, struct panfrost_streamout_target)->base;980981if (!target)982return NULL;983984pipe_reference_init(&target->reference, 1);985pipe_resource_reference(&target->buffer, prsc);986987target->context = pctx;988target->buffer_offset = buffer_offset;989target->buffer_size = buffer_size;990991return target;992}993994static void995panfrost_stream_output_target_destroy(struct pipe_context *pctx,996struct pipe_stream_output_target *target)997{998pipe_resource_reference(&target->buffer, NULL);999ralloc_free(target);1000}10011002static void1003panfrost_set_stream_output_targets(struct pipe_context *pctx,1004unsigned num_targets,1005struct pipe_stream_output_target **targets,1006const unsigned *offsets)1007{1008struct panfrost_context *ctx = pan_context(pctx);1009struct panfrost_streamout *so = &ctx->streamout;10101011assert(num_targets <= ARRAY_SIZE(so->targets));10121013for (unsigned i = 0; i < num_targets; i++) {1014if (offsets[i] != -1)1015pan_so_target(targets[i])->offset = offsets[i];10161017pipe_so_target_reference(&so->targets[i], targets[i]);1018}10191020for (unsigned i = 0; i < so->num_targets; i++)1021pipe_so_target_reference(&so->targets[i], NULL);10221023so->num_targets = num_targets;1024}10251026struct pipe_context *1027panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags)1028{1029struct panfrost_context *ctx = rzalloc(screen, struct panfrost_context);1030struct pipe_context *gallium = (struct pipe_context *) ctx;1031struct panfrost_device *dev = pan_device(screen);10321033gallium->screen = screen;10341035gallium->destroy = panfrost_destroy;10361037gallium->set_framebuffer_state = panfrost_set_framebuffer_state;10381039gallium->flush = panfrost_flush;1040gallium->clear = panfrost_clear;1041gallium->texture_barrier = panfrost_texture_barrier;1042gallium->set_frontend_noop = panfrost_set_frontend_noop;10431044gallium->set_vertex_buffers = panfrost_set_vertex_buffers;1045gallium->set_constant_buffer = panfrost_set_constant_buffer;1046gallium->set_shader_buffers = panfrost_set_shader_buffers;1047gallium->set_shader_images = panfrost_set_shader_images;10481049gallium->set_stencil_ref = panfrost_set_stencil_ref;10501051gallium->set_sampler_views = panfrost_set_sampler_views;1052gallium->sampler_view_destroy = panfrost_sampler_view_destroy;10531054gallium->bind_rasterizer_state = panfrost_bind_rasterizer_state;1055gallium->delete_rasterizer_state = panfrost_generic_cso_delete;10561057gallium->bind_vertex_elements_state = panfrost_bind_vertex_elements_state;1058gallium->delete_vertex_elements_state = panfrost_generic_cso_delete;10591060gallium->create_fs_state = panfrost_create_fs_state;1061gallium->delete_fs_state = panfrost_delete_shader_state;1062gallium->bind_fs_state = panfrost_bind_fs_state;10631064gallium->create_vs_state = panfrost_create_vs_state;1065gallium->delete_vs_state = panfrost_delete_shader_state;1066gallium->bind_vs_state = panfrost_bind_vs_state;10671068gallium->delete_sampler_state = panfrost_generic_cso_delete;1069gallium->bind_sampler_states = panfrost_bind_sampler_states;10701071gallium->bind_depth_stencil_alpha_state = panfrost_bind_depth_stencil_state;1072gallium->delete_depth_stencil_alpha_state = panfrost_generic_cso_delete;10731074gallium->set_sample_mask = panfrost_set_sample_mask;1075gallium->set_min_samples = panfrost_set_min_samples;10761077gallium->set_clip_state = panfrost_set_clip_state;1078gallium->set_viewport_states = panfrost_set_viewport_states;1079gallium->set_scissor_states = panfrost_set_scissor_states;1080gallium->set_polygon_stipple = panfrost_set_polygon_stipple;1081gallium->set_active_query_state = panfrost_set_active_query_state;1082gallium->render_condition = panfrost_render_condition;10831084gallium->create_query = panfrost_create_query;1085gallium->destroy_query = panfrost_destroy_query;1086gallium->begin_query = panfrost_begin_query;1087gallium->end_query = panfrost_end_query;1088gallium->get_query_result = panfrost_get_query_result;10891090gallium->create_stream_output_target = panfrost_create_stream_output_target;1091gallium->stream_output_target_destroy = panfrost_stream_output_target_destroy;1092gallium->set_stream_output_targets = panfrost_set_stream_output_targets;10931094gallium->bind_blend_state = panfrost_bind_blend_state;1095gallium->delete_blend_state = panfrost_generic_cso_delete;10961097gallium->set_blend_color = panfrost_set_blend_color;10981099panfrost_cmdstream_context_init(gallium);1100panfrost_resource_context_init(gallium);1101panfrost_compute_context_init(gallium);11021103gallium->stream_uploader = u_upload_create_default(gallium);1104gallium->const_uploader = gallium->stream_uploader;11051106panfrost_pool_init(&ctx->descs, ctx, dev,11070, 4096, "Descriptors", true, false);11081109panfrost_pool_init(&ctx->shaders, ctx, dev,1110PAN_BO_EXECUTE, 4096, "Shaders", true, false);11111112/* All of our GPUs support ES mode. Midgard supports additionally1113* QUADS/QUAD_STRIPS/POLYGON. Bifrost supports just QUADS. */11141115ctx->draw_modes = (1 << (PIPE_PRIM_QUADS + 1)) - 1;11161117if (!pan_is_bifrost(dev)) {1118ctx->draw_modes |= (1 << PIPE_PRIM_QUAD_STRIP);1119ctx->draw_modes |= (1 << PIPE_PRIM_POLYGON);1120}11211122ctx->primconvert = util_primconvert_create(gallium, ctx->draw_modes);11231124ctx->blitter = util_blitter_create(gallium);11251126assert(ctx->blitter);11271128/* Prepare for render! */11291130/* By default mask everything on */1131ctx->sample_mask = ~0;1132ctx->active_queries = true;11331134int ASSERTED ret;11351136/* Create a syncobj in a signaled state. Will be updated to point to the1137* last queued job out_sync every time we submit a new job.1138*/1139ret = drmSyncobjCreate(dev->fd, DRM_SYNCOBJ_CREATE_SIGNALED, &ctx->syncobj);1140assert(!ret && ctx->syncobj);11411142return gallium;1143}114411451146