st/nine: Use tgsi_to_nir when preferred IR is NIR.
authorTimur Kristóf <timur.kristof@gmail.com>
Fri, 31 May 2019 16:43:20 +0000 (18:43 +0200)
committerAxel Davy <davyaxel0@gmail.com>
Wed, 5 Jun 2019 21:32:13 +0000 (23:32 +0200)
This patch allows nine to read the preferred IR from pipe caps and use
NIR when that is preferred by the driver, by calling tgsi_to_nir. Also
adds some debug options that allow overriding it.

Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Reviewed-by: Axel Davy <davyaxel0@gmail.com>
src/gallium/state_trackers/nine/meson.build
src/gallium/state_trackers/nine/nine_ff.c
src/gallium/state_trackers/nine/nine_shader.c
src/gallium/state_trackers/nine/nine_shader.h

index 491b7937ab19d754e498d5f64e7724358f7040fc..7c9e035cafc4696406bcc248949841d340863f5f 100644 (file)
@@ -66,5 +66,10 @@ libnine_st = static_library(
   include_directories : [
     inc_d3d9, inc_gallium, inc_include, inc_src, inc_gallium_aux,
   ],
-  dependencies : dep_thread,
+  dependencies : [
+    dep_thread, idep_nir, idep_nir_headers
+  ],
+  link_with : [
+    libmesa_gallium
+  ]
 )
index b38205d61000a3121bd196c379ff4a3d40543b1b..5e756b36707d47e827d3d20b74b34f2351e7b6f5 100644 (file)
@@ -1060,7 +1060,7 @@ nine_ff_build_vs(struct NineDevice9 *device, struct vs_build_ctx *vs)
 
     ureg_END(ureg);
     nine_ureg_tgsi_dump(ureg, FALSE);
