ilo: add functions to manage shaders
authorChia-I Wu <olv@lunarg.com>
Wed, 12 Dec 2012 21:05:01 +0000 (05:05 +0800)
committerChia-I Wu <olvaffe@gmail.com>
Fri, 26 Apr 2013 08:16:42 +0000 (16:16 +0800)
This commits add shader cache, shader state, shader variant, and etc.  It does
not add the shader compiler though.

src/gallium/drivers/ilo/Makefile.sources
src/gallium/drivers/ilo/ilo_context.h
src/gallium/drivers/ilo/ilo_shader.c [new file with mode: 0644]
src/gallium/drivers/ilo/ilo_shader.h [new file with mode: 0644]

index 8911322e9cd95d82832cb85e1dd2359f2fe393a0..b5cb5fdca9d52c219d445ffd43c1388efbee63c6 100644 (file)
@@ -8,5 +8,6 @@ C_SOURCES := \
        ilo_query.c \
        ilo_resource.c \
        ilo_screen.c \
+       ilo_shader.c \
        ilo_state.c \
        ilo_video.c
index cb2971f773070862cea9a7ad8827d04b525068cf..d1632bb1db9301ac1298b8547f78f24b4c8b22e2 100644 (file)
@@ -58,6 +58,7 @@ struct intel_winsys;
 struct intel_bo;
 struct ilo_cp;
 struct ilo_screen;
