Path: blob/21.2-virgl/src/gallium/drivers/vc4/vc4_qir_lower_uniforms.c
4570 views
/*1* Copyright © 2014 Broadcom2*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, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223/**24* @file vc4_qir_lower_uniforms.c25*26* This is the pre-code-generation pass for fixing up instructions that try to27* read from multiple uniform values.28*/2930#include "vc4_qir.h"31#include "util/hash_table.h"32#include "util/u_math.h"3334static inline uint32_t35index_hash(const void *key)36{37return (uintptr_t)key;38}3940static inline bool41index_compare(const void *a, const void *b)42{43return a == b;44}4546static void47add_uniform(struct hash_table *ht, struct qreg reg)48{49struct hash_entry *entry;50void *key = (void *)(uintptr_t)(reg.index + 1);5152entry = _mesa_hash_table_search(ht, key);53if (entry) {54entry->data++;55} else {56_mesa_hash_table_insert(ht, key, (void *)(uintptr_t)1);57}58}5960static void61remove_uniform(struct hash_table *ht, struct qreg reg)62{63struct hash_entry *entry;64void *key = (void *)(uintptr_t)(reg.index + 1);6566entry = _mesa_hash_table_search(ht, key);67assert(entry);68entry->data = (void *)(((uintptr_t) entry->data) - 1);69if (entry->data == NULL)70_mesa_hash_table_remove(ht, entry);71}7273static bool74is_lowerable_uniform(struct qinst *inst, int i)75{76if (inst->src[i].file != QFILE_UNIF)77return false;78if (qir_is_tex(inst))79return i != qir_get_tex_uniform_src(inst);80return true;81}8283/* Returns the number of different uniform values referenced by the84* instruction.85*/86static uint32_t87qir_get_instruction_uniform_count(struct qinst *inst)88{89uint32_t count = 0;9091for (int i = 0; i < qir_get_nsrc(inst); i++) {92if (inst->src[i].file != QFILE_UNIF)93continue;9495bool is_duplicate = false;96for (int j = 0; j < i; j++) {97if (inst->src[j].file == QFILE_UNIF &&98inst->src[j].index == inst->src[i].index) {99is_duplicate = true;100break;101}102}103if (!is_duplicate)104count++;105}106107return count;108}109110void111qir_lower_uniforms(struct vc4_compile *c)112{113struct hash_table *ht =114_mesa_hash_table_create(c, index_hash, index_compare);115116/* Walk the instruction list, finding which instructions have more117* than one uniform referenced, and add those uniform values to the118* ht.119*/120qir_for_each_inst_inorder(inst, c) {121uint32_t nsrc = qir_get_nsrc(inst);122123if (qir_get_instruction_uniform_count(inst) <= 1)124continue;125126for (int i = 0; i < nsrc; i++) {127if (is_lowerable_uniform(inst, i))128add_uniform(ht, inst->src[i]);129}130}131132while (ht->entries) {133/* Find the most commonly used uniform in instructions that134* need a uniform lowered.135*/136uint32_t max_count = 0;137uint32_t max_index = 0;138hash_table_foreach(ht, entry) {139uint32_t count = (uintptr_t)entry->data;140uint32_t index = (uintptr_t)entry->key - 1;141if (count > max_count) {142max_count = count;143max_index = index;144}145}146147struct qreg unif = qir_reg(QFILE_UNIF, max_index);148149/* Now, find the instructions using this uniform and make them150* reference a temp instead.151*/152qir_for_each_block(block, c) {153struct qinst *mov = NULL;154155qir_for_each_inst(inst, block) {156uint32_t nsrc = qir_get_nsrc(inst);157158uint32_t count = qir_get_instruction_uniform_count(inst);159160if (count <= 1)161continue;162163/* If the block doesn't have a load of hte164* uniform yet, add it. We could potentially165* do better and CSE MOVs from multiple blocks166* into dominating blocks, except that may167* cause troubles for register allocation.168*/169if (!mov) {170mov = qir_inst(QOP_MOV, qir_get_temp(c),171unif, c->undef);172list_add(&mov->link,173&block->instructions);174c->defs[mov->dst.index] = mov;175}176177bool removed = false;178for (int i = 0; i < nsrc; i++) {179if (is_lowerable_uniform(inst, i) &&180inst->src[i].index == max_index) {181inst->src[i] = mov->dst;182remove_uniform(ht, unif);183removed = true;184}185}186if (removed)187count--;188189/* If the instruction doesn't need lowering any more,190* then drop it from the list.191*/192if (count <= 1) {193for (int i = 0; i < nsrc; i++) {194if (is_lowerable_uniform(inst, i))195remove_uniform(ht, inst->src[i]);196}197}198}199}200}201202_mesa_hash_table_destroy(ht, NULL);203}204205206