-    return ureg_create_shader_and_destroy(ureg, device->context.pipe);
+    return nine_create_shader_with_so_and_destroy(ureg, device->context.pipe, NULL);
 }
 
 /* PS FF constants layout:
@@ -1555,7 +1555,7 @@ nine_ff_build_ps(struct NineDevice9 *device, struct nine_ff_ps_key *key)
 
     ureg_END(ureg);
     nine_ureg_tgsi_dump(ureg, FALSE);
-    return ureg_create_shader_and_destroy(ureg, device->context.pipe);
+    return nine_create_shader_with_so_and_destroy(ureg, device->context.pipe, NULL);
 }
 
 static struct NineVertexShader9 *
index 212fd60255a2eadc1dacd1e3e9842ac508704d36..93910f90741f821bab1e5441ea22dbcb794a6f7f 100644 (file)
@@ -34,6 +34,7 @@
 #include "pipe/p_shader_tokens.h"
 #include "tgsi/tgsi_ureg.h"
 #include "tgsi/tgsi_dump.h"
+#include "nir/tgsi_to_nir.h"
 
 #define DBG_CHANNEL DBG_SHADER
 
@@ -3789,6 +3790,123 @@ static void parse_shader(struct shader_translator *tx)
     ureg_END(tx->ureg);
 }
 
+#define NINE_SHADER_DEBUG_OPTION_NIR_VS           (1 << 0)
+#define NINE_SHADER_DEBUG_OPTION_NIR_PS           (1 << 1)
+#define NINE_SHADER_DEBUG_OPTION_NO_NIR_VS        (1 << 2)
+#define NINE_SHADER_DEBUG_OPTION_NO_NIR_PS        (1 << 3)
+#define NINE_SHADER_DEBUG_OPTION_DUMP_NIR         (1 << 4)
+#define NINE_SHADER_DEBUG_OPTION_DUMP_TGSI        (1 << 5)
+
+static const struct debug_named_value nine_shader_debug_options[] = {
+    { "nir_vs", NINE_SHADER_DEBUG_OPTION_NIR_VS, "Use NIR for vertex shaders even if the driver doesn't prefer it." },
+    { "nir_ps", NINE_SHADER_DEBUG_OPTION_NIR_PS, "Use NIR for pixel shaders even if the driver doesn't prefer it." },
+    { "no_nir_vs", NINE_SHADER_DEBUG_OPTION_NO_NIR_VS, "Never use NIR for vertex shaders even if the driver prefers it." },
+    { "no_nir_ps", NINE_SHADER_DEBUG_OPTION_NO_NIR_PS, "Never use NIR for pixel shaders even if the driver prefers it." },
+    { "dump_nir", NINE_SHADER_DEBUG_OPTION_DUMP_NIR, "Print translated NIR shaders." },
+    { "dump_tgsi", NINE_SHADER_DEBUG_OPTION_DUMP_TGSI, "Print TGSI shaders." },
+    DEBUG_NAMED_VALUE_END /* must be last */
+};
+
+static inline boolean
+nine_shader_get_debug_flag(uint64_t flag)
+{
+    static uint64_t flags = 0;
+    static boolean first_run = TRUE;
+
+    if (unlikely(first_run)) {
+        first_run = FALSE;
+        flags = debug_get_flags_option("NINE_SHADER", nine_shader_debug_options, 0);
+
+        // Check old TGSI dump envvar too
+        if (debug_get_bool_option("NINE_TGSI_DUMP", FALSE)) {
+            flags |= NINE_SHADER_DEBUG_OPTION_DUMP_TGSI;
+        }
+    }
+
+    return !!(flags & flag);
+}
+
+static void
+nine_pipe_nir_shader_state_from_tgsi(struct pipe_shader_state *state, const struct tgsi_token *tgsi_tokens,
+                                     struct pipe_screen *screen)
+{
+    struct nir_shader *nir = tgsi_to_nir(tgsi_tokens, screen);
+
+    if (unlikely(nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_DUMP_NIR))) {
+        nir_print_shader(nir, stdout);
+    }
+
+    state->type = PIPE_SHADER_IR_NIR;
+    state->tokens = NULL;
+    state->ir.nir = nir;
+    memset(&state->stream_output, 0, sizeof(state->stream_output));
+}
+
+static void *
+nine_ureg_create_shader(struct ureg_program                  *ureg,
+                        struct pipe_context                  *pipe,
+                        const struct pipe_stream_output_info   *so)
+{
+    struct pipe_shader_state state;
+    const struct tgsi_token *tgsi_tokens;
+    struct pipe_screen *screen = pipe->screen;
+
+    tgsi_tokens = ureg_finalize(ureg);
+    if (!tgsi_tokens)
+        return NULL;
+
+    assert(((struct tgsi_header *) &tgsi_tokens[0])->HeaderSize >= 2);
+    enum pipe_shader_type shader_type = ((struct tgsi_processor *) &tgsi_tokens[1])->Processor;
+
+    int preferred_ir = screen->get_shader_param(screen, shader_type, PIPE_SHADER_CAP_PREFERRED_IR);
+    bool prefer_nir = (preferred_ir == PIPE_SHADER_IR_NIR);
+    bool use_nir = prefer_nir ||
+        ((shader_type == PIPE_SHADER_VERTEX) && nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_NIR_VS)) ||
+        ((shader_type == PIPE_SHADER_FRAGMENT) && nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_NIR_PS));
+
+    /* Allow user to override preferred IR, this is very useful for debugging */
+    if (unlikely(shader_type == PIPE_SHADER_VERTEX && nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_NO_NIR_VS)))
+        use_nir = false;
+    if (unlikely(shader_type == PIPE_SHADER_FRAGMENT && nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_NO_NIR_PS)))
+        use_nir = false;
+
+    DUMP("shader type: %s, preferred IR: %s, selected IR: %s\n",
+         shader_type == PIPE_SHADER_VERTEX ? "VS" : "PS",
+         prefer_nir ? "NIR" : "TGSI",
+         use_nir ? "NIR" : "TGSI");
+
+    if (use_nir) {
+        nine_pipe_nir_shader_state_from_tgsi(&state, tgsi_tokens, screen);
+    } else {
+        pipe_shader_state_from_tgsi(&state, tgsi_tokens);
+    }
+
+    assert(state.tokens || state.ir.nir);
+
+    if (so)
+        state.stream_output = *so;
+
+    switch (shader_type) {
+    case PIPE_SHADER_VERTEX:
+        return pipe->create_vs_state(pipe, &state);
+    case PIPE_SHADER_FRAGMENT:
+        return pipe->create_fs_state(pipe, &state);
+    default:
+        unreachable("unsupported shader type");
+    }
+}
+
+
+void *
+nine_create_shader_with_so_and_destroy(struct ureg_program                   *p,
+                                       struct pipe_context                *pipe,
+                                       const struct pipe_stream_output_info *so)
+{
+    void *result = nine_ureg_create_shader(p, pipe, so);
+    ureg_destroy(p);
+    return result;
+}
+
 HRESULT
 nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info, struct pipe_context *pipe)
 {
@@ -3984,7 +4102,7 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info,
     if (info->process_vertices)
         ureg_DECL_constant2D(tx->ureg, 0, 2, 4); /* Viewport data */
 
-    if (debug_get_bool_option("NINE_TGSI_DUMP", FALSE)) {
+    if (unlikely(nine_shader_get_debug_flag(NINE_SHADER_DEBUG_OPTION_DUMP_TGSI))) {
         const struct tgsi_token *toks = ureg_get_tokens(tx->ureg, NULL);
         tgsi_dump(toks, 0);
         ureg_free_tokens(toks);
@@ -3995,9 +4113,9 @@ nine_translate_shader(struct NineDevice9 *device, struct nine_shader_info *info,
                                                     tx->output_info,
                                                     tx->num_outputs,
                                                     &(info->so));
-        info->cso = ureg_create_shader_with_so_and_destroy(tx->ureg, pipe, &(info->so));
+        info->cso = nine_create_shader_with_so_and_destroy(tx->ureg, pipe, &(info->so));
     } else
-        info->cso = ureg_create_shader_and_destroy(tx->ureg, pipe);
+        info->cso = nine_create_shader_with_so_and_destroy(tx->ureg, pipe, NULL);
     if (!info->cso) {
         hr = D3DERR_DRIVERINTERNALERROR;
         FREE(info->lconstf.data);
index 65dc2efd62acf7c6d2da10cad9646e0d902ac194..5abdbe244725028c34fb1b36484653cb9713ed91 100644 (file)
@@ -33,6 +33,7 @@
 
 struct NineDevice9;
 struct NineVertexDeclaration9;
+struct ureg_program;
 
 struct nine_lconstf /* NOTE: both pointers should be FREE'd by the user */
 {
@@ -108,6 +109,11 @@ struct nine_vs_output_info
     int output_index;
 };
 
+void *
+nine_create_shader_with_so_and_destroy(struct ureg_program *p,
+                                       struct pipe_context *pipe,
+                                       const struct pipe_stream_output_info *so);
+
 HRESULT
 nine_translate_shader(struct NineDevice9 *device,
                       struct nine_shader_info *,