aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/zink/zink_compiler.c
diff options
context:
space:
mode:
authorErik Faye-Lund <[email protected]>2018-08-31 16:50:20 +0200
committerErik Faye-Lund <[email protected]>2019-10-28 08:51:43 +0000
commit8d46e35d16e3936968958bcab86d61967a673305 (patch)
tree340ebb375451698e95c55ff577fc0e4412d803f2 /src/gallium/drivers/zink/zink_compiler.c
parent59127925010bfbab09e0c22a41ce77b334f59942 (diff)
zink: introduce opengl over vulkan
Here's zink, a so far pretty simple vulkan-gallium driver that is able to translate some applications from OpenGL to Vulkan. The compiler is quite limited for now, this will be improved on later. Signed-off-by: Erik Faye-Lund <[email protected]> Acked-by: Jordan Justen <[email protected]>
Diffstat (limited to 'src/gallium/drivers/zink/zink_compiler.c')
-rw-r--r--src/gallium/drivers/zink/zink_compiler.c263
1 files changed, 263 insertions, 0 deletions
diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c
new file mode 100644
index 00000000000..610caf6eaa0
--- /dev/null
+++ b/src/gallium/drivers/zink/zink_compiler.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2018 Collabora Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "zink_compiler.h"
+#include "zink_screen.h"
+#include "nir_to_spirv/nir_to_spirv.h"
+
+#include "pipe/p_state.h"
+
+#include "nir.h"
+#include "compiler/nir/nir_builder.h"
+
+#include "nir/tgsi_to_nir.h"
+#include "tgsi/tgsi_dump.h"
+#include "tgsi/tgsi_from_mesa.h"
+
+#include "util/u_memory.h"
+
+static bool
+lower_instr(nir_intrinsic_instr *instr, nir_builder *b)
+{
+ b->cursor = nir_before_instr(&instr->instr);
+
+ if (instr->intrinsic == nir_intrinsic_load_ubo) {
+ nir_ssa_def *old_idx = nir_ssa_for_src(b, instr->src[0], 1);
+ nir_ssa_def *new_idx = nir_iadd(b, old_idx, nir_imm_int(b, 1));
+ nir_instr_rewrite_src(&instr->instr, &instr->src[0],
+ nir_src_for_ssa(new_idx));
+ return true;
+ }
+
+ if (instr->intrinsic == nir_intrinsic_load_uniform) {
+ nir_ssa_def *ubo_idx = nir_imm_int(b, 0);
+ nir_ssa_def *ubo_offset =
+ nir_iadd(b, nir_imm_int(b, nir_intrinsic_base(instr)),
+ nir_ssa_for_src(b, instr->src[0], 1));
+
+ nir_intrinsic_instr *load =
+ nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_ubo);
+ load->num_components = instr->num_components;
+ load->src[0] = nir_src_for_ssa(ubo_idx);
+ load->src[1] = nir_src_for_ssa(ubo_offset);
+ nir_ssa_dest_init(&load->instr, &load->dest,
+ load->num_components, instr->dest.ssa.bit_size,
+ instr->dest.ssa.name);
+ nir_builder_instr_insert(b, &load->instr);
+ nir_ssa_def_rewrite_uses(&instr->dest.ssa, nir_src_for_ssa(&load->dest.ssa));
+
+ nir_instr_remove(&instr->instr);
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+lower_uniforms_to_ubo(nir_shader *shader)
+{
+ bool progress = false;
+
+ nir_foreach_function(function, shader) {
+ if (function->impl) {
+ nir_builder builder;
+ nir_builder_init(&builder, function->impl);
+ nir_foreach_block(block, function->impl) {
+ nir_foreach_instr_safe(instr, block) {
+ if (instr->type == nir_instr_type_intrinsic)
+ progress |= lower_instr(nir_instr_as_intrinsic(instr),
+ &builder);
+ }
+ }
+
+ nir_metadata_preserve(function->impl, nir_metadata_block_index |
+ nir_metadata_dominance);
+ }
+ }
+
+ if (progress) {
+ assert(shader->num_uniforms > 0);
+ const struct glsl_type *type = glsl_array_type(glsl_vec4_type(),
+ shader->num_uniforms, 0);
+ nir_variable *ubo = nir_variable_create(shader, nir_var_mem_ubo, type,
+ "uniform_0");
+ ubo->data.binding = 0;
+
+ struct glsl_struct_field field = {
+ .type = type,
+ .name = "data",
+ .location = -1,
+ };
+ ubo->interface_type =
+ glsl_interface_type(&field, 1, GLSL_INTERFACE_PACKING_STD430,
+ false, "__ubo0_interface");
+ }
+
+ return progress;
+}
+
+static const struct nir_shader_compiler_options nir_options = {
+ .lower_all_io_to_temps = true,
+ .lower_ffma = true,
+ .lower_flrp32 = true,
+ .lower_fpow = true,
+ .lower_fsat = true,
+};
+
+const void *
+zink_get_compiler_options(struct pipe_screen *screen,
+ enum pipe_shader_ir ir,
+ enum pipe_shader_type shader)
+{
+ assert(ir == PIPE_SHADER_IR_NIR);
+ return &nir_options;
+}
+
+struct nir_shader *
+zink_tgsi_to_nir(struct pipe_screen *screen, const struct tgsi_token *tokens)
+{
+ if (zink_debug & ZINK_DEBUG_TGSI) {
+ fprintf(stderr, "TGSI shader:\n---8<---\n");
+ tgsi_dump_to_file(tokens, 0, stderr);
+ fprintf(stderr, "---8<---\n\n");
+ }
+
+ return tgsi_to_nir(tokens, screen);
+}
+
+static void
+optimize_nir(struct nir_shader *s)
+{
+ bool progress;
+ do {
+ progress = false;
+ NIR_PASS_V(s, nir_lower_vars_to_ssa);
+ NIR_PASS(progress, s, nir_copy_prop);
+ NIR_PASS(progress, s, nir_opt_remove_phis);
+ NIR_PASS(progress, s, nir_opt_dce);
+ NIR_PASS(progress, s, nir_opt_dead_cf);
+ NIR_PASS(progress, s, nir_opt_cse);
+ NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true);
+ NIR_PASS(progress, s, nir_opt_algebraic);
+ NIR_PASS(progress, s, nir_opt_constant_folding);
+ NIR_PASS(progress, s, nir_opt_undef);
+ } while (progress);
+}
+
+static int
+glsl_type_size(const struct glsl_type *type, bool bindless)
+{
+ return glsl_count_attribute_slots(type, false);
+}
+
+static uint32_t
+zink_binding(enum pipe_shader_type stage, VkDescriptorType type, int index)
+{
+ if (stage == PIPE_SHADER_COMPUTE) {
+ unreachable("not supported");
+ } else {
+ uint32_t stage_offset = (uint32_t)stage * (PIPE_MAX_CONSTANT_BUFFERS +
+ PIPE_MAX_SHADER_SAMPLER_VIEWS);
+
+ switch (type) {
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ assert(index < PIPE_MAX_CONSTANT_BUFFERS);
+ return stage_offset + index;
+
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ assert(index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
+ return stage_offset + PIPE_MAX_CONSTANT_BUFFERS + index;
+
+ default:
+ unreachable("unexpected type");
+ }
+ }
+}
+
+struct zink_shader *
+zink_compile_nir(struct zink_screen *screen, struct nir_shader *nir)
+{
+ struct zink_shader *ret = CALLOC_STRUCT(zink_shader);
+
+ NIR_PASS_V(nir, nir_lower_io, nir_var_all, glsl_type_size, (nir_lower_io_options)0);
+ NIR_PASS_V(nir, lower_uniforms_to_ubo);
+ NIR_PASS_V(nir, nir_lower_regs_to_ssa);
+ NIR_PASS_V(nir, nir_lower_bool_to_float);
+ optimize_nir(nir);
+ NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp);
+
+ if (zink_debug & ZINK_DEBUG_NIR) {
+ fprintf(stderr, "NIR shader:\n---8<---\n");
+ nir_print_shader(nir, stderr);
+ fprintf(stderr, "---8<---\n");
+ }
+
+ enum pipe_shader_type stage = pipe_shader_type_from_mesa(nir->info.stage);
+
+ ret->num_bindings = 0;
+ nir_foreach_variable(var, &nir->uniforms) {
+ if (glsl_type_is_sampler(var->type)) {
+ ret->bindings[ret->num_bindings].index = var->data.driver_location;
+ var->data.binding = zink_binding(stage, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, var->data.driver_location);
+ ret->bindings[ret->num_bindings].binding = var->data.binding;
+ ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ ret->num_bindings++;
+ } else if (var->interface_type) {
+ ret->bindings[ret->num_bindings].index = var->data.binding;
+ var->data.binding = zink_binding(stage, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, var->data.binding);
+ ret->bindings[ret->num_bindings].binding = var->data.binding;
+ ret->bindings[ret->num_bindings].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ ret->num_bindings++;
+ }
+ }
+
+ struct spirv_shader *spirv = nir_to_spirv(nir);
+ assert(spirv);
+
+ if (zink_debug & ZINK_DEBUG_SPIRV) {
+ char buf[256];
+ static int i;
+ snprintf(buf, sizeof(buf), "dump%02d.spv", i++);
+ FILE *fp = fopen(buf, "wb");
+ fwrite(spirv->words, sizeof(uint32_t), spirv->num_words, fp);
+ fclose(fp);
+ fprintf(stderr, "wrote '%s'...\n", buf);
+ }
+
+ VkShaderModuleCreateInfo smci = {};
+ smci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ smci.codeSize = spirv->num_words * sizeof(uint32_t);
+ smci.pCode = spirv->words;
+
+ if (vkCreateShaderModule(screen->dev, &smci, NULL, &ret->shader_module) != VK_SUCCESS)
+ return NULL;
+
+ return ret;
+}
+
+void
+zink_shader_free(struct zink_screen *screen, struct zink_shader *shader)
+{
+ vkDestroyShaderModule(screen->dev, shader->shader_module, NULL);
+ FREE(shader);
+}