Commit 35ffc9ac authored by Erik Faye-Lund 's avatar Erik Faye-Lund

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 's avatarErik Faye-Lund <erik.faye-lund@collabora.com>
parent 53eff53d
......@@ -180,6 +180,7 @@ with_gallium_svga = gallium_drivers.contains('svga')
with_gallium_virgl = gallium_drivers.contains('virgl')
with_gallium_swr = gallium_drivers.contains('swr')
with_gallium_lima = gallium_drivers.contains('lima')
with_gallium_zink = gallium_drivers.contains('zink')
if cc.get_id() == 'intel'
if meson.version().version_compare('< 0.49.0')
......@@ -467,6 +468,10 @@ if vdpau_drivers_path == ''
vdpau_drivers_path = join_paths(get_option('libdir'), 'vdpau')
endif
if with_gallium_zink
dep_vulkan = dependency('vulkan')
endif
_xvmc = get_option('gallium-xvmc')
if not system_has_kms_drm
if _xvmc == 'true'
......
......@@ -60,7 +60,7 @@ option(
choices : [
'', 'auto', 'kmsro', 'radeonsi', 'r300', 'r600', 'nouveau', 'freedreno',
'swrast', 'v3d', 'vc4', 'etnaviv', 'tegra', 'i915', 'svga', 'virgl',
'swr', 'panfrost', 'iris', 'lima'
'swr', 'panfrost', 'iris', 'lima', 'zink'
],
description : 'List of gallium drivers to build. If this is set to auto all drivers applicable to the target OS/architecture will be built'
)
......
......@@ -55,6 +55,11 @@ sw_screen_create_named(struct sw_winsys *winsys, const char *driver)
screen = swr_create_screen(winsys);
#endif
#if defined(GALLIUM_ZINK)
if (screen == NULL && strcmp(driver, "zink") == 0)
screen = zink_create_screen(winsys);
#endif
return screen;
}
......@@ -71,6 +76,8 @@ sw_screen_create(struct sw_winsys *winsys)
default_driver = "softpipe";
#elif defined(GALLIUM_SWR)
default_driver = "swr";
#elif defined(GALLIUM_ZINK)
default_driver = "zink";
#else
default_driver = "";
#endif
......
......@@ -12,6 +12,10 @@
* llvmpipe, softpipe, swr.
*/
#ifdef GALLIUM_ZINK
#include "zink/zink_public.h"
#endif
#ifdef GALLIUM_SOFTPIPE
#include "softpipe/sp_public.h"
#endif
......@@ -57,6 +61,11 @@ sw_screen_create_named(struct sw_winsys *winsys, const char *driver)
screen = swr_create_screen(winsys);
#endif
#if defined(GALLIUM_ZINK)
if (screen == NULL && strcmp(driver, "zink") == 0)
screen = zink_create_screen(winsys);
#endif
return screen;
}
......@@ -73,6 +82,8 @@ sw_screen_create(struct sw_winsys *winsys)
default_driver = "softpipe";
#elif defined(GALLIUM_SWR)
default_driver = "swr";
#elif defined(GALLIUM_SWR)
default_driver = "zink";
#else
default_driver = "";
#endif
......
# 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 the rights
# to use, copy, modify, merge, publish, distribute, sublicense, 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS 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.
files_libzink = files(
'nir_to_spirv/nir_to_spirv.c',
'nir_to_spirv/spirv_builder.c',
'zink_cmdbuf.c',
'zink_compiler.c',
'zink_context.c',
'zink_fence.c',
'zink_framebuffer.c',
'zink_pipeline.c',
'zink_program.c',
'zink_render_pass.c',
'zink_resource.c',
'zink_screen.c',
'zink_state.c',
'zink_surface.c',
)
libzink = static_library(
'zink',
files_libzink,
c_args : c_vis_args,
include_directories : inc_common,
dependencies: [dep_vulkan, idep_nir_headers],
)
driver_zink = declare_dependency(
compile_args : '-DGALLIUM_ZINK',
link_with : [libzink],
)
This diff is collapsed.
/*
* 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include <stdint.h>
#include <vulkan/vulkan.h>
struct spirv_shader {
uint32_t *words;
size_t num_words;
};
struct nir_shader;
struct spirv_shader *
nir_to_spirv(struct nir_shader *s);
void
spirv_shader_delete(struct spirv_shader *s);
#ifdef __cplusplus
}
#endif
This diff is collapsed.
/*
* 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.
*/
#ifndef SPIRV_BUILDER_H
#define SPIRV_BUILDER_H
#include "compiler/spirv/spirv.h"
#include "compiler/spirv/GLSL.std.450.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
struct spirv_buffer {
uint32_t *words;
size_t num_words, room;
};
struct spirv_builder {
struct spirv_buffer capabilities;
struct spirv_buffer imports;
struct spirv_buffer memory_model;
struct spirv_buffer entry_points;
struct spirv_buffer exec_modes;
struct spirv_buffer debug_names;
struct spirv_buffer decorations;
struct spirv_buffer types_const_defs;
struct hash_table *types;
struct spirv_buffer instructions;
SpvId prev_id;
};
static inline SpvId
spirv_builder_new_id(struct spirv_builder *b)
{
return ++b->prev_id;
}
void
spirv_builder_emit_cap(struct spirv_builder *b, SpvCapability cap);
void
spirv_builder_emit_source(struct spirv_builder *b, SpvSourceLanguage lang,
uint32_t version);
void
spirv_builder_emit_mem_model(struct spirv_builder *b,
SpvAddressingModel addr_model,
SpvMemoryModel mem_model);
void
spirv_builder_emit_name(struct spirv_builder *b, SpvId target,
const char *name);
void
spirv_builder_emit_decoration(struct spirv_builder *b, SpvId target,
SpvDecoration decoration);
void
spirv_builder_emit_location(struct spirv_builder *b, SpvId target,
uint32_t location);
void
spirv_builder_emit_component(struct spirv_builder *b, SpvId target,
uint32_t component);
void
spirv_builder_emit_builtin(struct spirv_builder *b, SpvId target,
SpvBuiltIn builtin);
void
spirv_builder_emit_descriptor_set(struct spirv_builder *b, SpvId target,
uint32_t descriptor_set);
void
spirv_builder_emit_binding(struct spirv_builder *b, SpvId target,
uint32_t binding);
void
spirv_builder_emit_array_stride(struct spirv_builder *b, SpvId target,
uint32_t stride);
void
spirv_builder_emit_member_offset(struct spirv_builder *b, SpvId target,
uint32_t member, uint32_t offset);
void
spirv_builder_emit_entry_point(struct spirv_builder *b,
SpvExecutionModel exec_model, SpvId entry_point,
const char *name, const SpvId interfaces[],
size_t num_interfaces);
void
spirv_builder_emit_exec_mode(struct spirv_builder *b, SpvId entry_point,
SpvExecutionMode exec_mode);
void
spirv_builder_function(struct spirv_builder *b, SpvId result,
SpvId return_type,
SpvFunctionControlMask function_control,
SpvId function_type);
void
spirv_builder_function_end(struct spirv_builder *b);
void
spirv_builder_label(struct spirv_builder *b, SpvId label);
void
spirv_builder_return(struct spirv_builder *b);
SpvId
spirv_builder_emit_undef(struct spirv_builder *b, SpvId result_type);
SpvId
spirv_builder_emit_load(struct spirv_builder *b, SpvId result_type,
SpvId pointer);
void
spirv_builder_emit_store(struct spirv_builder *b, SpvId pointer, SpvId object);
SpvId
spirv_builder_emit_access_chain(struct spirv_builder *b, SpvId result_type,
SpvId base, const SpvId indexes[],
size_t num_indexes);
SpvId
spirv_builder_emit_unop(struct spirv_builder *b, SpvOp op, SpvId result_type,
SpvId operand);
SpvId
spirv_builder_emit_binop(struct spirv_builder *b, SpvOp op, SpvId result_type,
SpvId operand0, SpvId operand1);
SpvId
spirv_builder_emit_triop(struct spirv_builder *b, SpvOp op, SpvId result_type,
SpvId operand0, SpvId operand1, SpvId operand2);
SpvId
spirv_builder_emit_composite_extract(struct spirv_builder *b, SpvId result_type,
SpvId composite, const uint32_t indexes[],
size_t num_indexes);
SpvId
spirv_builder_emit_composite_construct(struct spirv_builder *b,
SpvId result_type,
const SpvId constituents[],
size_t num_constituents);
SpvId
spirv_builder_emit_vector_shuffle(struct spirv_builder *b, SpvId result_type,
SpvId vector_1, SpvId vector_2,
const uint32_t components[],
size_t num_components);
SpvId
spirv_builder_emit_image_sample_implicit_lod(struct spirv_builder *b,
SpvId result_type,
SpvId sampled_image,
SpvId coordinate);
SpvId
spirv_builder_emit_image_sample_proj_implicit_lod(struct spirv_builder *b,
SpvId result_type,
SpvId sampled_image,
SpvId coordinate);
SpvId
spirv_builder_emit_ext_inst(struct spirv_builder *b, SpvId result_type,
SpvId set, uint32_t instruction,
const SpvId args[], size_t num_args);
SpvId
spirv_builder_type_void(struct spirv_builder *b);
SpvId
spirv_builder_type_bool(struct spirv_builder *b);
SpvId
spirv_builder_type_int(struct spirv_builder *b, unsigned width);
SpvId
spirv_builder_type_uint(struct spirv_builder *b, unsigned width);
SpvId
spirv_builder_type_float(struct spirv_builder *b, unsigned width);
SpvId
spirv_builder_type_image(struct spirv_builder *b, SpvId sampled_type,
SpvDim dim, bool depth, bool arrayed, bool ms,
unsigned sampled, SpvImageFormat image_format);
SpvId
spirv_builder_type_sampled_image(struct spirv_builder *b, SpvId image_type);
SpvId
spirv_builder_type_pointer(struct spirv_builder *b,
SpvStorageClass storage_class, SpvId type);
SpvId
spirv_builder_type_vector(struct spirv_builder *b, SpvId component_type,
unsigned component_count);
SpvId
spirv_builder_type_array(struct spirv_builder *b, SpvId component_type,
SpvId length);
SpvId
spirv_builder_type_struct(struct spirv_builder *b, const SpvId member_types[],
size_t num_member_types);
SpvId
spirv_builder_type_function(struct spirv_builder *b, SpvId return_type,
const SpvId parameter_types[],
size_t num_parameter_types);
SpvId
spirv_builder_const_bool(struct spirv_builder *b, bool val);
SpvId
spirv_builder_const_int(struct spirv_builder *b, int width, int32_t val);
SpvId
spirv_builder_const_uint(struct spirv_builder *b, int width, uint32_t val);
SpvId
spirv_builder_const_float(struct spirv_builder *b, int width, float val);
SpvId
spirv_builder_const_composite(struct spirv_builder *b, SpvId result_type,
const SpvId constituents[],
size_t num_constituents);
SpvId
spirv_builder_emit_var(struct spirv_builder *b, SpvId type,
SpvStorageClass storage_class);
SpvId
spirv_builder_import(struct spirv_builder *b, const char *name);
size_t
spirv_builder_get_num_words(struct spirv_builder *b);
size_t
spirv_builder_get_words(struct spirv_builder *b, uint32_t *words,
size_t num_words);
#endif
#include "zink_cmdbuf.h"
#include "zink_context.h"
#include "zink_fence.h"
#include "zink_screen.h"
#include "util/u_debug.h"
struct zink_cmdbuf *
zink_start_cmdbuf(struct zink_context *ctx)
{
struct zink_cmdbuf *cmdbuf = &ctx->cmdbuf;
if (cmdbuf->fence) {
struct zink_screen *screen = zink_screen(ctx->base.screen);
zink_fence_finish(screen, cmdbuf->fence, PIPE_TIMEOUT_INFINITE);
zink_fence_reference(screen, &cmdbuf->fence, NULL);
}
VkCommandBufferBeginInfo cbbi = {};
cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
if (vkBeginCommandBuffer(cmdbuf->cmdbuf, &cbbi) != VK_SUCCESS) {
debug_printf("vkBeginCommandBuffer failed\n");
return NULL;
}
return cmdbuf;
}
static bool
submit_cmdbuf(struct zink_context *ctx, VkCommandBuffer cmdbuf, VkFence fence)
{
VkPipelineStageFlags wait = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkSubmitInfo si = {};
si.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
si.waitSemaphoreCount = 0;
si.pWaitSemaphores = NULL;
si.signalSemaphoreCount = 0;
si.pSignalSemaphores = NULL;
si.pWaitDstStageMask = &wait;
si.commandBufferCount = 1;
si.pCommandBuffers = &cmdbuf;
if (vkQueueSubmit(ctx->queue, 1, &si, fence) != VK_SUCCESS) {
debug_printf("vkQueueSubmit failed\n");
return false;
}
return true;
}
void
zink_end_cmdbuf(struct zink_context *ctx, struct zink_cmdbuf *cmdbuf)
{
if (vkEndCommandBuffer(cmdbuf->cmdbuf) != VK_SUCCESS) {
debug_printf("vkEndCommandBuffer failed\n");
return;
}
assert(cmdbuf->fence == NULL);
cmdbuf->fence = zink_create_fence(ctx->base.screen);
if (!cmdbuf->fence ||
!submit_cmdbuf(ctx, cmdbuf->cmdbuf, cmdbuf->fence->fence))
return;
if (vkQueueWaitIdle(ctx->queue) != VK_SUCCESS)
debug_printf("vkQueueWaitIdle failed\n");
}
/*
* 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.
*/
#ifndef ZINK_CMDBUF_H
#define ZINK_CMDBUF_H
#include <vulkan/vulkan.h>
struct zink_context;
struct zink_fence;
struct zink_cmdbuf {
VkCommandBuffer cmdbuf;
struct zink_fence *fence;
};
struct zink_cmdbuf *
zink_start_cmdbuf(struct zink_context *ctx);
void
zink_end_cmdbuf(struct zink_context *ctx, struct zink_cmdbuf *cmdbuf);
#endif
/*
* 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);