+struct ilo_shader_state;
 
 struct ilo_context {
    struct pipe_context base;
@@ -78,6 +79,22 @@ struct ilo_context {
 
    struct ilo_cp *cp;
    struct intel_bo *last_cp_bo;
+
+   struct pipe_rasterizer_state *rasterizer;
+   struct ilo_shader_state *vs;
+
+   struct pipe_framebuffer_state framebuffer;
+
+   struct {
+      struct pipe_sampler_state *samplers[ILO_MAX_SAMPLERS];
+      unsigned num_samplers;
+   } samplers[PIPE_SHADER_TYPES];
+
+   struct {
+      struct pipe_sampler_view *views[ILO_MAX_SAMPLER_VIEWS];
+      unsigned num_views;
+   } sampler_views[PIPE_SHADER_TYPES];
+
 };
 
 static inline struct ilo_context *
diff --git a/src/gallium/drivers/ilo/ilo_shader.c b/src/gallium/drivers/ilo/ilo_shader.c
new file mode 100644 (file)
index 0000000..d81ac35
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2012-2013 LunarG, Inc.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Chia-I Wu <olv@lunarg.com>
+ */
+
+#include "tgsi/tgsi_parse.h"
+#include "intel_winsys.h"
+
+#include "ilo_shader.h"
+
+/**
+ * Initialize a shader variant.
+ */
+void
+ilo_shader_variant_init(struct ilo_shader_variant *variant,
+                        const struct ilo_shader_info *info,
+                        const struct ilo_context *ilo)
+{
+   int num_views, i;
+
+   memset(variant, 0, sizeof(*variant));
+
+   switch (info->type) {
+   case PIPE_SHADER_VERTEX:
+      variant->u.vs.rasterizer_discard = ilo->rasterizer->rasterizer_discard;
+      variant->u.vs.num_ucps =
+         util_last_bit(ilo->rasterizer->clip_plane_enable);
+      break;
+   case PIPE_SHADER_GEOMETRY:
+      variant->u.gs.rasterizer_discard = ilo->rasterizer->rasterizer_discard;
+      variant->u.gs.num_inputs = ilo->vs->shader->out.count;
+      for (i = 0; i < ilo->vs->shader->out.count; i++) {
+         variant->u.gs.semantic_names[i] =
+            ilo->vs->shader->out.semantic_names[i];
+         variant->u.gs.semantic_indices[i] =
+            ilo->vs->shader->out.semantic_indices[i];
+      }
+      break;
+   case PIPE_SHADER_FRAGMENT:
+      variant->u.fs.flatshade =
+         (info->has_color_interp && ilo->rasterizer->flatshade);
+      variant->u.fs.fb_height = (info->has_pos) ?
+         ilo->framebuffer.height : 1;
+      variant->u.fs.num_cbufs = ilo->framebuffer.nr_cbufs;
+      break;
+   default:
+      assert(!"unknown shader type");
+      break;
+   }
+
+   num_views = ilo->sampler_views[info->type].num_views;
+   assert(info->num_samplers <= num_views);
+
+   variant->num_sampler_views = info->num_samplers;
+   for (i = 0; i < info->num_samplers; i++) {
+      const struct pipe_sampler_view *view =
+         ilo->sampler_views[info->type].views[i];
+      const struct pipe_sampler_state *sampler =
+         ilo->samplers[info->type].samplers[i];
+
+      if (view) {
+         variant->sampler_view_swizzles[i].r = view->swizzle_r;
+         variant->sampler_view_swizzles[i].g = view->swizzle_g;
+         variant->sampler_view_swizzles[i].b = view->swizzle_b;
+         variant->sampler_view_swizzles[i].a = view->swizzle_a;
+      }
+      else if (info->shadow_samplers & (1 << i)) {
+         variant->sampler_view_swizzles[i].r = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].g = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].b = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].a = PIPE_SWIZZLE_ONE;
+      }
+      else {
+         variant->sampler_view_swizzles[i].r = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].g = PIPE_SWIZZLE_GREEN;
+         variant->sampler_view_swizzles[i].b = PIPE_SWIZZLE_BLUE;
+         variant->sampler_view_swizzles[i].a = PIPE_SWIZZLE_ALPHA;
+      }
+
+      /*
+       * When non-nearest filter and PIPE_TEX_WRAP_CLAMP wrap mode is used,
+       * the HW wrap mode is set to BRW_TEXCOORDMODE_CLAMP_BORDER, and we need
+       * to manually saturate the texture coordinates.
+       */
+      if (sampler && sampler->min_img_filter != PIPE_TEX_FILTER_NEAREST) {
+         if (sampler->wrap_s == PIPE_TEX_WRAP_CLAMP)
+            variant->saturate_tex_coords[0] |= 1 << i;
+         if (sampler->wrap_t == PIPE_TEX_WRAP_CLAMP)
+            variant->saturate_tex_coords[1] |= 1 << i;
+         if (sampler->wrap_r == PIPE_TEX_WRAP_CLAMP)
+            variant->saturate_tex_coords[2] |= 1 << i;
+      }
+   }
+}
+
+/**
+ * Guess the shader variant, knowing that the context may still change.
+ */
+static void
+ilo_shader_variant_guess(struct ilo_shader_variant *variant,
+                         const struct ilo_shader_info *info,
+                         const struct ilo_context *ilo)
+{
+   int i;
+
+   memset(variant, 0, sizeof(*variant));
+
+   switch (info->type) {
+   case PIPE_SHADER_VERTEX:
+      break;
+   case PIPE_SHADER_GEOMETRY:
+      break;
+   case PIPE_SHADER_FRAGMENT:
+      variant->u.fs.flatshade = false;
+      variant->u.fs.fb_height = (info->has_pos) ?
+         ilo->framebuffer.height : 1;
+      variant->u.fs.num_cbufs = 1;
+      break;
+   default:
+      assert(!"unknown shader type");
+      break;
+   }
+
+   variant->num_sampler_views = info->num_samplers;
+   for (i = 0; i < info->num_samplers; i++) {
+      if (info->shadow_samplers & (1 << i)) {
+         variant->sampler_view_swizzles[i].r = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].g = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].b = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].a = PIPE_SWIZZLE_ONE;
+      }
+      else {
+         variant->sampler_view_swizzles[i].r = PIPE_SWIZZLE_RED;
+         variant->sampler_view_swizzles[i].g = PIPE_SWIZZLE_GREEN;
+         variant->sampler_view_swizzles[i].b = PIPE_SWIZZLE_BLUE;
+         variant->sampler_view_swizzles[i].a = PIPE_SWIZZLE_ALPHA;
+      }
+   }
+}
+
+/**
+ * Hash a shader variant.
+ */
+static unsigned int
+ilo_shader_variant_hash(const struct ilo_shader_variant *variant)
+{
+   const int num_bytes = sizeof(*variant);
+   const unsigned char *bytes = (const unsigned char *) variant;
+   const unsigned int seed = 131;
+   unsigned int hash = 0;
+   int i;
+
+   for (i = 0; i < num_bytes; i++)
+      hash = hash * seed + bytes[i];
+
+   return hash;
+}
+
+/**
+ * Parse a TGSI instruction for the shader info.
+ */
+static void
+ilo_shader_info_parse_inst(struct ilo_shader_info *info,
+                           const struct tgsi_full_instruction *inst)
+{
+   int i;
+
+   /* look for edgeflag passthrough */
+   if (info->edgeflag_out >= 0 &&
+       inst->Instruction.Opcode == TGSI_OPCODE_MOV &&
+       inst->Dst[0].Register.File == TGSI_FILE_OUTPUT &&
+       inst->Dst[0].Register.Index == info->edgeflag_out) {
+
+      assert(inst->Src[0].Register.File == TGSI_FILE_INPUT);
+      info->edgeflag_in = inst->Src[0].Register.Index;
+   }
+
+   if (inst->Instruction.Texture) {
+      bool shadow;
+
+      switch (inst->Texture.Texture) {
+      case TGSI_TEXTURE_SHADOW1D:
+      case TGSI_TEXTURE_SHADOW2D:
+      case TGSI_TEXTURE_SHADOWRECT:
+      case TGSI_TEXTURE_SHADOW1D_ARRAY:
+      case TGSI_TEXTURE_SHADOW2D_ARRAY:
+      case TGSI_TEXTURE_SHADOWCUBE:
+      case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
+         shadow = true;
+         break;
+      default:
+         shadow = false;
+         break;
+      }
+
+      for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
+         const struct tgsi_full_src_register *src = &inst->Src[i];
+
+         if (src->Register.File == TGSI_FILE_SAMPLER) {
+            const int idx = src->Register.Index;
+
+            if (idx >= info->num_samplers)
+               info->num_samplers = idx + 1;
+
+            if (shadow)
+               info->shadow_samplers |= 1 << idx;
+         }
+      }
+   }
+}
+
+/**
+ * Parse a TGSI property for the shader info.
+ */
+static void
+ilo_shader_info_parse_prop(struct ilo_shader_info *info,
+                           const struct tgsi_full_property *prop)
+{
+   switch (prop->Property.PropertyName) {
+   case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
+      info->fs_color0_writes_all_cbufs = prop->u[0].Data;
+      break;
+   default:
+      break;
+   }
+}
+
+/**
+ * Parse a TGSI declaration for the shader info.
+ */
+static void
+ilo_shader_info_parse_decl(struct ilo_shader_info *info,
+                           const struct tgsi_full_declaration *decl)
+{
+   switch (decl->Declaration.File) {
+   case TGSI_FILE_INPUT:
+      if (decl->Declaration.Interpolate &&
+          decl->Interp.Interpolate == TGSI_INTERPOLATE_COLOR)
+         info->has_color_interp = true;
+      if (decl->Declaration.Semantic &&
+          decl->Semantic.Name == TGSI_SEMANTIC_POSITION)
+         info->has_pos = true;
+      break;
+   case TGSI_FILE_OUTPUT:
+      if (decl->Declaration.Semantic &&
+          decl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG)
+         info->edgeflag_out = decl->Range.First;
+      break;
+   case TGSI_FILE_SYSTEM_VALUE:
+      if (decl->Declaration.Semantic &&
+          decl->Semantic.Name == TGSI_SEMANTIC_INSTANCEID)
+         info->has_instanceid = true;
+      if (decl->Declaration.Semantic &&
+          decl->Semantic.Name == TGSI_SEMANTIC_VERTEXID)
+         info->has_vertexid = true;
+      break;
+   default:
+      break;
+   }
+}
+
+static void
+ilo_shader_info_parse_tokens(struct ilo_shader_info *info)
+{
+   struct tgsi_parse_context parse;
+
+   info->edgeflag_in = -1;
+   info->edgeflag_out = -1;
+
+   tgsi_parse_init(&parse, info->tokens);
+   while (!tgsi_parse_end_of_tokens(&parse)) {
+      const union tgsi_full_token *token;
+
+      tgsi_parse_token(&parse);
+      token = &parse.FullToken;
+
+      switch (token->Token.Type) {
+      case TGSI_TOKEN_TYPE_DECLARATION:
+         ilo_shader_info_parse_decl(info, &token->FullDeclaration);
+         break;
+      case TGSI_TOKEN_TYPE_INSTRUCTION:
+         ilo_shader_info_parse_inst(info, &token->FullInstruction);
+         break;
+      case TGSI_TOKEN_TYPE_PROPERTY:
+         ilo_shader_info_parse_prop(info, &token->FullProperty);
+         break;
+      default:
+         break;
+      }
+   }
+   tgsi_parse_free(&parse);
+}
+
+/**
+ * Create a shader state.
+ */
+struct ilo_shader_state *
+ilo_shader_state_create(const struct ilo_context *ilo,
+                        int type, const void *templ)
+{
+   struct ilo_shader_state *state;
+   struct ilo_shader_variant variant;
+
+   state = CALLOC_STRUCT(ilo_shader_state);
+   if (!state)
+      return NULL;
+
+   state->info.type = type;
+   state->info.gen = ilo->gen;
+
+   if (type == PIPE_SHADER_COMPUTE) {
+      const struct pipe_compute_state *c =
+         (const struct pipe_compute_state *) templ;
+
+      state->info.tokens = tgsi_dup_tokens(c->prog);
+      state->info.compute.req_local_mem = c->req_local_mem;
+      state->info.compute.req_private_mem = c->req_private_mem;
+      state->info.compute.req_input_mem = c->req_input_mem;
+   }
+   else {
+      const struct pipe_shader_state *s =
+         (const struct pipe_shader_state *) templ;
+
+      state->info.tokens = tgsi_dup_tokens(s->tokens);
+      state->info.stream_output = s->stream_output;
+   }
+
+   list_inithead(&state->variants);
+
+   ilo_shader_info_parse_tokens(&state->info);
+
+   /* guess and compile now */
+   ilo_shader_variant_guess(&variant, &state->info, ilo);
+   if (!ilo_shader_state_use_variant(state, &variant)) {
+      ilo_shader_state_destroy(state);
+      return NULL;
+   }
+
+   return state;
+}
+
+/**
+ * Destroy a shader state.
+ */
+void
+ilo_shader_state_destroy(struct ilo_shader_state *state)
+{
+   struct ilo_shader *sh, *next;
+
+   LIST_FOR_EACH_ENTRY_SAFE(sh, next, &state->variants, list)
+      ilo_shader_destroy(sh);
+
+   FREE((struct tgsi_token *) state->info.tokens);
+   FREE(state);
+}
+
+/**
+ * Add a compiled shader to the shader state.
+ */
+static void
+ilo_shader_state_add_shader(struct ilo_shader_state *state,
+                            struct ilo_shader *sh)
+{
+   list_add(&sh->list, &state->variants);
+   state->num_variants++;
+   state->total_size += sh->kernel_size;
+}
+
+/**
+ * Remove a compiled shader from the shader state.
+ */
+static void
+ilo_shader_state_remove_shader(struct ilo_shader_state *state,
+                               struct ilo_shader *sh)
+{
+   list_del(&sh->list);
+   state->num_variants--;
+   state->total_size -= sh->kernel_size;
+}
+
+/**
+ * Garbage collect shader variants in the shader state.
+ */
+static void
+ilo_shader_state_gc(struct ilo_shader_state *state)
+{
+   /* activate when the variants take up more than 4KiB of space */
+   const int limit = 4 * 1024;
+   struct ilo_shader *sh, *next;
+
+   if (state->total_size < limit)
+      return;
+
+   /* remove from the tail as the most recently ones are at the head */
+   LIST_FOR_EACH_ENTRY_SAFE_REV(sh, next, &state->variants, list) {
+      ilo_shader_state_remove_shader(state, sh);
+      ilo_shader_destroy(sh);
+
+      if (state->total_size <= limit / 2)
+         break;
+   }
+}
+
+/**
+ * Search for a shader variant.
+ */
+static struct ilo_shader *
+ilo_shader_state_search_variant(struct ilo_shader_state *state,
+                                unsigned int hash,
+                                const struct ilo_shader_variant *variant)
+{
+   struct ilo_shader *sh = NULL, *tmp;
+
+   LIST_FOR_EACH_ENTRY(tmp, &state->variants, list) {
+      if (tmp->hash == hash &&
+          memcmp(&tmp->variant, variant, sizeof(*variant)) == 0) {
+         sh = tmp;
+         break;
+      }
+   }
+
+   return sh;
+}
+
+/**
+ * Add a shader variant to the shader state.
+ */
+struct ilo_shader *
+ilo_shader_state_add_variant(struct ilo_shader_state *state,
+                             const struct ilo_shader_variant *variant)
+{
+   const unsigned int hash = ilo_shader_variant_hash(variant);
+   struct ilo_shader *sh;
+
+   sh = ilo_shader_state_search_variant(state, hash, variant);
+   if (sh)
+      return sh;
+
+   ilo_shader_state_gc(state);
+
+   switch (state->info.type) {
+   case PIPE_SHADER_VERTEX:
+      sh = ilo_shader_compile_vs(state, variant);
+      break;
+   case PIPE_SHADER_FRAGMENT:
+      sh = ilo_shader_compile_fs(state, variant);
+      break;
+   case PIPE_SHADER_GEOMETRY:
+      sh = ilo_shader_compile_gs(state, variant);
+      break;
+   case PIPE_SHADER_COMPUTE:
+      sh = ilo_shader_compile_cs(state, variant);
+      break;
+   default:
+      sh = NULL;
+      break;
+   }
+   if (!sh) {
+      assert(!"failed to compile shader");
+      return NULL;
+   }
+
+   sh->variant = *variant;
+   sh->hash = hash;
+
+   ilo_shader_state_add_shader(state, sh);
+
+   return sh;
+}
+
+/**
+ * Update state->shader to point to a variant.  If the variant does not exist,
+ * it will be added first.
+ */
+bool
+ilo_shader_state_use_variant(struct ilo_shader_state *state,
+                             const struct ilo_shader_variant *variant)
+{
+   struct ilo_shader *sh;
+
+   sh = ilo_shader_state_add_variant(state, variant);
+   if (!sh)
+      return false;
+
+   /* move to head */
+   if (state->variants.next != &sh->list) {
+      list_del(&sh->list);
+      list_add(&sh->list, &state->variants);
+   }
+
+   state->shader = sh;
+
+   return true;
+}
+
+/**
+ * Reset the shader cache.
+ */
+static void
+ilo_shader_cache_reset(struct ilo_shader_cache *shc)
+{
+   if (shc->bo)
+      shc->bo->unreference(shc->bo);
+
+   shc->bo = shc->winsys->alloc_buffer(shc->winsys,
+         "shader cache", shc->size, 0);
+   shc->busy = false;
+   shc->cur = 0;
+   shc->seqno++;
+   if (!shc->seqno)
+      shc->seqno = 1;
+}
+
+/**
+ * Create a shader cache.  A shader cache is a bo holding all compiled shaders.
+ * When the bo is full, a larger bo is allocated and all cached shaders are
+ * invalidated.  This is how outdated shaders get dropped.  Active shaders
+ * will be added to the new bo when used.
+ */
+struct ilo_shader_cache *
+ilo_shader_cache_create(struct intel_winsys *winsys)
+{
+   struct ilo_shader_cache *shc;
+
+   shc = CALLOC_STRUCT(ilo_shader_cache);
+   if (!shc)
+      return NULL;
+
+   shc->winsys = winsys;
+   /* initial cache size */
+   shc->size = 4096;
+
+   ilo_shader_cache_reset(shc);
+
+   return shc;
+}
+
+/**
+ * Destroy a shader cache.
+ */
+void
+ilo_shader_cache_destroy(struct ilo_shader_cache *shc)
+{
+   if (shc->bo)
+      shc->bo->unreference(shc->bo);
+
+   FREE(shc);
+}
+
+/**
+ * Add shaders to the cache.  This may invalidate all other shaders in the
+ * cache.
+ */
+void
+ilo_shader_cache_set(struct ilo_shader_cache *shc,
+                     struct ilo_shader **shaders,
+                     int num_shaders)
+{
+   int new_cur, i;
+
+   /* calculate the space needed */
+   new_cur = shc->cur;
+   for (i = 0; i < num_shaders; i++) {
+      if (shaders[i]->cache_seqno != shc->seqno)
+         new_cur = align(new_cur, 64) + shaders[i]->kernel_size;
+   }
+
+   /* all shaders are already in the cache */
+   if (new_cur == shc->cur)
+      return;
+
+   /*
+    * From the Sandy Bridge PRM, volume 4 part 2, page 112:
+    *
+    *     "Due to prefetch of the instruction stream, the EUs may attempt to
+    *      access up to 8 instructions (128 bytes) beyond the end of the kernel
+    *      program - possibly into the next memory page.  Although these
+    *      instructions will not be executed, software must account for the
+    *      prefetch in order to avoid invalid page access faults."
+    */
+   new_cur += 128;
+
+   /*
+    * we should be able to append data without being blocked even the bo
+    * is busy...
+    */
+
+   /* reallocate when the cache is full or busy */
+   if (new_cur > shc->size || shc->busy) {
+      while (new_cur > shc->size)
+         shc->size <<= 1;
+
+      ilo_shader_cache_reset(shc);
+   }
+
+   /* upload now */
+   for (i = 0; i < num_shaders; i++) {
+      if (shaders[i]->cache_seqno != shc->seqno) {
+         /* kernels must be aligned to 64-byte */
+         shc->cur = align(shc->cur, 64);
+         shc->bo->pwrite(shc->bo, shc->cur,
+               shaders[i]->kernel_size, shaders[i]->kernel);
+
+         shaders[i]->cache_seqno = shc->seqno;
+         shaders[i]->cache_offset = shc->cur;
+
+         shc->cur += shaders[i]->kernel_size;
+      }
+   }
+}
diff --git a/src/gallium/drivers/ilo/ilo_shader.h b/src/gallium/drivers/ilo/ilo_shader.h
new file mode 100644 (file)
index 0000000..ffe5611
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2012-2013 LunarG, Inc.
+ *
+ * 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.
+ *
+ * Authors:
+ *    Chia-I Wu <olv@lunarg.com>
+ */
+
+#ifndef ILO_SHADER_H
+#define ILO_SHADER_H
+
+#include "ilo_common.h"
+#include "ilo_context.h"
+
+/* XXX The interface needs to be reworked */
+
+/**
+ * A shader variant.  It consists of non-orthogonal states of the pipe context
+ * affecting the compilation of a shader.
+ */
+struct ilo_shader_variant {
+   union {
+      struct {
+         bool rasterizer_discard;
+         int num_ucps;
+      } vs;
+
+      struct {
+         bool rasterizer_discard;
+         int num_inputs;
+         int semantic_names[PIPE_MAX_SHADER_INPUTS];
+         int semantic_indices[PIPE_MAX_SHADER_INPUTS];
+      } gs;
+
+      struct {
+         bool flatshade;
+         int fb_height;
+         int num_cbufs;
+      } fs;
+   } u;
+
+   int num_sampler_views;
+   struct {
+      unsigned r:3;
+      unsigned g:3;
+      unsigned b:3;
+      unsigned a:3;
+   } sampler_view_swizzles[ILO_MAX_SAMPLER_VIEWS];
+
+   uint32_t saturate_tex_coords[3];
+};
+
+/**
+ * A compiled shader.
+ */
+struct ilo_shader {
+   struct ilo_shader_variant variant;
+   /* hash of the shader variant for quicker lookup */
+   unsigned hash;
+
+   struct {
+      int semantic_names[PIPE_MAX_SHADER_INPUTS];
+      int semantic_indices[PIPE_MAX_SHADER_INPUTS];
+      int interp[PIPE_MAX_SHADER_INPUTS];
+      bool centroid[PIPE_MAX_SHADER_INPUTS];
+      int count;
+
+      int start_grf;
+      bool has_pos;
+      bool has_linear_interp;
+      int barycentric_interpolation_mode;
+      bool discard_adj;
+   } in;
+
+   struct {
+      int semantic_names[PIPE_MAX_SHADER_OUTPUTS];
+      int semantic_indices[PIPE_MAX_SHADER_OUTPUTS];
+      int count;
+
+      bool has_pos;
+   } out;
+
+   bool has_kill;
+   bool dispatch_16;
+
+   bool stream_output;
+   int svbi_post_inc;
+   /* for VS stream output / rasterizer discard */
+   int gs_offsets[3];
+   int gs_start_grf;
+
+   void *kernel;
+   int kernel_size;
+
+   /* what does the push constant buffer consist of? */
+   struct {
+      int clip_state_size;
+   } pcb;
+
+   struct list_head list;
+
+   uint32_t cache_seqno;
+   uint32_t cache_offset;
+};
+
+/**
+ * Information about a shader state.
+ */
+struct ilo_shader_info {
+   int type;
+   int gen;
+
+   const struct tgsi_token *tokens;
+
+   struct pipe_stream_output_info stream_output;
+   struct {
+      unsigned req_local_mem;
+      unsigned req_private_mem;
+      unsigned req_input_mem;
+   } compute;
+
+   bool has_color_interp;
+   bool has_pos;
+   bool has_vertexid;
+   bool has_instanceid;
+   bool fs_color0_writes_all_cbufs;
+
+   int edgeflag_in;
+   int edgeflag_out;
+
+   uint32_t shadow_samplers;
+   int num_samplers;
+};
+
+/**
+ * A shader state.
+ */
+struct ilo_shader_state {
+   struct ilo_shader_info info;
+
+   struct list_head variants;
+   int num_variants, total_size;
+
+   struct ilo_shader *shader;
+};
+
+struct ilo_shader_cache {
+   struct intel_winsys *winsys;
+   struct intel_bo *bo;
+   int cur, size;
+   bool busy;
+
+   /* starting from 1, incremented whenever a new bo is allocated */
+   uint32_t seqno;
+};
+
+void
+ilo_shader_variant_init(struct ilo_shader_variant *variant,
+                        const struct ilo_shader_info *info,
+                        const struct ilo_context *ilo);
+
+struct ilo_shader_state *
+ilo_shader_state_create(const struct ilo_context *ilo,
+                        int type, const void *templ);
+
+void
+ilo_shader_state_destroy(struct ilo_shader_state *state);
+
+struct ilo_shader *
+ilo_shader_state_add_variant(struct ilo_shader_state *state,
+                             const struct ilo_shader_variant *variant);
+
+bool
+ilo_shader_state_use_variant(struct ilo_shader_state *state,
+                             const struct ilo_shader_variant *variant);
+
+struct ilo_shader_cache *
+ilo_shader_cache_create(struct intel_winsys *winsys);
+
+void
+ilo_shader_cache_destroy(struct ilo_shader_cache *shc);
+
+void
+ilo_shader_cache_set(struct ilo_shader_cache *shc,
+                     struct ilo_shader **shaders,
+                     int num_shaders);
+
+static inline void
+ilo_shader_cache_mark_busy(struct ilo_shader_cache *shc)
+{
+   if (shc->cur)
+      shc->busy = true;
+}
+
+static inline struct ilo_shader *
+ilo_shader_compile_vs(const struct ilo_shader_state *state,
+                      const struct ilo_shader_variant *variant)
+{
+   return NULL;
+}
+
+static inline struct ilo_shader *
+ilo_shader_compile_gs(const struct ilo_shader_state *state,
+                      const struct ilo_shader_variant *variant)
+{
+   return NULL;
+}
+
+static inline struct ilo_shader *
+ilo_shader_compile_fs(const struct ilo_shader_state *state,
+                      const struct ilo_shader_variant *variant)
+{
+   return NULL;
+}
+
+static inline struct ilo_shader *
+ilo_shader_compile_cs(const struct ilo_shader_state *state,
+                      const struct ilo_shader_variant *variant)
+{
+   return NULL;
+}
+
+static inline void
+ilo_shader_destroy(struct ilo_shader *sh)
+{
+   FREE(sh->kernel);
+   FREE(sh);
+}
+
+#endif /* ILO_SHADER_H */