1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "dzn_private.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "spirv/nir_spirv.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "dxil_nir.h"
29bf215546Sopenharmony_ci#include "nir_to_dxil.h"
30bf215546Sopenharmony_ci#include "dxil_spirv_nir.h"
31bf215546Sopenharmony_ci#include "spirv_to_dxil.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "dxil_validator.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "vk_alloc.h"
36bf215546Sopenharmony_ci#include "vk_util.h"
37bf215546Sopenharmony_ci#include "vk_format.h"
38bf215546Sopenharmony_ci#include "vk_pipeline.h"
39bf215546Sopenharmony_ci#include "vk_pipeline_cache.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#include "util/u_debug.h"
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci#define d3d12_pipeline_state_stream_new_desc(__stream, __maxstreamsz, __id, __type, __desc) \
44bf215546Sopenharmony_ci   __type *__desc; \
45bf215546Sopenharmony_ci   do { \
46bf215546Sopenharmony_ci      struct { \
47bf215546Sopenharmony_ci         D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; \
48bf215546Sopenharmony_ci         __type desc; \
49bf215546Sopenharmony_ci      } *__wrapper; \
50bf215546Sopenharmony_ci      (__stream)->SizeInBytes = ALIGN_POT((__stream)->SizeInBytes, alignof(void *)); \
51bf215546Sopenharmony_ci      __wrapper = (void *)((uint8_t *)(__stream)->pPipelineStateSubobjectStream + (__stream)->SizeInBytes); \
52bf215546Sopenharmony_ci      (__stream)->SizeInBytes += sizeof(*__wrapper); \
53bf215546Sopenharmony_ci      assert((__stream)->SizeInBytes <= __maxstreamsz); \
54bf215546Sopenharmony_ci      __wrapper->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ ## __id; \
55bf215546Sopenharmony_ci      __desc = &__wrapper->desc; \
56bf215546Sopenharmony_ci      memset(__desc, 0, sizeof(*__desc)); \
57bf215546Sopenharmony_ci   } while (0)
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci#define d3d12_gfx_pipeline_state_stream_new_desc(__stream, __id, __type, __desc) \
60bf215546Sopenharmony_ci   d3d12_pipeline_state_stream_new_desc(__stream, MAX_GFX_PIPELINE_STATE_STREAM_SIZE, __id, __type, __desc)
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci#define d3d12_compute_pipeline_state_stream_new_desc(__stream, __id, __type, __desc) \
63bf215546Sopenharmony_ci   d3d12_pipeline_state_stream_new_desc(__stream, MAX_COMPUTE_PIPELINE_STATE_STREAM_SIZE, __id, __type, __desc)
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_cistatic bool
66bf215546Sopenharmony_cigfx_pipeline_variant_key_equal(const void *a, const void *b)
67bf215546Sopenharmony_ci{
68bf215546Sopenharmony_ci   return !memcmp(a, b, sizeof(struct dzn_graphics_pipeline_variant_key));
69bf215546Sopenharmony_ci}
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_cistatic uint32_t
72bf215546Sopenharmony_cigfx_pipeline_variant_key_hash(const void *key)
73bf215546Sopenharmony_ci{
74bf215546Sopenharmony_ci   return _mesa_hash_data(key, sizeof(struct dzn_graphics_pipeline_variant_key));
75bf215546Sopenharmony_ci}
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_cistruct dzn_cached_blob {
78bf215546Sopenharmony_ci   struct vk_pipeline_cache_object base;
79bf215546Sopenharmony_ci   uint8_t hash[SHA1_DIGEST_LENGTH];
80bf215546Sopenharmony_ci   const void *data;
81bf215546Sopenharmony_ci   size_t size;
82bf215546Sopenharmony_ci};
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_cistatic bool
85bf215546Sopenharmony_cidzn_cached_blob_serialize(struct vk_pipeline_cache_object *object,
86bf215546Sopenharmony_ci                          struct blob *blob)
87bf215546Sopenharmony_ci{
88bf215546Sopenharmony_ci   struct dzn_cached_blob *cached_blob =
89bf215546Sopenharmony_ci      container_of(object, struct dzn_cached_blob, base);
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   blob_write_bytes(blob, cached_blob->data, cached_blob->size);
92bf215546Sopenharmony_ci   return true;
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_cistatic void
96bf215546Sopenharmony_cidzn_cached_blob_destroy(struct vk_pipeline_cache_object *object)
97bf215546Sopenharmony_ci{
98bf215546Sopenharmony_ci   struct dzn_cached_blob *shader =
99bf215546Sopenharmony_ci      container_of(object, struct dzn_cached_blob, base);
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   vk_free(&shader->base.device->alloc, shader);
102bf215546Sopenharmony_ci}
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_cistatic struct vk_pipeline_cache_object *
105bf215546Sopenharmony_cidzn_cached_blob_create(struct vk_device *device,
106bf215546Sopenharmony_ci                       const void *hash,
107bf215546Sopenharmony_ci                       const void *data,
108bf215546Sopenharmony_ci                       size_t data_size);
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_cistatic struct vk_pipeline_cache_object *
111bf215546Sopenharmony_cidzn_cached_blob_deserialize(struct vk_device *device,
112bf215546Sopenharmony_ci                                   const void *key_data,
113bf215546Sopenharmony_ci                                   size_t key_size,
114bf215546Sopenharmony_ci                                   struct blob_reader *blob)
115bf215546Sopenharmony_ci{
116bf215546Sopenharmony_ci   size_t data_size = blob->end - blob->current;
117bf215546Sopenharmony_ci   assert(key_size == SHA1_DIGEST_LENGTH);
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   return dzn_cached_blob_create(device, key_data,
120bf215546Sopenharmony_ci                                 blob_read_bytes(blob, data_size),
121bf215546Sopenharmony_ci                                 data_size);
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ciconst struct vk_pipeline_cache_object_ops dzn_cached_blob_ops = {
125bf215546Sopenharmony_ci   .serialize = dzn_cached_blob_serialize,
126bf215546Sopenharmony_ci   .deserialize = dzn_cached_blob_deserialize,
127bf215546Sopenharmony_ci   .destroy = dzn_cached_blob_destroy,
128bf215546Sopenharmony_ci};
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_cistatic struct vk_pipeline_cache_object *
132bf215546Sopenharmony_cidzn_cached_blob_create(struct vk_device *device,
133bf215546Sopenharmony_ci                       const void *hash,
134bf215546Sopenharmony_ci                       const void *data,
135bf215546Sopenharmony_ci                       size_t data_size)
136bf215546Sopenharmony_ci{
137bf215546Sopenharmony_ci   VK_MULTIALLOC(ma);
138bf215546Sopenharmony_ci   VK_MULTIALLOC_DECL(&ma, struct dzn_cached_blob, blob, 1);
139bf215546Sopenharmony_ci   VK_MULTIALLOC_DECL(&ma, uint8_t, copy, data_size);
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   if (!vk_multialloc_alloc(&ma, &device->alloc,
142bf215546Sopenharmony_ci                            VK_SYSTEM_ALLOCATION_SCOPE_DEVICE))
143bf215546Sopenharmony_ci      return NULL;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   memcpy(blob->hash, hash, sizeof(blob->hash));
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   vk_pipeline_cache_object_init(device, &blob->base,
148bf215546Sopenharmony_ci                                 &dzn_cached_blob_ops,
149bf215546Sopenharmony_ci                                 blob->hash, sizeof(blob->hash));
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci   if (data)
152bf215546Sopenharmony_ci      memcpy(copy, data, data_size);
153bf215546Sopenharmony_ci   blob->data = copy;
154bf215546Sopenharmony_ci   blob->size = data_size;
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   return &blob->base;
157bf215546Sopenharmony_ci}
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_cistatic VkResult
160bf215546Sopenharmony_cidzn_graphics_pipeline_prepare_for_variants(struct dzn_device *device,
161bf215546Sopenharmony_ci                                           struct dzn_graphics_pipeline *pipeline)
162bf215546Sopenharmony_ci{
163bf215546Sopenharmony_ci   if (pipeline->variants)
164bf215546Sopenharmony_ci      return VK_SUCCESS;
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   pipeline->variants =
167bf215546Sopenharmony_ci      _mesa_hash_table_create(NULL,
168bf215546Sopenharmony_ci                              gfx_pipeline_variant_key_hash,
169bf215546Sopenharmony_ci                              gfx_pipeline_variant_key_equal);
170bf215546Sopenharmony_ci   if (!pipeline->variants)
171bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   return VK_SUCCESS;
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_cistatic dxil_spirv_shader_stage
177bf215546Sopenharmony_cito_dxil_shader_stage(VkShaderStageFlagBits in)
178bf215546Sopenharmony_ci{
179bf215546Sopenharmony_ci   switch (in) {
180bf215546Sopenharmony_ci   case VK_SHADER_STAGE_VERTEX_BIT: return DXIL_SPIRV_SHADER_VERTEX;
181bf215546Sopenharmony_ci   case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return DXIL_SPIRV_SHADER_TESS_CTRL;
182bf215546Sopenharmony_ci   case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return DXIL_SPIRV_SHADER_TESS_EVAL;
183bf215546Sopenharmony_ci   case VK_SHADER_STAGE_GEOMETRY_BIT: return DXIL_SPIRV_SHADER_GEOMETRY;
184bf215546Sopenharmony_ci   case VK_SHADER_STAGE_FRAGMENT_BIT: return DXIL_SPIRV_SHADER_FRAGMENT;
185bf215546Sopenharmony_ci   case VK_SHADER_STAGE_COMPUTE_BIT: return DXIL_SPIRV_SHADER_COMPUTE;
186bf215546Sopenharmony_ci   default: unreachable("Unsupported stage");
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci}
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_cistatic VkResult
191bf215546Sopenharmony_cidzn_pipeline_get_nir_shader(struct dzn_device *device,
192bf215546Sopenharmony_ci                            const struct dzn_pipeline_layout *layout,
193bf215546Sopenharmony_ci                            struct vk_pipeline_cache *cache,
194bf215546Sopenharmony_ci                            const uint8_t *hash,
195bf215546Sopenharmony_ci                            const VkPipelineShaderStageCreateInfo *stage_info,
196bf215546Sopenharmony_ci                            gl_shader_stage stage,
197bf215546Sopenharmony_ci                            enum dxil_spirv_yz_flip_mode yz_flip_mode,
198bf215546Sopenharmony_ci                            uint16_t y_flip_mask, uint16_t z_flip_mask,
199bf215546Sopenharmony_ci                            bool force_sample_rate_shading,
200bf215546Sopenharmony_ci                            enum pipe_format *vi_conversions,
201bf215546Sopenharmony_ci                            const nir_shader_compiler_options *nir_opts,
202bf215546Sopenharmony_ci                            nir_shader **nir)
203bf215546Sopenharmony_ci{
204bf215546Sopenharmony_ci   if (cache) {
205bf215546Sopenharmony_ci      *nir = vk_pipeline_cache_lookup_nir(cache, hash, SHA1_DIGEST_LENGTH,
206bf215546Sopenharmony_ci                                          nir_opts, NULL, NULL);
207bf215546Sopenharmony_ci       if (*nir)
208bf215546Sopenharmony_ci          return VK_SUCCESS;
209bf215546Sopenharmony_ci   }
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   VK_FROM_HANDLE(vk_shader_module, module, stage_info->module);
212bf215546Sopenharmony_ci   struct spirv_to_nir_options spirv_opts = {
213bf215546Sopenharmony_ci      .caps = {
214bf215546Sopenharmony_ci         .draw_parameters = true,
215bf215546Sopenharmony_ci      },
216bf215546Sopenharmony_ci      .ubo_addr_format = nir_address_format_32bit_index_offset,
217bf215546Sopenharmony_ci      .ssbo_addr_format = nir_address_format_32bit_index_offset,
218bf215546Sopenharmony_ci      .shared_addr_format = nir_address_format_32bit_offset_as_64bit,
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci      /* use_deref_buffer_array_length + nir_lower_explicit_io force
221bf215546Sopenharmony_ci       * get_ssbo_size to take in the return from load_vulkan_descriptor
222bf215546Sopenharmony_ci       * instead of vulkan_resource_index. This makes it much easier to
223bf215546Sopenharmony_ci       * get the DXIL handle for the SSBO.
224bf215546Sopenharmony_ci       */
225bf215546Sopenharmony_ci      .use_deref_buffer_array_length = true
226bf215546Sopenharmony_ci   };
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   VkResult result =
229bf215546Sopenharmony_ci      vk_shader_module_to_nir(&device->vk, module, stage,
230bf215546Sopenharmony_ci                              stage_info->pName, stage_info->pSpecializationInfo,
231bf215546Sopenharmony_ci                              &spirv_opts, nir_opts, NULL, nir);
232bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
233bf215546Sopenharmony_ci      return result;
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   struct dxil_spirv_runtime_conf conf = {
236bf215546Sopenharmony_ci      .runtime_data_cbv = {
237bf215546Sopenharmony_ci         .register_space = DZN_REGISTER_SPACE_SYSVALS,
238bf215546Sopenharmony_ci         .base_shader_register = 0,
239bf215546Sopenharmony_ci      },
240bf215546Sopenharmony_ci      .push_constant_cbv = {
241bf215546Sopenharmony_ci         .register_space = DZN_REGISTER_SPACE_PUSH_CONSTANT,
242bf215546Sopenharmony_ci         .base_shader_register = 0,
243bf215546Sopenharmony_ci      },
244bf215546Sopenharmony_ci      .zero_based_vertex_instance_id = false,
245bf215546Sopenharmony_ci      .yz_flip = {
246bf215546Sopenharmony_ci         .mode = yz_flip_mode,
247bf215546Sopenharmony_ci         .y_mask = y_flip_mask,
248bf215546Sopenharmony_ci         .z_mask = z_flip_mask,
249bf215546Sopenharmony_ci      },
250bf215546Sopenharmony_ci      .read_only_images_as_srvs = true,
251bf215546Sopenharmony_ci      .force_sample_rate_shading = force_sample_rate_shading,
252bf215546Sopenharmony_ci   };
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   bool requires_runtime_data;
255bf215546Sopenharmony_ci   dxil_spirv_nir_passes(*nir, &conf, &requires_runtime_data);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   if (stage == MESA_SHADER_VERTEX) {
258bf215546Sopenharmony_ci      bool needs_conv = false;
259bf215546Sopenharmony_ci      for (uint32_t i = 0; i < MAX_VERTEX_GENERIC_ATTRIBS; i++) {
260bf215546Sopenharmony_ci         if (vi_conversions[i] != PIPE_FORMAT_NONE)
261bf215546Sopenharmony_ci            needs_conv = true;
262bf215546Sopenharmony_ci      }
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci      if (needs_conv)
265bf215546Sopenharmony_ci         NIR_PASS_V(*nir, dxil_nir_lower_vs_vertex_conversion, vi_conversions);
266bf215546Sopenharmony_ci   }
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci   if (cache)
269bf215546Sopenharmony_ci      vk_pipeline_cache_add_nir(cache, hash, SHA1_DIGEST_LENGTH, *nir);
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   return VK_SUCCESS;
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_cistatic bool
275bf215546Sopenharmony_ciadjust_resource_index_binding(struct nir_builder *builder, nir_instr *instr,
276bf215546Sopenharmony_ci                              void *cb_data)
277bf215546Sopenharmony_ci{
278bf215546Sopenharmony_ci   if (instr->type != nir_instr_type_intrinsic)
279bf215546Sopenharmony_ci      return false;
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   if (intrin->intrinsic != nir_intrinsic_vulkan_resource_index)
284bf215546Sopenharmony_ci      return false;
285bf215546Sopenharmony_ci
286bf215546Sopenharmony_ci   const struct dzn_pipeline_layout *layout = cb_data;
287bf215546Sopenharmony_ci   unsigned set = nir_intrinsic_desc_set(intrin);
288bf215546Sopenharmony_ci   unsigned binding = nir_intrinsic_binding(intrin);
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_ci   if (set >= layout->set_count ||
291bf215546Sopenharmony_ci       binding >= layout->binding_translation[set].binding_count)
292bf215546Sopenharmony_ci      return false;
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   binding = layout->binding_translation[set].base_reg[binding];
295bf215546Sopenharmony_ci   nir_intrinsic_set_binding(intrin, binding);
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   return true;
298bf215546Sopenharmony_ci}
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_cistatic bool
301bf215546Sopenharmony_ciadjust_var_bindings(nir_shader *shader,
302bf215546Sopenharmony_ci                    const struct dzn_pipeline_layout *layout,
303bf215546Sopenharmony_ci                    uint8_t *bindings_hash)
304bf215546Sopenharmony_ci{
305bf215546Sopenharmony_ci   uint32_t modes = nir_var_image | nir_var_uniform | nir_var_mem_ubo | nir_var_mem_ssbo;
306bf215546Sopenharmony_ci   struct mesa_sha1 bindings_hash_ctx;
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   if (bindings_hash)
309bf215546Sopenharmony_ci      _mesa_sha1_init(&bindings_hash_ctx);
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   nir_foreach_variable_with_modes(var, shader, modes) {
312bf215546Sopenharmony_ci      if (var->data.mode == nir_var_uniform) {
313bf215546Sopenharmony_ci         const struct glsl_type *type = glsl_without_array(var->type);
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci         if (!glsl_type_is_sampler(type) && !glsl_type_is_texture(type))
316bf215546Sopenharmony_ci            continue;
317bf215546Sopenharmony_ci      }
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci      unsigned s = var->data.descriptor_set, b = var->data.binding;
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci      if (s >= layout->set_count)
322bf215546Sopenharmony_ci         continue;
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci      assert(b < layout->binding_translation[s].binding_count);
325bf215546Sopenharmony_ci      var->data.binding = layout->binding_translation[s].base_reg[b];
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci      if (bindings_hash) {
328bf215546Sopenharmony_ci         _mesa_sha1_update(&bindings_hash_ctx, &s, sizeof(s));
329bf215546Sopenharmony_ci         _mesa_sha1_update(&bindings_hash_ctx, &b, sizeof(b));
330bf215546Sopenharmony_ci         _mesa_sha1_update(&bindings_hash_ctx, &var->data.binding, sizeof(var->data.binding));
331bf215546Sopenharmony_ci      }
332bf215546Sopenharmony_ci   }
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   if (bindings_hash)
335bf215546Sopenharmony_ci      _mesa_sha1_final(&bindings_hash_ctx, bindings_hash);
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci   return nir_shader_instructions_pass(shader, adjust_resource_index_binding,
338bf215546Sopenharmony_ci                                       nir_metadata_all, (void *)layout);
339bf215546Sopenharmony_ci}
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_cistatic VkResult
342bf215546Sopenharmony_cidzn_pipeline_compile_shader(struct dzn_device *device,
343bf215546Sopenharmony_ci                            nir_shader *nir,
344bf215546Sopenharmony_ci                            D3D12_SHADER_BYTECODE *slot)
345bf215546Sopenharmony_ci{
346bf215546Sopenharmony_ci   struct dzn_instance *instance =
347bf215546Sopenharmony_ci      container_of(device->vk.physical->instance, struct dzn_instance, vk);
348bf215546Sopenharmony_ci   struct nir_to_dxil_options opts = {
349bf215546Sopenharmony_ci      .environment = DXIL_ENVIRONMENT_VULKAN,
350bf215546Sopenharmony_ci      .shader_model_max = SHADER_MODEL_6_2,
351bf215546Sopenharmony_ci#ifdef _WIN32
352bf215546Sopenharmony_ci      .validator_version_max = dxil_get_validator_version(instance->dxil_validator),
353bf215546Sopenharmony_ci#endif
354bf215546Sopenharmony_ci   };
355bf215546Sopenharmony_ci   struct blob dxil_blob;
356bf215546Sopenharmony_ci   VkResult result = VK_SUCCESS;
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   if (instance->debug_flags & DZN_DEBUG_NIR)
359bf215546Sopenharmony_ci      nir_print_shader(nir, stderr);
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci   if (nir_to_dxil(nir, &opts, &dxil_blob)) {
362bf215546Sopenharmony_ci      blob_finish_get_buffer(&dxil_blob, (void **)&slot->pShaderBytecode,
363bf215546Sopenharmony_ci                             (size_t *)&slot->BytecodeLength);
364bf215546Sopenharmony_ci   } else {
365bf215546Sopenharmony_ci      result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
366bf215546Sopenharmony_ci   }
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   if (dxil_blob.allocated)
369bf215546Sopenharmony_ci      blob_finish(&dxil_blob);
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
372bf215546Sopenharmony_ci      return result;
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci#ifdef _WIN32
375bf215546Sopenharmony_ci   char *err;
376bf215546Sopenharmony_ci   bool res = dxil_validate_module(instance->dxil_validator,
377bf215546Sopenharmony_ci                                   (void *)slot->pShaderBytecode,
378bf215546Sopenharmony_ci                                   slot->BytecodeLength, &err);
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_ci   if (instance->debug_flags & DZN_DEBUG_DXIL) {
381bf215546Sopenharmony_ci      char *disasm = dxil_disasm_module(instance->dxil_validator,
382bf215546Sopenharmony_ci                                        (void *)slot->pShaderBytecode,
383bf215546Sopenharmony_ci                                        slot->BytecodeLength);
384bf215546Sopenharmony_ci      if (disasm) {
385bf215546Sopenharmony_ci         fprintf(stderr,
386bf215546Sopenharmony_ci                 "== BEGIN SHADER ============================================\n"
387bf215546Sopenharmony_ci                 "%s\n"
388bf215546Sopenharmony_ci                 "== END SHADER ==============================================\n",
389bf215546Sopenharmony_ci                  disasm);
390bf215546Sopenharmony_ci         ralloc_free(disasm);
391bf215546Sopenharmony_ci      }
392bf215546Sopenharmony_ci   }
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ci   if (!res) {
395bf215546Sopenharmony_ci      if (err) {
396bf215546Sopenharmony_ci         fprintf(stderr,
397bf215546Sopenharmony_ci               "== VALIDATION ERROR =============================================\n"
398bf215546Sopenharmony_ci               "%s\n"
399bf215546Sopenharmony_ci               "== END ==========================================================\n",
400bf215546Sopenharmony_ci               err);
401bf215546Sopenharmony_ci         ralloc_free(err);
402bf215546Sopenharmony_ci      }
403bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
404bf215546Sopenharmony_ci   }
405bf215546Sopenharmony_ci#endif
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci   return VK_SUCCESS;
408bf215546Sopenharmony_ci}
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_cistatic D3D12_SHADER_BYTECODE *
411bf215546Sopenharmony_cidzn_pipeline_get_gfx_shader_slot(D3D12_PIPELINE_STATE_STREAM_DESC *stream,
412bf215546Sopenharmony_ci                                 gl_shader_stage in)
413bf215546Sopenharmony_ci{
414bf215546Sopenharmony_ci   switch (in) {
415bf215546Sopenharmony_ci   case MESA_SHADER_VERTEX: {
416bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream, VS, D3D12_SHADER_BYTECODE, desc);
417bf215546Sopenharmony_ci      return desc;
418bf215546Sopenharmony_ci   }
419bf215546Sopenharmony_ci   case MESA_SHADER_TESS_CTRL: {
420bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream, DS, D3D12_SHADER_BYTECODE, desc);
421bf215546Sopenharmony_ci      return desc;
422bf215546Sopenharmony_ci   }
423bf215546Sopenharmony_ci   case MESA_SHADER_TESS_EVAL: {
424bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream, HS, D3D12_SHADER_BYTECODE, desc);
425bf215546Sopenharmony_ci      return desc;
426bf215546Sopenharmony_ci   }
427bf215546Sopenharmony_ci   case MESA_SHADER_GEOMETRY: {
428bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream, GS, D3D12_SHADER_BYTECODE, desc);
429bf215546Sopenharmony_ci      return desc;
430bf215546Sopenharmony_ci   }
431bf215546Sopenharmony_ci   case MESA_SHADER_FRAGMENT: {
432bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream, PS, D3D12_SHADER_BYTECODE, desc);
433bf215546Sopenharmony_ci      return desc;
434bf215546Sopenharmony_ci   }
435bf215546Sopenharmony_ci   default: unreachable("Unsupported stage");
436bf215546Sopenharmony_ci   }
437bf215546Sopenharmony_ci}
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_cistruct dzn_cached_dxil_shader_header {
440bf215546Sopenharmony_ci   gl_shader_stage stage;
441bf215546Sopenharmony_ci   size_t size;
442bf215546Sopenharmony_ci   uint8_t data[0];
443bf215546Sopenharmony_ci};
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_cistatic VkResult
446bf215546Sopenharmony_cidzn_pipeline_cache_lookup_dxil_shader(struct vk_pipeline_cache *cache,
447bf215546Sopenharmony_ci                                      const uint8_t *dxil_hash,
448bf215546Sopenharmony_ci                                      gl_shader_stage *stage,
449bf215546Sopenharmony_ci                                      D3D12_SHADER_BYTECODE *bc)
450bf215546Sopenharmony_ci{
451bf215546Sopenharmony_ci   *stage = MESA_SHADER_NONE;
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   if (!cache)
454bf215546Sopenharmony_ci      return VK_SUCCESS;
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   struct vk_pipeline_cache_object *cache_obj = NULL;
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci   cache_obj =
459bf215546Sopenharmony_ci      vk_pipeline_cache_lookup_object(cache, dxil_hash, SHA1_DIGEST_LENGTH,
460bf215546Sopenharmony_ci                                      &dzn_cached_blob_ops,
461bf215546Sopenharmony_ci                                      NULL);
462bf215546Sopenharmony_ci   if (!cache_obj)
463bf215546Sopenharmony_ci      return VK_SUCCESS;
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   struct dzn_cached_blob *cached_blob =
466bf215546Sopenharmony_ci      container_of(cache_obj, struct dzn_cached_blob, base);
467bf215546Sopenharmony_ci   VkResult ret = VK_SUCCESS;
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci   assert(sizeof(struct dzn_cached_dxil_shader_header) <= cached_blob->size);
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci   const struct dzn_cached_dxil_shader_header *info =
472bf215546Sopenharmony_ci      (struct dzn_cached_dxil_shader_header *)(cached_blob->data);
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   assert(sizeof(struct dzn_cached_dxil_shader_header) + info->size <= cached_blob->size);
475bf215546Sopenharmony_ci   assert(info->stage > MESA_SHADER_NONE && info->stage < MESA_VULKAN_SHADER_STAGES);
476bf215546Sopenharmony_ci   assert(info->size > 0);
477bf215546Sopenharmony_ci
478bf215546Sopenharmony_ci   void *code = malloc(info->size);
479bf215546Sopenharmony_ci   if (!code) {
480bf215546Sopenharmony_ci      ret = vk_error(cache->base.device, VK_ERROR_OUT_OF_HOST_MEMORY);
481bf215546Sopenharmony_ci      goto out;
482bf215546Sopenharmony_ci   }
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci   memcpy(code, info->data, info->size);
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci   bc->pShaderBytecode = code;
487bf215546Sopenharmony_ci   bc->BytecodeLength = info->size;
488bf215546Sopenharmony_ci   *stage = info->stage;
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ciout:
491bf215546Sopenharmony_ci   vk_pipeline_cache_object_unref(cache_obj);
492bf215546Sopenharmony_ci   return ret;
493bf215546Sopenharmony_ci}
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_cistatic void
496bf215546Sopenharmony_cidzn_pipeline_cache_add_dxil_shader(struct vk_pipeline_cache *cache,
497bf215546Sopenharmony_ci                                   const uint8_t *dxil_hash,
498bf215546Sopenharmony_ci                                   gl_shader_stage stage,
499bf215546Sopenharmony_ci                                   const D3D12_SHADER_BYTECODE *bc)
500bf215546Sopenharmony_ci{
501bf215546Sopenharmony_ci   size_t size = sizeof(struct dzn_cached_dxil_shader_header) +
502bf215546Sopenharmony_ci                 bc->BytecodeLength;
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_ci   struct vk_pipeline_cache_object *cache_obj =
505bf215546Sopenharmony_ci      dzn_cached_blob_create(cache->base.device, dxil_hash, NULL, size);
506bf215546Sopenharmony_ci   if (!cache_obj)
507bf215546Sopenharmony_ci      return;
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci   struct dzn_cached_blob *cached_blob =
510bf215546Sopenharmony_ci      container_of(cache_obj, struct dzn_cached_blob, base);
511bf215546Sopenharmony_ci   struct dzn_cached_dxil_shader_header *info =
512bf215546Sopenharmony_ci      (struct dzn_cached_dxil_shader_header *)(cached_blob->data);
513bf215546Sopenharmony_ci   info->stage = stage;
514bf215546Sopenharmony_ci   info->size = bc->BytecodeLength;
515bf215546Sopenharmony_ci   memcpy(info->data, bc->pShaderBytecode, bc->BytecodeLength);
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   cache_obj = vk_pipeline_cache_add_object(cache, cache_obj);
518bf215546Sopenharmony_ci   vk_pipeline_cache_object_unref(cache_obj);
519bf215546Sopenharmony_ci}
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_cistruct dzn_cached_gfx_pipeline_header {
522bf215546Sopenharmony_ci   uint32_t stages;
523bf215546Sopenharmony_ci   uint32_t input_count;
524bf215546Sopenharmony_ci};
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_cistatic VkResult
527bf215546Sopenharmony_cidzn_pipeline_cache_lookup_gfx_pipeline(struct dzn_graphics_pipeline *pipeline,
528bf215546Sopenharmony_ci                                       struct vk_pipeline_cache *cache,
529bf215546Sopenharmony_ci                                       const uint8_t *pipeline_hash,
530bf215546Sopenharmony_ci                                       bool *cache_hit)
531bf215546Sopenharmony_ci{
532bf215546Sopenharmony_ci   *cache_hit = false;
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci   if (!cache)
535bf215546Sopenharmony_ci      return VK_SUCCESS;
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   struct vk_pipeline_cache_object *cache_obj = NULL;
538bf215546Sopenharmony_ci
539bf215546Sopenharmony_ci   cache_obj =
540bf215546Sopenharmony_ci      vk_pipeline_cache_lookup_object(cache, pipeline_hash, SHA1_DIGEST_LENGTH,
541bf215546Sopenharmony_ci                                      &dzn_cached_blob_ops,
542bf215546Sopenharmony_ci                                      NULL);
543bf215546Sopenharmony_ci   if (!cache_obj)
544bf215546Sopenharmony_ci      return VK_SUCCESS;
545bf215546Sopenharmony_ci
546bf215546Sopenharmony_ci   struct dzn_cached_blob *cached_blob =
547bf215546Sopenharmony_ci      container_of(cache_obj, struct dzn_cached_blob, base);
548bf215546Sopenharmony_ci   D3D12_PIPELINE_STATE_STREAM_DESC *stream_desc =
549bf215546Sopenharmony_ci      &pipeline->templates.stream_desc;
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_ci   const struct dzn_cached_gfx_pipeline_header *info =
552bf215546Sopenharmony_ci      (const struct dzn_cached_gfx_pipeline_header *)(cached_blob->data);
553bf215546Sopenharmony_ci   size_t offset = sizeof(*info);
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci   assert(cached_blob->size >= sizeof(*info));
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci   if (info->input_count > 0) {
558bf215546Sopenharmony_ci      offset = ALIGN_POT(offset, alignof(D3D12_INPUT_LAYOUT_DESC));
559bf215546Sopenharmony_ci      const D3D12_INPUT_ELEMENT_DESC *inputs =
560bf215546Sopenharmony_ci         (const D3D12_INPUT_ELEMENT_DESC *)((uint8_t *)cached_blob->data + offset);
561bf215546Sopenharmony_ci
562bf215546Sopenharmony_ci      assert(cached_blob->size >= offset + sizeof(*inputs) * info->input_count);
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_ci      memcpy(pipeline->templates.inputs, inputs,
565bf215546Sopenharmony_ci             sizeof(*inputs) * info->input_count);
566bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream_desc, INPUT_LAYOUT, D3D12_INPUT_LAYOUT_DESC, desc);
567bf215546Sopenharmony_ci      desc->pInputElementDescs = pipeline->templates.inputs;
568bf215546Sopenharmony_ci      desc->NumElements = info->input_count;
569bf215546Sopenharmony_ci      offset += sizeof(*inputs) * info->input_count;
570bf215546Sopenharmony_ci   }
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci   assert(cached_blob->size == offset + util_bitcount(info->stages) * SHA1_DIGEST_LENGTH);
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci   u_foreach_bit(s, info->stages) {
575bf215546Sopenharmony_ci      uint8_t *dxil_hash = (uint8_t *)cached_blob->data + offset;
576bf215546Sopenharmony_ci      gl_shader_stage stage;
577bf215546Sopenharmony_ci
578bf215546Sopenharmony_ci      D3D12_SHADER_BYTECODE *slot =
579bf215546Sopenharmony_ci         dzn_pipeline_get_gfx_shader_slot(stream_desc, s);
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_ci      VkResult ret =
582bf215546Sopenharmony_ci         dzn_pipeline_cache_lookup_dxil_shader(cache, dxil_hash, &stage, slot);
583bf215546Sopenharmony_ci      if (ret != VK_SUCCESS)
584bf215546Sopenharmony_ci         return ret;
585bf215546Sopenharmony_ci
586bf215546Sopenharmony_ci      assert(stage == s);
587bf215546Sopenharmony_ci      offset += SHA1_DIGEST_LENGTH;
588bf215546Sopenharmony_ci   }
589bf215546Sopenharmony_ci
590bf215546Sopenharmony_ci   *cache_hit = true;
591bf215546Sopenharmony_ci
592bf215546Sopenharmony_ci   vk_pipeline_cache_object_unref(cache_obj);
593bf215546Sopenharmony_ci   return VK_SUCCESS;
594bf215546Sopenharmony_ci}
595bf215546Sopenharmony_ci
596bf215546Sopenharmony_cistatic void
597bf215546Sopenharmony_cidzn_pipeline_cache_add_gfx_pipeline(struct dzn_graphics_pipeline *pipeline,
598bf215546Sopenharmony_ci                                    struct vk_pipeline_cache *cache,
599bf215546Sopenharmony_ci                                    uint32_t vertex_input_count,
600bf215546Sopenharmony_ci                                    const uint8_t *pipeline_hash,
601bf215546Sopenharmony_ci                                    const uint8_t *const *dxil_hashes)
602bf215546Sopenharmony_ci{
603bf215546Sopenharmony_ci   size_t offset =
604bf215546Sopenharmony_ci      ALIGN_POT(sizeof(struct dzn_cached_gfx_pipeline_header), alignof(D3D12_INPUT_ELEMENT_DESC)) +
605bf215546Sopenharmony_ci      (sizeof(D3D12_INPUT_ELEMENT_DESC) * vertex_input_count);
606bf215546Sopenharmony_ci   uint32_t stages = 0;
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   for (uint32_t i = 0; i < MESA_VULKAN_SHADER_STAGES; i++) {
609bf215546Sopenharmony_ci      if (pipeline->templates.shaders[i].bc) {
610bf215546Sopenharmony_ci         stages |= BITFIELD_BIT(i);
611bf215546Sopenharmony_ci         offset += SHA1_DIGEST_LENGTH;
612bf215546Sopenharmony_ci      }
613bf215546Sopenharmony_ci   }
614bf215546Sopenharmony_ci
615bf215546Sopenharmony_ci   struct vk_pipeline_cache_object *cache_obj =
616bf215546Sopenharmony_ci      dzn_cached_blob_create(cache->base.device, pipeline_hash, NULL, offset);
617bf215546Sopenharmony_ci   if (!cache_obj)
618bf215546Sopenharmony_ci      return;
619bf215546Sopenharmony_ci
620bf215546Sopenharmony_ci   struct dzn_cached_blob *cached_blob =
621bf215546Sopenharmony_ci      container_of(cache_obj, struct dzn_cached_blob, base);
622bf215546Sopenharmony_ci
623bf215546Sopenharmony_ci   offset = 0;
624bf215546Sopenharmony_ci   struct dzn_cached_gfx_pipeline_header *info =
625bf215546Sopenharmony_ci      (struct dzn_cached_gfx_pipeline_header *)(cached_blob->data);
626bf215546Sopenharmony_ci
627bf215546Sopenharmony_ci   info->input_count = vertex_input_count;
628bf215546Sopenharmony_ci   info->stages = stages;
629bf215546Sopenharmony_ci
630bf215546Sopenharmony_ci   offset = ALIGN_POT(offset + sizeof(*info), alignof(D3D12_INPUT_ELEMENT_DESC));
631bf215546Sopenharmony_ci
632bf215546Sopenharmony_ci   D3D12_INPUT_ELEMENT_DESC *inputs =
633bf215546Sopenharmony_ci      (D3D12_INPUT_ELEMENT_DESC *)((uint8_t *)cached_blob->data + offset);
634bf215546Sopenharmony_ci   memcpy(inputs, pipeline->templates.inputs,
635bf215546Sopenharmony_ci          sizeof(*inputs) * vertex_input_count);
636bf215546Sopenharmony_ci   offset += sizeof(*inputs) * vertex_input_count;
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_ci   u_foreach_bit(s, stages) {
639bf215546Sopenharmony_ci      uint8_t *dxil_hash = (uint8_t *)cached_blob->data + offset;
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_ci      memcpy(dxil_hash, dxil_hashes[s], SHA1_DIGEST_LENGTH);
642bf215546Sopenharmony_ci      offset += SHA1_DIGEST_LENGTH;
643bf215546Sopenharmony_ci   }
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci   cache_obj = vk_pipeline_cache_add_object(cache, cache_obj);
646bf215546Sopenharmony_ci   vk_pipeline_cache_object_unref(cache_obj);
647bf215546Sopenharmony_ci}
648bf215546Sopenharmony_ci
649bf215546Sopenharmony_cistatic void
650bf215546Sopenharmony_cidzn_graphics_pipeline_hash_attribs(D3D12_INPUT_ELEMENT_DESC *attribs,
651bf215546Sopenharmony_ci                                   enum pipe_format *vi_conversions,
652bf215546Sopenharmony_ci                                   uint8_t *result)
653bf215546Sopenharmony_ci{
654bf215546Sopenharmony_ci   struct mesa_sha1 ctx;
655bf215546Sopenharmony_ci
656bf215546Sopenharmony_ci   _mesa_sha1_init(&ctx);
657bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, attribs, sizeof(*attribs) * MAX_VERTEX_GENERIC_ATTRIBS);
658bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, vi_conversions, sizeof(*vi_conversions) * MAX_VERTEX_GENERIC_ATTRIBS);
659bf215546Sopenharmony_ci   _mesa_sha1_final(&ctx, result);
660bf215546Sopenharmony_ci}
661bf215546Sopenharmony_ci
662bf215546Sopenharmony_cistatic VkResult
663bf215546Sopenharmony_cidzn_graphics_pipeline_compile_shaders(struct dzn_device *device,
664bf215546Sopenharmony_ci                                      struct dzn_graphics_pipeline *pipeline,
665bf215546Sopenharmony_ci                                      struct vk_pipeline_cache *cache,
666bf215546Sopenharmony_ci                                      const struct dzn_pipeline_layout *layout,
667bf215546Sopenharmony_ci                                      D3D12_PIPELINE_STATE_STREAM_DESC *out,
668bf215546Sopenharmony_ci                                      D3D12_INPUT_ELEMENT_DESC *attribs,
669bf215546Sopenharmony_ci                                      enum pipe_format *vi_conversions,
670bf215546Sopenharmony_ci                                      const VkGraphicsPipelineCreateInfo *info)
671bf215546Sopenharmony_ci{
672bf215546Sopenharmony_ci   const VkPipelineViewportStateCreateInfo *vp_info =
673bf215546Sopenharmony_ci      info->pRasterizationState->rasterizerDiscardEnable ?
674bf215546Sopenharmony_ci      NULL : info->pViewportState;
675bf215546Sopenharmony_ci   struct {
676bf215546Sopenharmony_ci      const VkPipelineShaderStageCreateInfo *info;
677bf215546Sopenharmony_ci      uint8_t spirv_hash[SHA1_DIGEST_LENGTH];
678bf215546Sopenharmony_ci      uint8_t dxil_hash[SHA1_DIGEST_LENGTH];
679bf215546Sopenharmony_ci   } stages[MESA_VULKAN_SHADER_STAGES] = { 0 };
680bf215546Sopenharmony_ci   const uint8_t *dxil_hashes[MESA_VULKAN_SHADER_STAGES] = { 0 };
681bf215546Sopenharmony_ci   uint8_t attribs_hash[SHA1_DIGEST_LENGTH];
682bf215546Sopenharmony_ci   uint8_t pipeline_hash[SHA1_DIGEST_LENGTH];
683bf215546Sopenharmony_ci   gl_shader_stage yz_flip_stage = MESA_SHADER_NONE;
684bf215546Sopenharmony_ci   uint32_t active_stage_mask = 0;
685bf215546Sopenharmony_ci   VkResult ret;
686bf215546Sopenharmony_ci
687bf215546Sopenharmony_ci   /* First step: collect stage info in a table indexed by gl_shader_stage
688bf215546Sopenharmony_ci    * so we can iterate over stages in pipeline order or reverse pipeline
689bf215546Sopenharmony_ci    * order.
690bf215546Sopenharmony_ci    */
691bf215546Sopenharmony_ci   for (uint32_t i = 0; i < info->stageCount; i++) {
692bf215546Sopenharmony_ci      gl_shader_stage stage =
693bf215546Sopenharmony_ci         vk_to_mesa_shader_stage(info->pStages[i].stage);
694bf215546Sopenharmony_ci
695bf215546Sopenharmony_ci      assert(stage <= MESA_SHADER_FRAGMENT);
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci      if ((stage == MESA_SHADER_VERTEX ||
698bf215546Sopenharmony_ci           stage == MESA_SHADER_TESS_EVAL ||
699bf215546Sopenharmony_ci           stage == MESA_SHADER_GEOMETRY) &&
700bf215546Sopenharmony_ci          yz_flip_stage < stage)
701bf215546Sopenharmony_ci         yz_flip_stage = stage;
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_ci      if (stage == MESA_SHADER_FRAGMENT &&
704bf215546Sopenharmony_ci          info->pRasterizationState &&
705bf215546Sopenharmony_ci          (info->pRasterizationState->rasterizerDiscardEnable ||
706bf215546Sopenharmony_ci           info->pRasterizationState->cullMode == VK_CULL_MODE_FRONT_AND_BACK)) {
707bf215546Sopenharmony_ci         /* Disable rasterization (AKA leave fragment shader NULL) when
708bf215546Sopenharmony_ci          * front+back culling or discard is set.
709bf215546Sopenharmony_ci          */
710bf215546Sopenharmony_ci         continue;
711bf215546Sopenharmony_ci      }
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci      stages[stage].info = &info->pStages[i];
714bf215546Sopenharmony_ci      active_stage_mask |= BITFIELD_BIT(stage);
715bf215546Sopenharmony_ci   }
716bf215546Sopenharmony_ci
717bf215546Sopenharmony_ci   enum dxil_spirv_yz_flip_mode yz_flip_mode = DXIL_SPIRV_YZ_FLIP_NONE;
718bf215546Sopenharmony_ci   uint16_t y_flip_mask = 0, z_flip_mask = 0;
719bf215546Sopenharmony_ci
720bf215546Sopenharmony_ci   if (pipeline->vp.dynamic) {
721bf215546Sopenharmony_ci      yz_flip_mode = DXIL_SPIRV_YZ_FLIP_CONDITIONAL;
722bf215546Sopenharmony_ci   } else if (vp_info) {
723bf215546Sopenharmony_ci      for (uint32_t i = 0; vp_info->pViewports && i < vp_info->viewportCount; i++) {
724bf215546Sopenharmony_ci         if (vp_info->pViewports[i].height > 0)
725bf215546Sopenharmony_ci            y_flip_mask |= BITFIELD_BIT(i);
726bf215546Sopenharmony_ci
727bf215546Sopenharmony_ci         if (vp_info->pViewports[i].minDepth > vp_info->pViewports[i].maxDepth)
728bf215546Sopenharmony_ci            z_flip_mask |= BITFIELD_BIT(i);
729bf215546Sopenharmony_ci      }
730bf215546Sopenharmony_ci
731bf215546Sopenharmony_ci      if (y_flip_mask && z_flip_mask)
732bf215546Sopenharmony_ci         yz_flip_mode = DXIL_SPIRV_YZ_FLIP_UNCONDITIONAL;
733bf215546Sopenharmony_ci      else if (z_flip_mask)
734bf215546Sopenharmony_ci         yz_flip_mode = DXIL_SPIRV_Z_FLIP_UNCONDITIONAL;
735bf215546Sopenharmony_ci      else if (y_flip_mask)
736bf215546Sopenharmony_ci         yz_flip_mode = DXIL_SPIRV_Y_FLIP_UNCONDITIONAL;
737bf215546Sopenharmony_ci   }
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci   bool force_sample_rate_shading =
740bf215546Sopenharmony_ci      info->pMultisampleState &&
741bf215546Sopenharmony_ci      info->pMultisampleState->sampleShadingEnable;
742bf215546Sopenharmony_ci
743bf215546Sopenharmony_ci   if (cache) {
744bf215546Sopenharmony_ci      dzn_graphics_pipeline_hash_attribs(attribs, vi_conversions, attribs_hash);
745bf215546Sopenharmony_ci
746bf215546Sopenharmony_ci      struct mesa_sha1 pipeline_hash_ctx;
747bf215546Sopenharmony_ci
748bf215546Sopenharmony_ci      _mesa_sha1_init(&pipeline_hash_ctx);
749bf215546Sopenharmony_ci      _mesa_sha1_update(&pipeline_hash_ctx, attribs_hash, sizeof(attribs_hash));
750bf215546Sopenharmony_ci      _mesa_sha1_update(&pipeline_hash_ctx, &yz_flip_mode, sizeof(yz_flip_mode));
751bf215546Sopenharmony_ci      _mesa_sha1_update(&pipeline_hash_ctx, &y_flip_mask, sizeof(y_flip_mask));
752bf215546Sopenharmony_ci      _mesa_sha1_update(&pipeline_hash_ctx, &z_flip_mask, sizeof(z_flip_mask));
753bf215546Sopenharmony_ci      _mesa_sha1_update(&pipeline_hash_ctx, &force_sample_rate_shading, sizeof(force_sample_rate_shading));
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_ci      u_foreach_bit(stage, active_stage_mask) {
756bf215546Sopenharmony_ci         vk_pipeline_hash_shader_stage(stages[stage].info, stages[stage].spirv_hash);
757bf215546Sopenharmony_ci         _mesa_sha1_update(&pipeline_hash_ctx, stages[stage].spirv_hash, sizeof(stages[stage].spirv_hash));
758bf215546Sopenharmony_ci         _mesa_sha1_update(&pipeline_hash_ctx, layout->stages[stage].hash, sizeof(layout->stages[stage].hash));
759bf215546Sopenharmony_ci      }
760bf215546Sopenharmony_ci      _mesa_sha1_final(&pipeline_hash_ctx, pipeline_hash);
761bf215546Sopenharmony_ci
762bf215546Sopenharmony_ci      bool cache_hit;
763bf215546Sopenharmony_ci      ret = dzn_pipeline_cache_lookup_gfx_pipeline(pipeline, cache, pipeline_hash,
764bf215546Sopenharmony_ci                                                   &cache_hit);
765bf215546Sopenharmony_ci      if (ret != VK_SUCCESS)
766bf215546Sopenharmony_ci         return ret;
767bf215546Sopenharmony_ci
768bf215546Sopenharmony_ci      if (cache_hit)
769bf215546Sopenharmony_ci         return VK_SUCCESS;
770bf215546Sopenharmony_ci   }
771bf215546Sopenharmony_ci
772bf215546Sopenharmony_ci   /* Second step: get NIR shaders for all stages. */
773bf215546Sopenharmony_ci   nir_shader_compiler_options nir_opts = *dxil_get_nir_compiler_options();
774bf215546Sopenharmony_ci   nir_opts.lower_base_vertex = true;
775bf215546Sopenharmony_ci   u_foreach_bit(stage, active_stage_mask) {
776bf215546Sopenharmony_ci      struct mesa_sha1 nir_hash_ctx;
777bf215546Sopenharmony_ci      uint8_t nir_hash[SHA1_DIGEST_LENGTH];
778bf215546Sopenharmony_ci
779bf215546Sopenharmony_ci      if (cache) {
780bf215546Sopenharmony_ci         _mesa_sha1_init(&nir_hash_ctx);
781bf215546Sopenharmony_ci         if (stage == MESA_SHADER_VERTEX)
782bf215546Sopenharmony_ci            _mesa_sha1_update(&nir_hash_ctx, attribs_hash, sizeof(attribs_hash));
783bf215546Sopenharmony_ci         if (stage == yz_flip_stage) {
784bf215546Sopenharmony_ci            _mesa_sha1_update(&nir_hash_ctx, &yz_flip_mode, sizeof(yz_flip_mode));
785bf215546Sopenharmony_ci            _mesa_sha1_update(&nir_hash_ctx, &y_flip_mask, sizeof(y_flip_mask));
786bf215546Sopenharmony_ci            _mesa_sha1_update(&nir_hash_ctx, &z_flip_mask, sizeof(z_flip_mask));
787bf215546Sopenharmony_ci         }
788bf215546Sopenharmony_ci         _mesa_sha1_update(&nir_hash_ctx, stages[stage].spirv_hash, sizeof(stages[stage].spirv_hash));
789bf215546Sopenharmony_ci         _mesa_sha1_final(&nir_hash_ctx, nir_hash);
790bf215546Sopenharmony_ci      }
791bf215546Sopenharmony_ci
792bf215546Sopenharmony_ci      ret = dzn_pipeline_get_nir_shader(device, layout,
793bf215546Sopenharmony_ci                                        cache, nir_hash,
794bf215546Sopenharmony_ci                                        stages[stage].info, stage,
795bf215546Sopenharmony_ci                                        stage == yz_flip_stage ? yz_flip_mode : DXIL_SPIRV_YZ_FLIP_NONE,
796bf215546Sopenharmony_ci                                        y_flip_mask, z_flip_mask,
797bf215546Sopenharmony_ci                                        stage == MESA_SHADER_FRAGMENT ? force_sample_rate_shading : false,
798bf215546Sopenharmony_ci                                        vi_conversions,
799bf215546Sopenharmony_ci                                        &nir_opts, &pipeline->templates.shaders[stage].nir);
800bf215546Sopenharmony_ci      if (ret != VK_SUCCESS)
801bf215546Sopenharmony_ci         return ret;
802bf215546Sopenharmony_ci   }
803bf215546Sopenharmony_ci
804bf215546Sopenharmony_ci   /* Third step: link those NIR shaders. We iterate in reverse order
805bf215546Sopenharmony_ci    * so we can eliminate outputs that are never read by the next stage.
806bf215546Sopenharmony_ci    */
807bf215546Sopenharmony_ci   uint32_t link_mask = active_stage_mask;
808bf215546Sopenharmony_ci   while (link_mask != 0) {
809bf215546Sopenharmony_ci      gl_shader_stage stage = util_last_bit(link_mask) - 1;
810bf215546Sopenharmony_ci      link_mask &= ~BITFIELD_BIT(stage);
811bf215546Sopenharmony_ci      gl_shader_stage prev_stage = util_last_bit(link_mask) - 1;
812bf215546Sopenharmony_ci
813bf215546Sopenharmony_ci      assert(pipeline->templates.shaders[stage].nir);
814bf215546Sopenharmony_ci      dxil_spirv_nir_link(pipeline->templates.shaders[stage].nir,
815bf215546Sopenharmony_ci                          prev_stage != MESA_SHADER_NONE ?
816bf215546Sopenharmony_ci                          pipeline->templates.shaders[prev_stage].nir : NULL);
817bf215546Sopenharmony_ci   }
818bf215546Sopenharmony_ci
819bf215546Sopenharmony_ci   u_foreach_bit(stage, active_stage_mask) {
820bf215546Sopenharmony_ci      uint8_t bindings_hash[SHA1_DIGEST_LENGTH];
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci      NIR_PASS_V(pipeline->templates.shaders[stage].nir, adjust_var_bindings, layout,
823bf215546Sopenharmony_ci                 cache ? bindings_hash : NULL);
824bf215546Sopenharmony_ci
825bf215546Sopenharmony_ci      if (cache) {
826bf215546Sopenharmony_ci         struct mesa_sha1 dxil_hash_ctx;
827bf215546Sopenharmony_ci
828bf215546Sopenharmony_ci         _mesa_sha1_init(&dxil_hash_ctx);
829bf215546Sopenharmony_ci
830bf215546Sopenharmony_ci         if (stage == MESA_SHADER_VERTEX)
831bf215546Sopenharmony_ci            _mesa_sha1_update(&dxil_hash_ctx, attribs_hash, sizeof(attribs_hash));
832bf215546Sopenharmony_ci
833bf215546Sopenharmony_ci         if (stage == yz_flip_stage) {
834bf215546Sopenharmony_ci            _mesa_sha1_update(&dxil_hash_ctx, &yz_flip_mode, sizeof(yz_flip_mode));
835bf215546Sopenharmony_ci            _mesa_sha1_update(&dxil_hash_ctx, &y_flip_mask, sizeof(y_flip_mask));
836bf215546Sopenharmony_ci            _mesa_sha1_update(&dxil_hash_ctx, &z_flip_mask, sizeof(z_flip_mask));
837bf215546Sopenharmony_ci         }
838bf215546Sopenharmony_ci
839bf215546Sopenharmony_ci         if (stage == MESA_SHADER_FRAGMENT)
840bf215546Sopenharmony_ci            _mesa_sha1_update(&dxil_hash_ctx, &force_sample_rate_shading, sizeof(force_sample_rate_shading));
841bf215546Sopenharmony_ci
842bf215546Sopenharmony_ci         _mesa_sha1_update(&dxil_hash_ctx, stages[stage].spirv_hash, sizeof(stages[stage].spirv_hash));
843bf215546Sopenharmony_ci         _mesa_sha1_update(&dxil_hash_ctx, bindings_hash, sizeof(bindings_hash));
844bf215546Sopenharmony_ci         _mesa_sha1_final(&dxil_hash_ctx, stages[stage].dxil_hash);
845bf215546Sopenharmony_ci         dxil_hashes[stage] = stages[stage].dxil_hash;
846bf215546Sopenharmony_ci
847bf215546Sopenharmony_ci         gl_shader_stage cached_stage;
848bf215546Sopenharmony_ci         D3D12_SHADER_BYTECODE bc;
849bf215546Sopenharmony_ci         ret = dzn_pipeline_cache_lookup_dxil_shader(cache, stages[stage].dxil_hash, &cached_stage, &bc);
850bf215546Sopenharmony_ci         if (ret != VK_SUCCESS)
851bf215546Sopenharmony_ci            return ret;
852bf215546Sopenharmony_ci
853bf215546Sopenharmony_ci         if (cached_stage != MESA_SHADER_NONE) {
854bf215546Sopenharmony_ci            assert(cached_stage == stage);
855bf215546Sopenharmony_ci            D3D12_SHADER_BYTECODE *slot =
856bf215546Sopenharmony_ci               dzn_pipeline_get_gfx_shader_slot(out, stage);
857bf215546Sopenharmony_ci            *slot = bc;
858bf215546Sopenharmony_ci            pipeline->templates.shaders[stage].bc = slot;
859bf215546Sopenharmony_ci         }
860bf215546Sopenharmony_ci      }
861bf215546Sopenharmony_ci   }
862bf215546Sopenharmony_ci
863bf215546Sopenharmony_ci   uint32_t vert_input_count = 0;
864bf215546Sopenharmony_ci   if (pipeline->templates.shaders[MESA_SHADER_VERTEX].nir) {
865bf215546Sopenharmony_ci      /* Now, declare one D3D12_INPUT_ELEMENT_DESC per VS input variable, so
866bf215546Sopenharmony_ci       * we can handle location overlaps properly.
867bf215546Sopenharmony_ci       */
868bf215546Sopenharmony_ci      nir_foreach_shader_in_variable(var, pipeline->templates.shaders[MESA_SHADER_VERTEX].nir) {
869bf215546Sopenharmony_ci         assert(var->data.location >= VERT_ATTRIB_GENERIC0);
870bf215546Sopenharmony_ci         unsigned loc = var->data.location - VERT_ATTRIB_GENERIC0;
871bf215546Sopenharmony_ci         assert(vert_input_count < D3D12_VS_INPUT_REGISTER_COUNT);
872bf215546Sopenharmony_ci         assert(loc < MAX_VERTEX_GENERIC_ATTRIBS);
873bf215546Sopenharmony_ci
874bf215546Sopenharmony_ci         pipeline->templates.inputs[vert_input_count] = attribs[loc];
875bf215546Sopenharmony_ci         pipeline->templates.inputs[vert_input_count].SemanticIndex = vert_input_count;
876bf215546Sopenharmony_ci         var->data.driver_location = vert_input_count++;
877bf215546Sopenharmony_ci      }
878bf215546Sopenharmony_ci
879bf215546Sopenharmony_ci      if (vert_input_count > 0) {
880bf215546Sopenharmony_ci         d3d12_gfx_pipeline_state_stream_new_desc(out, INPUT_LAYOUT, D3D12_INPUT_LAYOUT_DESC, desc);
881bf215546Sopenharmony_ci         desc->pInputElementDescs = pipeline->templates.inputs;
882bf215546Sopenharmony_ci         desc->NumElements = vert_input_count;
883bf215546Sopenharmony_ci      }
884bf215546Sopenharmony_ci   }
885bf215546Sopenharmony_ci
886bf215546Sopenharmony_ci   /* Last step: translate NIR shaders into DXIL modules */
887bf215546Sopenharmony_ci   u_foreach_bit(stage, active_stage_mask) {
888bf215546Sopenharmony_ci      /* Cache hit, we can skip the compilation. */
889bf215546Sopenharmony_ci      if (pipeline->templates.shaders[stage].bc)
890bf215546Sopenharmony_ci         continue;
891bf215546Sopenharmony_ci
892bf215546Sopenharmony_ci      if (stage == MESA_SHADER_FRAGMENT) {
893bf215546Sopenharmony_ci         gl_shader_stage prev_stage =
894bf215546Sopenharmony_ci            util_last_bit(active_stage_mask & BITFIELD_MASK(MESA_SHADER_FRAGMENT)) - 1;
895bf215546Sopenharmony_ci         /* Disable rasterization if the last geometry stage doesn't
896bf215546Sopenharmony_ci          * write the position.
897bf215546Sopenharmony_ci          */
898bf215546Sopenharmony_ci         if (prev_stage == MESA_SHADER_NONE ||
899bf215546Sopenharmony_ci             !(pipeline->templates.shaders[prev_stage].nir->info.outputs_written & VARYING_BIT_POS))
900bf215546Sopenharmony_ci            continue;
901bf215546Sopenharmony_ci      }
902bf215546Sopenharmony_ci
903bf215546Sopenharmony_ci      D3D12_SHADER_BYTECODE *slot =
904bf215546Sopenharmony_ci         dzn_pipeline_get_gfx_shader_slot(out, stage);
905bf215546Sopenharmony_ci
906bf215546Sopenharmony_ci      ret = dzn_pipeline_compile_shader(device, pipeline->templates.shaders[stage].nir, slot);
907bf215546Sopenharmony_ci      if (ret != VK_SUCCESS)
908bf215546Sopenharmony_ci         return ret;
909bf215546Sopenharmony_ci
910bf215546Sopenharmony_ci      pipeline->templates.shaders[stage].bc = slot;
911bf215546Sopenharmony_ci
912bf215546Sopenharmony_ci      if (cache)
913bf215546Sopenharmony_ci         dzn_pipeline_cache_add_dxil_shader(cache, stages[stage].dxil_hash, stage, slot);
914bf215546Sopenharmony_ci   }
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci   if (cache)
917bf215546Sopenharmony_ci      dzn_pipeline_cache_add_gfx_pipeline(pipeline, cache, vert_input_count, pipeline_hash,
918bf215546Sopenharmony_ci                                          dxil_hashes);
919bf215546Sopenharmony_ci
920bf215546Sopenharmony_ci   return VK_SUCCESS;
921bf215546Sopenharmony_ci}
922bf215546Sopenharmony_ci
923bf215546Sopenharmony_ciVkFormat
924bf215546Sopenharmony_cidzn_graphics_pipeline_patch_vi_format(VkFormat format)
925bf215546Sopenharmony_ci{
926bf215546Sopenharmony_ci   switch (format) {
927bf215546Sopenharmony_ci   case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
928bf215546Sopenharmony_ci   case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
929bf215546Sopenharmony_ci   case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
930bf215546Sopenharmony_ci   case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
931bf215546Sopenharmony_ci   case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
932bf215546Sopenharmony_ci   case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
933bf215546Sopenharmony_ci   case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
934bf215546Sopenharmony_ci      return VK_FORMAT_R32_UINT;
935bf215546Sopenharmony_ci   case VK_FORMAT_R8G8B8A8_SSCALED:
936bf215546Sopenharmony_ci      return VK_FORMAT_R8G8B8A8_SINT;
937bf215546Sopenharmony_ci   case VK_FORMAT_R8G8B8A8_USCALED:
938bf215546Sopenharmony_ci      return VK_FORMAT_R8G8B8A8_UINT;
939bf215546Sopenharmony_ci   case VK_FORMAT_R16G16B16A16_USCALED:
940bf215546Sopenharmony_ci      return VK_FORMAT_R16G16B16A16_UINT;
941bf215546Sopenharmony_ci   case VK_FORMAT_R16G16B16A16_SSCALED:
942bf215546Sopenharmony_ci      return VK_FORMAT_R16G16B16A16_SINT;
943bf215546Sopenharmony_ci   default:
944bf215546Sopenharmony_ci      return format;
945bf215546Sopenharmony_ci   }
946bf215546Sopenharmony_ci}
947bf215546Sopenharmony_ci
948bf215546Sopenharmony_cistatic VkResult
949bf215546Sopenharmony_cidzn_graphics_pipeline_translate_vi(struct dzn_graphics_pipeline *pipeline,
950bf215546Sopenharmony_ci                                   const VkGraphicsPipelineCreateInfo *in,
951bf215546Sopenharmony_ci                                   D3D12_INPUT_ELEMENT_DESC *inputs,
952bf215546Sopenharmony_ci                                   enum pipe_format *vi_conversions)
953bf215546Sopenharmony_ci{
954bf215546Sopenharmony_ci   const VkPipelineVertexInputStateCreateInfo *in_vi =
955bf215546Sopenharmony_ci      in->pVertexInputState;
956bf215546Sopenharmony_ci   const VkPipelineVertexInputDivisorStateCreateInfoEXT *divisors =
957bf215546Sopenharmony_ci      (const VkPipelineVertexInputDivisorStateCreateInfoEXT *)
958bf215546Sopenharmony_ci      vk_find_struct_const(in_vi, PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT);
959bf215546Sopenharmony_ci
960bf215546Sopenharmony_ci   if (!in_vi->vertexAttributeDescriptionCount)
961bf215546Sopenharmony_ci      return VK_SUCCESS;
962bf215546Sopenharmony_ci
963bf215546Sopenharmony_ci   D3D12_INPUT_CLASSIFICATION slot_class[MAX_VBS];
964bf215546Sopenharmony_ci
965bf215546Sopenharmony_ci   pipeline->vb.count = 0;
966bf215546Sopenharmony_ci   for (uint32_t i = 0; i < in_vi->vertexBindingDescriptionCount; i++) {
967bf215546Sopenharmony_ci      const struct VkVertexInputBindingDescription *bdesc =
968bf215546Sopenharmony_ci         &in_vi->pVertexBindingDescriptions[i];
969bf215546Sopenharmony_ci
970bf215546Sopenharmony_ci      pipeline->vb.count = MAX2(pipeline->vb.count, bdesc->binding + 1);
971bf215546Sopenharmony_ci      pipeline->vb.strides[bdesc->binding] = bdesc->stride;
972bf215546Sopenharmony_ci      if (bdesc->inputRate == VK_VERTEX_INPUT_RATE_INSTANCE) {
973bf215546Sopenharmony_ci         slot_class[bdesc->binding] = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
974bf215546Sopenharmony_ci      } else {
975bf215546Sopenharmony_ci         assert(bdesc->inputRate == VK_VERTEX_INPUT_RATE_VERTEX);
976bf215546Sopenharmony_ci         slot_class[bdesc->binding] = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
977bf215546Sopenharmony_ci      }
978bf215546Sopenharmony_ci   }
979bf215546Sopenharmony_ci
980bf215546Sopenharmony_ci   for (uint32_t i = 0; i < in_vi->vertexAttributeDescriptionCount; i++) {
981bf215546Sopenharmony_ci      const VkVertexInputAttributeDescription *attr =
982bf215546Sopenharmony_ci         &in_vi->pVertexAttributeDescriptions[i];
983bf215546Sopenharmony_ci      const VkVertexInputBindingDivisorDescriptionEXT *divisor = NULL;
984bf215546Sopenharmony_ci
985bf215546Sopenharmony_ci      if (slot_class[attr->binding] == D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA &&
986bf215546Sopenharmony_ci          divisors) {
987bf215546Sopenharmony_ci         for (uint32_t d = 0; d < divisors->vertexBindingDivisorCount; d++) {
988bf215546Sopenharmony_ci            if (attr->binding == divisors->pVertexBindingDivisors[d].binding) {
989bf215546Sopenharmony_ci               divisor = &divisors->pVertexBindingDivisors[d];
990bf215546Sopenharmony_ci               break;
991bf215546Sopenharmony_ci            }
992bf215546Sopenharmony_ci         }
993bf215546Sopenharmony_ci      }
994bf215546Sopenharmony_ci
995bf215546Sopenharmony_ci      VkFormat patched_format = dzn_graphics_pipeline_patch_vi_format(attr->format);
996bf215546Sopenharmony_ci      if (patched_format != attr->format)
997bf215546Sopenharmony_ci         vi_conversions[attr->location] = vk_format_to_pipe_format(attr->format);
998bf215546Sopenharmony_ci
999bf215546Sopenharmony_ci      /* nir_to_dxil() name all vertex inputs as TEXCOORDx */
1000bf215546Sopenharmony_ci      inputs[attr->location] = (D3D12_INPUT_ELEMENT_DESC) {
1001bf215546Sopenharmony_ci         .SemanticName = "TEXCOORD",
1002bf215546Sopenharmony_ci         .Format = dzn_buffer_get_dxgi_format(patched_format),
1003bf215546Sopenharmony_ci         .InputSlot = attr->binding,
1004bf215546Sopenharmony_ci         .InputSlotClass = slot_class[attr->binding],
1005bf215546Sopenharmony_ci         .InstanceDataStepRate =
1006bf215546Sopenharmony_ci            divisor ? divisor->divisor :
1007bf215546Sopenharmony_ci            slot_class[attr->binding] == D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA ? 1 : 0,
1008bf215546Sopenharmony_ci         .AlignedByteOffset = attr->offset,
1009bf215546Sopenharmony_ci      };
1010bf215546Sopenharmony_ci   }
1011bf215546Sopenharmony_ci
1012bf215546Sopenharmony_ci   return VK_SUCCESS;
1013bf215546Sopenharmony_ci}
1014bf215546Sopenharmony_ci
1015bf215546Sopenharmony_cistatic D3D12_PRIMITIVE_TOPOLOGY_TYPE
1016bf215546Sopenharmony_cito_prim_topology_type(VkPrimitiveTopology in)
1017bf215546Sopenharmony_ci{
1018bf215546Sopenharmony_ci   switch (in) {
1019bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1020bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
1021bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1022bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
1023bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1024bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
1025bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
1026bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1027bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1028bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
1029bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1030bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
1031bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
1032bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1033bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
1034bf215546Sopenharmony_ci   default: unreachable("Invalid primitive topology");
1035bf215546Sopenharmony_ci   }
1036bf215546Sopenharmony_ci}
1037bf215546Sopenharmony_ci
1038bf215546Sopenharmony_cistatic D3D12_PRIMITIVE_TOPOLOGY
1039bf215546Sopenharmony_cito_prim_topology(VkPrimitiveTopology in, unsigned patch_control_points)
1040bf215546Sopenharmony_ci{
1041bf215546Sopenharmony_ci   switch (in) {
1042bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: return D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
1043bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: return D3D_PRIMITIVE_TOPOLOGY_LINELIST;
1044bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
1045bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: return D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
1046bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: return D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ;
1047bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1048bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
1049bf215546Sopenharmony_ci   /* Triangle fans are emulated using an intermediate index buffer. */
1050bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1051bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ;
1052bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ;
1053bf215546Sopenharmony_ci   case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1054bf215546Sopenharmony_ci      assert(patch_control_points);
1055bf215546Sopenharmony_ci      return (D3D12_PRIMITIVE_TOPOLOGY)(D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + patch_control_points - 1);
1056bf215546Sopenharmony_ci   default: unreachable("Invalid primitive topology");
1057bf215546Sopenharmony_ci   }
1058bf215546Sopenharmony_ci}
1059bf215546Sopenharmony_ci
1060bf215546Sopenharmony_cistatic VkResult
1061bf215546Sopenharmony_cidzn_graphics_pipeline_translate_ia(struct dzn_device *device,
1062bf215546Sopenharmony_ci                                   struct dzn_graphics_pipeline *pipeline,
1063bf215546Sopenharmony_ci                                   D3D12_PIPELINE_STATE_STREAM_DESC *out,
1064bf215546Sopenharmony_ci                                   const VkGraphicsPipelineCreateInfo *in)
1065bf215546Sopenharmony_ci{
1066bf215546Sopenharmony_ci   const VkPipelineInputAssemblyStateCreateInfo *in_ia =
1067bf215546Sopenharmony_ci      in->pInputAssemblyState;
1068bf215546Sopenharmony_ci   bool has_tes = false;
1069bf215546Sopenharmony_ci   for (uint32_t i = 0; i < in->stageCount; i++) {
1070bf215546Sopenharmony_ci      if (in->pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
1071bf215546Sopenharmony_ci          in->pStages[i].stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
1072bf215546Sopenharmony_ci         has_tes = true;
1073bf215546Sopenharmony_ci         break;
1074bf215546Sopenharmony_ci      }
1075bf215546Sopenharmony_ci   }
1076bf215546Sopenharmony_ci   const VkPipelineTessellationStateCreateInfo *in_tes =
1077bf215546Sopenharmony_ci      has_tes ? in->pTessellationState : NULL;
1078bf215546Sopenharmony_ci   VkResult ret = VK_SUCCESS;
1079bf215546Sopenharmony_ci
1080bf215546Sopenharmony_ci   d3d12_gfx_pipeline_state_stream_new_desc(out, PRIMITIVE_TOPOLOGY, D3D12_PRIMITIVE_TOPOLOGY_TYPE, prim_top_type);
1081bf215546Sopenharmony_ci   *prim_top_type = to_prim_topology_type(in_ia->topology);
1082bf215546Sopenharmony_ci   pipeline->ia.triangle_fan = in_ia->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
1083bf215546Sopenharmony_ci   pipeline->ia.topology =
1084bf215546Sopenharmony_ci      to_prim_topology(in_ia->topology, in_tes ? in_tes->patchControlPoints : 0);
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_ci   if (in_ia->primitiveRestartEnable) {
1087bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(out, IB_STRIP_CUT_VALUE, D3D12_INDEX_BUFFER_STRIP_CUT_VALUE, ib_strip_cut);
1088bf215546Sopenharmony_ci      pipeline->templates.desc_offsets.ib_strip_cut =
1089bf215546Sopenharmony_ci         (uintptr_t)ib_strip_cut - (uintptr_t)out->pPipelineStateSubobjectStream;
1090bf215546Sopenharmony_ci      *ib_strip_cut = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
1091bf215546Sopenharmony_ci      ret = dzn_graphics_pipeline_prepare_for_variants(device, pipeline);
1092bf215546Sopenharmony_ci   }
1093bf215546Sopenharmony_ci
1094bf215546Sopenharmony_ci   return ret;
1095bf215546Sopenharmony_ci}
1096bf215546Sopenharmony_ci
1097bf215546Sopenharmony_cistatic D3D12_FILL_MODE
1098bf215546Sopenharmony_citranslate_polygon_mode(VkPolygonMode in)
1099bf215546Sopenharmony_ci{
1100bf215546Sopenharmony_ci   switch (in) {
1101bf215546Sopenharmony_ci   case VK_POLYGON_MODE_FILL: return D3D12_FILL_MODE_SOLID;
1102bf215546Sopenharmony_ci   case VK_POLYGON_MODE_LINE: return D3D12_FILL_MODE_WIREFRAME;
1103bf215546Sopenharmony_ci   default: unreachable("Unsupported polygon mode");
1104bf215546Sopenharmony_ci   }
1105bf215546Sopenharmony_ci}
1106bf215546Sopenharmony_ci
1107bf215546Sopenharmony_cistatic D3D12_CULL_MODE
1108bf215546Sopenharmony_citranslate_cull_mode(VkCullModeFlags in)
1109bf215546Sopenharmony_ci{
1110bf215546Sopenharmony_ci   switch (in) {
1111bf215546Sopenharmony_ci   case VK_CULL_MODE_NONE: return D3D12_CULL_MODE_NONE;
1112bf215546Sopenharmony_ci   case VK_CULL_MODE_FRONT_BIT: return D3D12_CULL_MODE_FRONT;
1113bf215546Sopenharmony_ci   case VK_CULL_MODE_BACK_BIT: return D3D12_CULL_MODE_BACK;
1114bf215546Sopenharmony_ci   /* Front+back face culling is equivalent to 'rasterization disabled' */
1115bf215546Sopenharmony_ci   case VK_CULL_MODE_FRONT_AND_BACK: return D3D12_CULL_MODE_NONE;
1116bf215546Sopenharmony_ci   default: unreachable("Unsupported cull mode");
1117bf215546Sopenharmony_ci   }
1118bf215546Sopenharmony_ci}
1119bf215546Sopenharmony_ci
1120bf215546Sopenharmony_cistatic int32_t
1121bf215546Sopenharmony_citranslate_depth_bias(double depth_bias)
1122bf215546Sopenharmony_ci{
1123bf215546Sopenharmony_ci   if (depth_bias > INT32_MAX)
1124bf215546Sopenharmony_ci      return INT32_MAX;
1125bf215546Sopenharmony_ci   else if (depth_bias < INT32_MIN)
1126bf215546Sopenharmony_ci      return INT32_MIN;
1127bf215546Sopenharmony_ci
1128bf215546Sopenharmony_ci   return depth_bias;
1129bf215546Sopenharmony_ci}
1130bf215546Sopenharmony_ci
1131bf215546Sopenharmony_cistatic void
1132bf215546Sopenharmony_cidzn_graphics_pipeline_translate_rast(struct dzn_graphics_pipeline *pipeline,
1133bf215546Sopenharmony_ci                                     D3D12_PIPELINE_STATE_STREAM_DESC *out,
1134bf215546Sopenharmony_ci                                     const VkGraphicsPipelineCreateInfo *in)
1135bf215546Sopenharmony_ci{
1136bf215546Sopenharmony_ci   const VkPipelineRasterizationStateCreateInfo *in_rast =
1137bf215546Sopenharmony_ci      in->pRasterizationState;
1138bf215546Sopenharmony_ci   const VkPipelineViewportStateCreateInfo *in_vp =
1139bf215546Sopenharmony_ci      in_rast->rasterizerDiscardEnable ? NULL : in->pViewportState;
1140bf215546Sopenharmony_ci
1141bf215546Sopenharmony_ci   if (in_vp) {
1142bf215546Sopenharmony_ci      pipeline->vp.count = in_vp->viewportCount;
1143bf215546Sopenharmony_ci      if (in_vp->pViewports) {
1144bf215546Sopenharmony_ci         for (uint32_t i = 0; in_vp->pViewports && i < in_vp->viewportCount; i++)
1145bf215546Sopenharmony_ci            dzn_translate_viewport(&pipeline->vp.desc[i], &in_vp->pViewports[i]);
1146bf215546Sopenharmony_ci      }
1147bf215546Sopenharmony_ci
1148bf215546Sopenharmony_ci      pipeline->scissor.count = in_vp->scissorCount;
1149bf215546Sopenharmony_ci      if (in_vp->pScissors) {
1150bf215546Sopenharmony_ci         for (uint32_t i = 0; i < in_vp->scissorCount; i++)
1151bf215546Sopenharmony_ci            dzn_translate_rect(&pipeline->scissor.desc[i], &in_vp->pScissors[i]);
1152bf215546Sopenharmony_ci      }
1153bf215546Sopenharmony_ci   }
1154bf215546Sopenharmony_ci
1155bf215546Sopenharmony_ci   d3d12_gfx_pipeline_state_stream_new_desc(out, RASTERIZER, D3D12_RASTERIZER_DESC, desc);
1156bf215546Sopenharmony_ci   pipeline->templates.desc_offsets.rast =
1157bf215546Sopenharmony_ci      (uintptr_t)desc - (uintptr_t)out->pPipelineStateSubobjectStream;
1158bf215546Sopenharmony_ci   desc->DepthClipEnable = !in_rast->depthClampEnable;
1159bf215546Sopenharmony_ci   desc->FillMode = translate_polygon_mode(in_rast->polygonMode);
1160bf215546Sopenharmony_ci   desc->CullMode = translate_cull_mode(in_rast->cullMode);
1161bf215546Sopenharmony_ci   desc->FrontCounterClockwise =
1162bf215546Sopenharmony_ci      in_rast->frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE;
1163bf215546Sopenharmony_ci   if (in_rast->depthBiasEnable) {
1164bf215546Sopenharmony_ci      desc->DepthBias = translate_depth_bias(in_rast->depthBiasConstantFactor);
1165bf215546Sopenharmony_ci      desc->SlopeScaledDepthBias = in_rast->depthBiasSlopeFactor;
1166bf215546Sopenharmony_ci      desc->DepthBiasClamp = in_rast->depthBiasClamp;
1167bf215546Sopenharmony_ci   }
1168bf215546Sopenharmony_ci
1169bf215546Sopenharmony_ci   assert(in_rast->lineWidth == 1.0f);
1170bf215546Sopenharmony_ci}
1171bf215546Sopenharmony_ci
1172bf215546Sopenharmony_cistatic void
1173bf215546Sopenharmony_cidzn_graphics_pipeline_translate_ms(struct dzn_graphics_pipeline *pipeline,
1174bf215546Sopenharmony_ci                                   D3D12_PIPELINE_STATE_STREAM_DESC *out,
1175bf215546Sopenharmony_ci                                   const VkGraphicsPipelineCreateInfo *in)
1176bf215546Sopenharmony_ci{
1177bf215546Sopenharmony_ci   const VkPipelineRasterizationStateCreateInfo *in_rast =
1178bf215546Sopenharmony_ci      in->pRasterizationState;
1179bf215546Sopenharmony_ci   const VkPipelineMultisampleStateCreateInfo *in_ms =
1180bf215546Sopenharmony_ci      in_rast->rasterizerDiscardEnable ? NULL : in->pMultisampleState;
1181bf215546Sopenharmony_ci
1182bf215546Sopenharmony_ci   if (!in_ms)
1183bf215546Sopenharmony_ci      return;
1184bf215546Sopenharmony_ci
1185bf215546Sopenharmony_ci   /* TODO: minSampleShading (use VRS), alphaToOneEnable */
1186bf215546Sopenharmony_ci   d3d12_gfx_pipeline_state_stream_new_desc(out, SAMPLE_DESC, DXGI_SAMPLE_DESC, desc);
1187bf215546Sopenharmony_ci   desc->Count = in_ms ? in_ms->rasterizationSamples : 1;
1188bf215546Sopenharmony_ci   desc->Quality = 0;
1189bf215546Sopenharmony_ci
1190bf215546Sopenharmony_ci   if (!in_ms->pSampleMask)
1191bf215546Sopenharmony_ci      return;
1192bf215546Sopenharmony_ci
1193bf215546Sopenharmony_ci   d3d12_gfx_pipeline_state_stream_new_desc(out, SAMPLE_MASK, UINT, mask);
1194bf215546Sopenharmony_ci   *mask = *in_ms->pSampleMask;
1195bf215546Sopenharmony_ci}
1196bf215546Sopenharmony_ci
1197bf215546Sopenharmony_cistatic D3D12_STENCIL_OP
1198bf215546Sopenharmony_citranslate_stencil_op(VkStencilOp in)
1199bf215546Sopenharmony_ci{
1200bf215546Sopenharmony_ci   switch (in) {
1201bf215546Sopenharmony_ci   case VK_STENCIL_OP_KEEP: return D3D12_STENCIL_OP_KEEP;
1202bf215546Sopenharmony_ci   case VK_STENCIL_OP_ZERO: return D3D12_STENCIL_OP_ZERO;
1203bf215546Sopenharmony_ci   case VK_STENCIL_OP_REPLACE: return D3D12_STENCIL_OP_REPLACE;
1204bf215546Sopenharmony_ci   case VK_STENCIL_OP_INCREMENT_AND_CLAMP: return D3D12_STENCIL_OP_INCR_SAT;
1205bf215546Sopenharmony_ci   case VK_STENCIL_OP_DECREMENT_AND_CLAMP: return D3D12_STENCIL_OP_DECR_SAT;
1206bf215546Sopenharmony_ci   case VK_STENCIL_OP_INCREMENT_AND_WRAP: return D3D12_STENCIL_OP_INCR;
1207bf215546Sopenharmony_ci   case VK_STENCIL_OP_DECREMENT_AND_WRAP: return D3D12_STENCIL_OP_DECR;
1208bf215546Sopenharmony_ci   case VK_STENCIL_OP_INVERT: return D3D12_STENCIL_OP_INVERT;
1209bf215546Sopenharmony_ci   default: unreachable("Invalid stencil op");
1210bf215546Sopenharmony_ci   }
1211bf215546Sopenharmony_ci}
1212bf215546Sopenharmony_ci
1213bf215546Sopenharmony_cistatic void
1214bf215546Sopenharmony_citranslate_stencil_test(struct dzn_graphics_pipeline *pipeline,
1215bf215546Sopenharmony_ci                       D3D12_DEPTH_STENCIL_DESC1 *out,
1216bf215546Sopenharmony_ci                       const VkGraphicsPipelineCreateInfo *in)
1217bf215546Sopenharmony_ci{
1218bf215546Sopenharmony_ci   const VkPipelineDepthStencilStateCreateInfo *in_zsa =
1219bf215546Sopenharmony_ci      in->pDepthStencilState;
1220bf215546Sopenharmony_ci
1221bf215546Sopenharmony_ci   bool front_test_uses_ref =
1222bf215546Sopenharmony_ci      !(in->pRasterizationState->cullMode & VK_CULL_MODE_FRONT_BIT) &&
1223bf215546Sopenharmony_ci      in_zsa->front.compareOp != VK_COMPARE_OP_NEVER &&
1224bf215546Sopenharmony_ci      in_zsa->front.compareOp != VK_COMPARE_OP_ALWAYS &&
1225bf215546Sopenharmony_ci      (pipeline->zsa.stencil_test.dynamic_compare_mask ||
1226bf215546Sopenharmony_ci       in_zsa->front.compareMask != 0);
1227bf215546Sopenharmony_ci   bool back_test_uses_ref =
1228bf215546Sopenharmony_ci      !(in->pRasterizationState->cullMode & VK_CULL_MODE_BACK_BIT) &&
1229bf215546Sopenharmony_ci      in_zsa->back.compareOp != VK_COMPARE_OP_NEVER &&
1230bf215546Sopenharmony_ci      in_zsa->back.compareOp != VK_COMPARE_OP_ALWAYS &&
1231bf215546Sopenharmony_ci      (pipeline->zsa.stencil_test.dynamic_compare_mask ||
1232bf215546Sopenharmony_ci       in_zsa->back.compareMask != 0);
1233bf215546Sopenharmony_ci
1234bf215546Sopenharmony_ci   if (front_test_uses_ref && pipeline->zsa.stencil_test.dynamic_compare_mask)
1235bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.front.compare_mask = UINT32_MAX;
1236bf215546Sopenharmony_ci   else if (front_test_uses_ref)
1237bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.front.compare_mask = in_zsa->front.compareMask;
1238bf215546Sopenharmony_ci   else
1239bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.front.compare_mask = 0;
1240bf215546Sopenharmony_ci
1241bf215546Sopenharmony_ci   if (back_test_uses_ref && pipeline->zsa.stencil_test.dynamic_compare_mask)
1242bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.back.compare_mask = UINT32_MAX;
1243bf215546Sopenharmony_ci   else if (back_test_uses_ref)
1244bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.back.compare_mask = in_zsa->back.compareMask;
1245bf215546Sopenharmony_ci   else
1246bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.back.compare_mask = 0;
1247bf215546Sopenharmony_ci
1248bf215546Sopenharmony_ci   bool diff_wr_mask =
1249bf215546Sopenharmony_ci      in->pRasterizationState->cullMode == VK_CULL_MODE_NONE &&
1250bf215546Sopenharmony_ci      (pipeline->zsa.stencil_test.dynamic_write_mask ||
1251bf215546Sopenharmony_ci       in_zsa->back.writeMask != in_zsa->front.writeMask);
1252bf215546Sopenharmony_ci   bool diff_ref =
1253bf215546Sopenharmony_ci      in->pRasterizationState->cullMode == VK_CULL_MODE_NONE &&
1254bf215546Sopenharmony_ci      (pipeline->zsa.stencil_test.dynamic_ref ||
1255bf215546Sopenharmony_ci       in_zsa->back.reference != in_zsa->front.reference);
1256bf215546Sopenharmony_ci   bool diff_cmp_mask =
1257bf215546Sopenharmony_ci      back_test_uses_ref && front_test_uses_ref &&
1258bf215546Sopenharmony_ci      (pipeline->zsa.stencil_test.dynamic_compare_mask ||
1259bf215546Sopenharmony_ci       pipeline->zsa.stencil_test.front.compare_mask != pipeline->zsa.stencil_test.back.compare_mask);
1260bf215546Sopenharmony_ci
1261bf215546Sopenharmony_ci   if (diff_cmp_mask || diff_wr_mask)
1262bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.independent_front_back = true;
1263bf215546Sopenharmony_ci
1264bf215546Sopenharmony_ci   bool back_wr_uses_ref =
1265bf215546Sopenharmony_ci      !(in->pRasterizationState->cullMode & VK_CULL_MODE_BACK_BIT) &&
1266bf215546Sopenharmony_ci      ((in_zsa->back.compareOp != VK_COMPARE_OP_ALWAYS &&
1267bf215546Sopenharmony_ci        in_zsa->back.failOp == VK_STENCIL_OP_REPLACE) ||
1268bf215546Sopenharmony_ci       (in_zsa->back.compareOp != VK_COMPARE_OP_NEVER &&
1269bf215546Sopenharmony_ci        (!in_zsa->depthTestEnable || in_zsa->depthCompareOp != VK_COMPARE_OP_NEVER) &&
1270bf215546Sopenharmony_ci        in_zsa->back.passOp == VK_STENCIL_OP_REPLACE) ||
1271bf215546Sopenharmony_ci       (in_zsa->depthTestEnable &&
1272bf215546Sopenharmony_ci        in_zsa->depthCompareOp != VK_COMPARE_OP_ALWAYS &&
1273bf215546Sopenharmony_ci        in_zsa->back.depthFailOp == VK_STENCIL_OP_REPLACE));
1274bf215546Sopenharmony_ci   bool front_wr_uses_ref =
1275bf215546Sopenharmony_ci      !(in->pRasterizationState->cullMode & VK_CULL_MODE_FRONT_BIT) &&
1276bf215546Sopenharmony_ci      ((in_zsa->front.compareOp != VK_COMPARE_OP_ALWAYS &&
1277bf215546Sopenharmony_ci        in_zsa->front.failOp == VK_STENCIL_OP_REPLACE) ||
1278bf215546Sopenharmony_ci       (in_zsa->front.compareOp != VK_COMPARE_OP_NEVER &&
1279bf215546Sopenharmony_ci        (!in_zsa->depthTestEnable || in_zsa->depthCompareOp != VK_COMPARE_OP_NEVER) &&
1280bf215546Sopenharmony_ci        in_zsa->front.passOp == VK_STENCIL_OP_REPLACE) ||
1281bf215546Sopenharmony_ci       (in_zsa->depthTestEnable &&
1282bf215546Sopenharmony_ci        in_zsa->depthCompareOp != VK_COMPARE_OP_ALWAYS &&
1283bf215546Sopenharmony_ci        in_zsa->front.depthFailOp == VK_STENCIL_OP_REPLACE));
1284bf215546Sopenharmony_ci
1285bf215546Sopenharmony_ci   pipeline->zsa.stencil_test.front.write_mask =
1286bf215546Sopenharmony_ci      (pipeline->zsa.stencil_test.dynamic_write_mask ||
1287bf215546Sopenharmony_ci       (in->pRasterizationState->cullMode & VK_CULL_MODE_FRONT_BIT)) ?
1288bf215546Sopenharmony_ci      0 : in_zsa->front.writeMask;
1289bf215546Sopenharmony_ci   pipeline->zsa.stencil_test.back.write_mask =
1290bf215546Sopenharmony_ci      (pipeline->zsa.stencil_test.dynamic_write_mask ||
1291bf215546Sopenharmony_ci       (in->pRasterizationState->cullMode & VK_CULL_MODE_BACK_BIT)) ?
1292bf215546Sopenharmony_ci      0 : in_zsa->back.writeMask;
1293bf215546Sopenharmony_ci
1294bf215546Sopenharmony_ci   pipeline->zsa.stencil_test.front.uses_ref = front_test_uses_ref || front_wr_uses_ref;
1295bf215546Sopenharmony_ci   pipeline->zsa.stencil_test.back.uses_ref = back_test_uses_ref || back_wr_uses_ref;
1296bf215546Sopenharmony_ci
1297bf215546Sopenharmony_ci   if (diff_ref &&
1298bf215546Sopenharmony_ci       pipeline->zsa.stencil_test.front.uses_ref &&
1299bf215546Sopenharmony_ci       pipeline->zsa.stencil_test.back.uses_ref)
1300bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.independent_front_back = true;
1301bf215546Sopenharmony_ci
1302bf215546Sopenharmony_ci   pipeline->zsa.stencil_test.front.ref =
1303bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.dynamic_ref ? 0 : in_zsa->front.reference;
1304bf215546Sopenharmony_ci   pipeline->zsa.stencil_test.back.ref =
1305bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.dynamic_ref ? 0 : in_zsa->back.reference;
1306bf215546Sopenharmony_ci
1307bf215546Sopenharmony_ci   /* FIXME: We don't support independent {compare,write}_mask and stencil
1308bf215546Sopenharmony_ci    * reference. Until we have proper support for independent front/back
1309bf215546Sopenharmony_ci    * stencil test, let's prioritize the front setup when both are active.
1310bf215546Sopenharmony_ci    */
1311bf215546Sopenharmony_ci   out->StencilReadMask =
1312bf215546Sopenharmony_ci      front_test_uses_ref ?
1313bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.front.compare_mask :
1314bf215546Sopenharmony_ci      back_test_uses_ref ?
1315bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.back.compare_mask : 0;
1316bf215546Sopenharmony_ci   out->StencilWriteMask =
1317bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.front.write_mask ?
1318bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.front.write_mask :
1319bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.back.write_mask;
1320bf215546Sopenharmony_ci
1321bf215546Sopenharmony_ci   assert(!pipeline->zsa.stencil_test.independent_front_back);
1322bf215546Sopenharmony_ci}
1323bf215546Sopenharmony_ci
1324bf215546Sopenharmony_cistatic void
1325bf215546Sopenharmony_cidzn_graphics_pipeline_translate_zsa(struct dzn_graphics_pipeline *pipeline,
1326bf215546Sopenharmony_ci                                    D3D12_PIPELINE_STATE_STREAM_DESC *out,
1327bf215546Sopenharmony_ci                                    const VkGraphicsPipelineCreateInfo *in)
1328bf215546Sopenharmony_ci{
1329bf215546Sopenharmony_ci   const VkPipelineRasterizationStateCreateInfo *in_rast =
1330bf215546Sopenharmony_ci      in->pRasterizationState;
1331bf215546Sopenharmony_ci   const VkPipelineDepthStencilStateCreateInfo *in_zsa =
1332bf215546Sopenharmony_ci      in_rast->rasterizerDiscardEnable ? NULL : in->pDepthStencilState;
1333bf215546Sopenharmony_ci
1334bf215546Sopenharmony_ci   if (!in_zsa)
1335bf215546Sopenharmony_ci      return;
1336bf215546Sopenharmony_ci
1337bf215546Sopenharmony_ci   d3d12_gfx_pipeline_state_stream_new_desc(out, DEPTH_STENCIL1, D3D12_DEPTH_STENCIL_DESC1, desc);
1338bf215546Sopenharmony_ci   pipeline->templates.desc_offsets.ds =
1339bf215546Sopenharmony_ci      (uintptr_t)desc - (uintptr_t)out->pPipelineStateSubobjectStream;
1340bf215546Sopenharmony_ci
1341bf215546Sopenharmony_ci   desc->DepthEnable =
1342bf215546Sopenharmony_ci      in_zsa->depthTestEnable || in_zsa->depthBoundsTestEnable;
1343bf215546Sopenharmony_ci   desc->DepthWriteMask =
1344bf215546Sopenharmony_ci      in_zsa->depthWriteEnable ?
1345bf215546Sopenharmony_ci      D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
1346bf215546Sopenharmony_ci   desc->DepthFunc =
1347bf215546Sopenharmony_ci      in_zsa->depthTestEnable ?
1348bf215546Sopenharmony_ci      dzn_translate_compare_op(in_zsa->depthCompareOp) :
1349bf215546Sopenharmony_ci      D3D12_COMPARISON_FUNC_ALWAYS;
1350bf215546Sopenharmony_ci   pipeline->zsa.depth_bounds.enable = in_zsa->depthBoundsTestEnable;
1351bf215546Sopenharmony_ci   pipeline->zsa.depth_bounds.min = in_zsa->minDepthBounds;
1352bf215546Sopenharmony_ci   pipeline->zsa.depth_bounds.max = in_zsa->maxDepthBounds;
1353bf215546Sopenharmony_ci   desc->DepthBoundsTestEnable = in_zsa->depthBoundsTestEnable;
1354bf215546Sopenharmony_ci   desc->StencilEnable = in_zsa->stencilTestEnable;
1355bf215546Sopenharmony_ci   if (in_zsa->stencilTestEnable) {
1356bf215546Sopenharmony_ci      desc->FrontFace.StencilFailOp =
1357bf215546Sopenharmony_ci        translate_stencil_op(in_zsa->front.failOp);
1358bf215546Sopenharmony_ci      desc->FrontFace.StencilDepthFailOp =
1359bf215546Sopenharmony_ci        translate_stencil_op(in_zsa->front.depthFailOp);
1360bf215546Sopenharmony_ci      desc->FrontFace.StencilPassOp =
1361bf215546Sopenharmony_ci        translate_stencil_op(in_zsa->front.passOp);
1362bf215546Sopenharmony_ci      desc->FrontFace.StencilFunc =
1363bf215546Sopenharmony_ci        dzn_translate_compare_op(in_zsa->front.compareOp);
1364bf215546Sopenharmony_ci      desc->BackFace.StencilFailOp =
1365bf215546Sopenharmony_ci        translate_stencil_op(in_zsa->back.failOp);
1366bf215546Sopenharmony_ci      desc->BackFace.StencilDepthFailOp =
1367bf215546Sopenharmony_ci        translate_stencil_op(in_zsa->back.depthFailOp);
1368bf215546Sopenharmony_ci      desc->BackFace.StencilPassOp =
1369bf215546Sopenharmony_ci        translate_stencil_op(in_zsa->back.passOp);
1370bf215546Sopenharmony_ci      desc->BackFace.StencilFunc =
1371bf215546Sopenharmony_ci        dzn_translate_compare_op(in_zsa->back.compareOp);
1372bf215546Sopenharmony_ci
1373bf215546Sopenharmony_ci      pipeline->zsa.stencil_test.enable = true;
1374bf215546Sopenharmony_ci
1375bf215546Sopenharmony_ci      translate_stencil_test(pipeline, desc, in);
1376bf215546Sopenharmony_ci   }
1377bf215546Sopenharmony_ci}
1378bf215546Sopenharmony_ci
1379bf215546Sopenharmony_cistatic D3D12_BLEND
1380bf215546Sopenharmony_citranslate_blend_factor(VkBlendFactor in, bool is_alpha)
1381bf215546Sopenharmony_ci{
1382bf215546Sopenharmony_ci   switch (in) {
1383bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ZERO: return D3D12_BLEND_ZERO;
1384bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE: return D3D12_BLEND_ONE;
1385bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC_COLOR:
1386bf215546Sopenharmony_ci      return is_alpha ? D3D12_BLEND_SRC_ALPHA : D3D12_BLEND_SRC_COLOR;
1387bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
1388bf215546Sopenharmony_ci      return is_alpha ? D3D12_BLEND_INV_SRC_ALPHA : D3D12_BLEND_INV_SRC_COLOR;
1389bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_DST_COLOR:
1390bf215546Sopenharmony_ci      return is_alpha ? D3D12_BLEND_DEST_ALPHA : D3D12_BLEND_DEST_COLOR;
1391bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
1392bf215546Sopenharmony_ci      return is_alpha ? D3D12_BLEND_INV_DEST_ALPHA : D3D12_BLEND_INV_DEST_COLOR;
1393bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC_ALPHA: return D3D12_BLEND_SRC_ALPHA;
1394bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: return D3D12_BLEND_INV_SRC_ALPHA;
1395bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_DST_ALPHA: return D3D12_BLEND_DEST_ALPHA;
1396bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: return D3D12_BLEND_INV_DEST_ALPHA;
1397bf215546Sopenharmony_ci   /* FIXME: no way to isolate the alpla and color constants */
1398bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_CONSTANT_COLOR:
1399bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_CONSTANT_ALPHA:
1400bf215546Sopenharmony_ci      return D3D12_BLEND_BLEND_FACTOR;
1401bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
1402bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
1403bf215546Sopenharmony_ci      return D3D12_BLEND_INV_BLEND_FACTOR;
1404bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC1_COLOR:
1405bf215546Sopenharmony_ci      return is_alpha ? D3D12_BLEND_SRC1_ALPHA : D3D12_BLEND_SRC1_COLOR;
1406bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR:
1407bf215546Sopenharmony_ci      return is_alpha ? D3D12_BLEND_INV_SRC1_ALPHA : D3D12_BLEND_INV_SRC1_COLOR;
1408bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC1_ALPHA: return D3D12_BLEND_SRC1_ALPHA;
1409bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA: return D3D12_BLEND_INV_SRC1_ALPHA;
1410bf215546Sopenharmony_ci   case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE: return D3D12_BLEND_SRC_ALPHA_SAT;
1411bf215546Sopenharmony_ci   default: unreachable("Invalid blend factor");
1412bf215546Sopenharmony_ci   }
1413bf215546Sopenharmony_ci}
1414bf215546Sopenharmony_ci
1415bf215546Sopenharmony_cistatic D3D12_BLEND_OP
1416bf215546Sopenharmony_citranslate_blend_op(VkBlendOp in)
1417bf215546Sopenharmony_ci{
1418bf215546Sopenharmony_ci   switch (in) {
1419bf215546Sopenharmony_ci   case VK_BLEND_OP_ADD: return D3D12_BLEND_OP_ADD;
1420bf215546Sopenharmony_ci   case VK_BLEND_OP_SUBTRACT: return D3D12_BLEND_OP_SUBTRACT;
1421bf215546Sopenharmony_ci   case VK_BLEND_OP_REVERSE_SUBTRACT: return D3D12_BLEND_OP_REV_SUBTRACT;
1422bf215546Sopenharmony_ci   case VK_BLEND_OP_MIN: return D3D12_BLEND_OP_MIN;
1423bf215546Sopenharmony_ci   case VK_BLEND_OP_MAX: return D3D12_BLEND_OP_MAX;
1424bf215546Sopenharmony_ci   default: unreachable("Invalid blend op");
1425bf215546Sopenharmony_ci   }
1426bf215546Sopenharmony_ci}
1427bf215546Sopenharmony_ci
1428bf215546Sopenharmony_cistatic D3D12_LOGIC_OP
1429bf215546Sopenharmony_citranslate_logic_op(VkLogicOp in)
1430bf215546Sopenharmony_ci{
1431bf215546Sopenharmony_ci   switch (in) {
1432bf215546Sopenharmony_ci   case VK_LOGIC_OP_CLEAR: return D3D12_LOGIC_OP_CLEAR;
1433bf215546Sopenharmony_ci   case VK_LOGIC_OP_AND: return D3D12_LOGIC_OP_AND;
1434bf215546Sopenharmony_ci   case VK_LOGIC_OP_AND_REVERSE: return D3D12_LOGIC_OP_AND_REVERSE;
1435bf215546Sopenharmony_ci   case VK_LOGIC_OP_COPY: return D3D12_LOGIC_OP_COPY;
1436bf215546Sopenharmony_ci   case VK_LOGIC_OP_AND_INVERTED: return D3D12_LOGIC_OP_AND_INVERTED;
1437bf215546Sopenharmony_ci   case VK_LOGIC_OP_NO_OP: return D3D12_LOGIC_OP_NOOP;
1438bf215546Sopenharmony_ci   case VK_LOGIC_OP_XOR: return D3D12_LOGIC_OP_XOR;
1439bf215546Sopenharmony_ci   case VK_LOGIC_OP_OR: return D3D12_LOGIC_OP_OR;
1440bf215546Sopenharmony_ci   case VK_LOGIC_OP_NOR: return D3D12_LOGIC_OP_NOR;
1441bf215546Sopenharmony_ci   case VK_LOGIC_OP_EQUIVALENT: return D3D12_LOGIC_OP_EQUIV;
1442bf215546Sopenharmony_ci   case VK_LOGIC_OP_INVERT: return D3D12_LOGIC_OP_INVERT;
1443bf215546Sopenharmony_ci   case VK_LOGIC_OP_OR_REVERSE: return D3D12_LOGIC_OP_OR_REVERSE;
1444bf215546Sopenharmony_ci   case VK_LOGIC_OP_COPY_INVERTED: return D3D12_LOGIC_OP_COPY_INVERTED;
1445bf215546Sopenharmony_ci   case VK_LOGIC_OP_OR_INVERTED: return D3D12_LOGIC_OP_OR_INVERTED;
1446bf215546Sopenharmony_ci   case VK_LOGIC_OP_NAND: return D3D12_LOGIC_OP_NAND;
1447bf215546Sopenharmony_ci   case VK_LOGIC_OP_SET: return D3D12_LOGIC_OP_SET;
1448bf215546Sopenharmony_ci   default: unreachable("Invalid logic op");
1449bf215546Sopenharmony_ci   }
1450bf215546Sopenharmony_ci}
1451bf215546Sopenharmony_ci
1452bf215546Sopenharmony_cistatic void
1453bf215546Sopenharmony_cidzn_graphics_pipeline_translate_blend(struct dzn_graphics_pipeline *pipeline,
1454bf215546Sopenharmony_ci                                      D3D12_PIPELINE_STATE_STREAM_DESC *out,
1455bf215546Sopenharmony_ci                                      const VkGraphicsPipelineCreateInfo *in)
1456bf215546Sopenharmony_ci{
1457bf215546Sopenharmony_ci   const VkPipelineRasterizationStateCreateInfo *in_rast =
1458bf215546Sopenharmony_ci      in->pRasterizationState;
1459bf215546Sopenharmony_ci   const VkPipelineColorBlendStateCreateInfo *in_blend =
1460bf215546Sopenharmony_ci      in_rast->rasterizerDiscardEnable ? NULL : in->pColorBlendState;
1461bf215546Sopenharmony_ci   const VkPipelineMultisampleStateCreateInfo *in_ms =
1462bf215546Sopenharmony_ci      in_rast->rasterizerDiscardEnable ? NULL : in->pMultisampleState;
1463bf215546Sopenharmony_ci
1464bf215546Sopenharmony_ci   if (!in_blend || !in_ms)
1465bf215546Sopenharmony_ci      return;
1466bf215546Sopenharmony_ci
1467bf215546Sopenharmony_ci   d3d12_gfx_pipeline_state_stream_new_desc(out, BLEND, D3D12_BLEND_DESC, desc);
1468bf215546Sopenharmony_ci   D3D12_LOGIC_OP logicop =
1469bf215546Sopenharmony_ci      in_blend->logicOpEnable ?
1470bf215546Sopenharmony_ci      translate_logic_op(in_blend->logicOp) : D3D12_LOGIC_OP_NOOP;
1471bf215546Sopenharmony_ci   desc->AlphaToCoverageEnable = in_ms->alphaToCoverageEnable;
1472bf215546Sopenharmony_ci   memcpy(pipeline->blend.constants, in_blend->blendConstants,
1473bf215546Sopenharmony_ci          sizeof(pipeline->blend.constants));
1474bf215546Sopenharmony_ci
1475bf215546Sopenharmony_ci   for (uint32_t i = 0; i < in_blend->attachmentCount; i++) {
1476bf215546Sopenharmony_ci      if (i > 0 &&
1477bf215546Sopenharmony_ci          !memcmp(&in_blend->pAttachments[i - 1], &in_blend->pAttachments[i],
1478bf215546Sopenharmony_ci                  sizeof(*in_blend->pAttachments)))
1479bf215546Sopenharmony_ci         desc->IndependentBlendEnable = true;
1480bf215546Sopenharmony_ci
1481bf215546Sopenharmony_ci      desc->RenderTarget[i].BlendEnable =
1482bf215546Sopenharmony_ci         in_blend->pAttachments[i].blendEnable;
1483bf215546Sopenharmony_ci      desc->RenderTarget[i].RenderTargetWriteMask =
1484bf215546Sopenharmony_ci         in_blend->pAttachments[i].colorWriteMask;
1485bf215546Sopenharmony_ci
1486bf215546Sopenharmony_ci      if (in_blend->logicOpEnable) {
1487bf215546Sopenharmony_ci         desc->RenderTarget[i].LogicOpEnable = true;
1488bf215546Sopenharmony_ci         desc->RenderTarget[i].LogicOp = logicop;
1489bf215546Sopenharmony_ci      } else {
1490bf215546Sopenharmony_ci         desc->RenderTarget[i].SrcBlend =
1491bf215546Sopenharmony_ci            translate_blend_factor(in_blend->pAttachments[i].srcColorBlendFactor, false);
1492bf215546Sopenharmony_ci         desc->RenderTarget[i].DestBlend =
1493bf215546Sopenharmony_ci            translate_blend_factor(in_blend->pAttachments[i].dstColorBlendFactor, false);
1494bf215546Sopenharmony_ci         desc->RenderTarget[i].BlendOp =
1495bf215546Sopenharmony_ci            translate_blend_op(in_blend->pAttachments[i].colorBlendOp);
1496bf215546Sopenharmony_ci         desc->RenderTarget[i].SrcBlendAlpha =
1497bf215546Sopenharmony_ci            translate_blend_factor(in_blend->pAttachments[i].srcAlphaBlendFactor, true);
1498bf215546Sopenharmony_ci         desc->RenderTarget[i].DestBlendAlpha =
1499bf215546Sopenharmony_ci            translate_blend_factor(in_blend->pAttachments[i].dstAlphaBlendFactor, true);
1500bf215546Sopenharmony_ci         desc->RenderTarget[i].BlendOpAlpha =
1501bf215546Sopenharmony_ci            translate_blend_op(in_blend->pAttachments[i].alphaBlendOp);
1502bf215546Sopenharmony_ci      }
1503bf215546Sopenharmony_ci   }
1504bf215546Sopenharmony_ci}
1505bf215546Sopenharmony_ci
1506bf215546Sopenharmony_ci
1507bf215546Sopenharmony_cistatic void
1508bf215546Sopenharmony_cidzn_pipeline_init(struct dzn_pipeline *pipeline,
1509bf215546Sopenharmony_ci                  struct dzn_device *device,
1510bf215546Sopenharmony_ci                  VkPipelineBindPoint type,
1511bf215546Sopenharmony_ci                  struct dzn_pipeline_layout *layout,
1512bf215546Sopenharmony_ci                  D3D12_PIPELINE_STATE_STREAM_DESC *stream_desc)
1513bf215546Sopenharmony_ci{
1514bf215546Sopenharmony_ci   pipeline->type = type;
1515bf215546Sopenharmony_ci   pipeline->root.sets_param_count = layout->root.sets_param_count;
1516bf215546Sopenharmony_ci   pipeline->root.sysval_cbv_param_idx = layout->root.sysval_cbv_param_idx;
1517bf215546Sopenharmony_ci   pipeline->root.push_constant_cbv_param_idx = layout->root.push_constant_cbv_param_idx;
1518bf215546Sopenharmony_ci   STATIC_ASSERT(sizeof(pipeline->root.type) == sizeof(layout->root.type));
1519bf215546Sopenharmony_ci   memcpy(pipeline->root.type, layout->root.type, sizeof(pipeline->root.type));
1520bf215546Sopenharmony_ci   pipeline->root.sig = layout->root.sig;
1521bf215546Sopenharmony_ci   ID3D12RootSignature_AddRef(pipeline->root.sig);
1522bf215546Sopenharmony_ci
1523bf215546Sopenharmony_ci   STATIC_ASSERT(sizeof(layout->desc_count) == sizeof(pipeline->desc_count));
1524bf215546Sopenharmony_ci   memcpy(pipeline->desc_count, layout->desc_count, sizeof(pipeline->desc_count));
1525bf215546Sopenharmony_ci
1526bf215546Sopenharmony_ci   STATIC_ASSERT(sizeof(layout->sets) == sizeof(pipeline->sets));
1527bf215546Sopenharmony_ci   memcpy(pipeline->sets, layout->sets, sizeof(pipeline->sets));
1528bf215546Sopenharmony_ci   vk_object_base_init(&device->vk, &pipeline->base, VK_OBJECT_TYPE_PIPELINE);
1529bf215546Sopenharmony_ci
1530bf215546Sopenharmony_ci   ASSERTED uint32_t max_streamsz =
1531bf215546Sopenharmony_ci      type == VK_PIPELINE_BIND_POINT_GRAPHICS ?
1532bf215546Sopenharmony_ci      MAX_GFX_PIPELINE_STATE_STREAM_SIZE :
1533bf215546Sopenharmony_ci      MAX_COMPUTE_PIPELINE_STATE_STREAM_SIZE;
1534bf215546Sopenharmony_ci
1535bf215546Sopenharmony_ci   d3d12_pipeline_state_stream_new_desc(stream_desc, max_streamsz, ROOT_SIGNATURE,
1536bf215546Sopenharmony_ci                                        ID3D12RootSignature *, root_sig);
1537bf215546Sopenharmony_ci   *root_sig = pipeline->root.sig;
1538bf215546Sopenharmony_ci}
1539bf215546Sopenharmony_ci
1540bf215546Sopenharmony_cistatic void
1541bf215546Sopenharmony_cidzn_pipeline_finish(struct dzn_pipeline *pipeline)
1542bf215546Sopenharmony_ci{
1543bf215546Sopenharmony_ci   if (pipeline->state)
1544bf215546Sopenharmony_ci      ID3D12PipelineState_Release(pipeline->state);
1545bf215546Sopenharmony_ci   if (pipeline->root.sig)
1546bf215546Sopenharmony_ci      ID3D12RootSignature_Release(pipeline->root.sig);
1547bf215546Sopenharmony_ci
1548bf215546Sopenharmony_ci   vk_object_base_finish(&pipeline->base);
1549bf215546Sopenharmony_ci}
1550bf215546Sopenharmony_ci
1551bf215546Sopenharmony_cistatic void dzn_graphics_pipeline_delete_variant(struct hash_entry *he)
1552bf215546Sopenharmony_ci{
1553bf215546Sopenharmony_ci   struct dzn_graphics_pipeline_variant *variant = he->data;
1554bf215546Sopenharmony_ci
1555bf215546Sopenharmony_ci   if (variant->state)
1556bf215546Sopenharmony_ci      ID3D12PipelineState_Release(variant->state);
1557bf215546Sopenharmony_ci}
1558bf215546Sopenharmony_ci
1559bf215546Sopenharmony_cistatic void
1560bf215546Sopenharmony_cidzn_graphics_pipeline_cleanup_nir_shaders(struct dzn_graphics_pipeline *pipeline)
1561bf215546Sopenharmony_ci{
1562bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(pipeline->templates.shaders); i++) {
1563bf215546Sopenharmony_ci      ralloc_free(pipeline->templates.shaders[i].nir);
1564bf215546Sopenharmony_ci      pipeline->templates.shaders[i].nir = NULL;
1565bf215546Sopenharmony_ci   }
1566bf215546Sopenharmony_ci}
1567bf215546Sopenharmony_ci
1568bf215546Sopenharmony_cistatic void
1569bf215546Sopenharmony_cidzn_graphics_pipeline_cleanup_dxil_shaders(struct dzn_graphics_pipeline *pipeline)
1570bf215546Sopenharmony_ci{
1571bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(pipeline->templates.shaders); i++) {
1572bf215546Sopenharmony_ci      if (pipeline->templates.shaders[i].bc) {
1573bf215546Sopenharmony_ci         free((void *)pipeline->templates.shaders[i].bc->pShaderBytecode);
1574bf215546Sopenharmony_ci         pipeline->templates.shaders[i].bc = NULL;
1575bf215546Sopenharmony_ci      }
1576bf215546Sopenharmony_ci   }
1577bf215546Sopenharmony_ci}
1578bf215546Sopenharmony_ci
1579bf215546Sopenharmony_cistatic void
1580bf215546Sopenharmony_cidzn_graphics_pipeline_destroy(struct dzn_graphics_pipeline *pipeline,
1581bf215546Sopenharmony_ci                              const VkAllocationCallbacks *alloc)
1582bf215546Sopenharmony_ci{
1583bf215546Sopenharmony_ci   if (!pipeline)
1584bf215546Sopenharmony_ci      return;
1585bf215546Sopenharmony_ci
1586bf215546Sopenharmony_ci   _mesa_hash_table_destroy(pipeline->variants,
1587bf215546Sopenharmony_ci                            dzn_graphics_pipeline_delete_variant);
1588bf215546Sopenharmony_ci
1589bf215546Sopenharmony_ci   dzn_graphics_pipeline_cleanup_nir_shaders(pipeline);
1590bf215546Sopenharmony_ci   dzn_graphics_pipeline_cleanup_dxil_shaders(pipeline);
1591bf215546Sopenharmony_ci
1592bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(pipeline->indirect_cmd_sigs); i++) {
1593bf215546Sopenharmony_ci      if (pipeline->indirect_cmd_sigs[i])
1594bf215546Sopenharmony_ci         ID3D12CommandSignature_Release(pipeline->indirect_cmd_sigs[i]);
1595bf215546Sopenharmony_ci   }
1596bf215546Sopenharmony_ci
1597bf215546Sopenharmony_ci   dzn_pipeline_finish(&pipeline->base);
1598bf215546Sopenharmony_ci   vk_free2(&pipeline->base.base.device->alloc, alloc, pipeline);
1599bf215546Sopenharmony_ci}
1600bf215546Sopenharmony_ci
1601bf215546Sopenharmony_cistatic VkResult
1602bf215546Sopenharmony_cidzn_graphics_pipeline_create(struct dzn_device *device,
1603bf215546Sopenharmony_ci                             VkPipelineCache cache,
1604bf215546Sopenharmony_ci                             const VkGraphicsPipelineCreateInfo *pCreateInfo,
1605bf215546Sopenharmony_ci                             const VkAllocationCallbacks *pAllocator,
1606bf215546Sopenharmony_ci                             VkPipeline *out)
1607bf215546Sopenharmony_ci{
1608bf215546Sopenharmony_ci   const VkPipelineRenderingCreateInfo *ri = (const VkPipelineRenderingCreateInfo *)
1609bf215546Sopenharmony_ci      vk_find_struct_const(pCreateInfo, PIPELINE_RENDERING_CREATE_INFO);
1610bf215546Sopenharmony_ci   VK_FROM_HANDLE(vk_pipeline_cache, pcache, cache);
1611bf215546Sopenharmony_ci   VK_FROM_HANDLE(vk_render_pass, pass, pCreateInfo->renderPass);
1612bf215546Sopenharmony_ci   VK_FROM_HANDLE(dzn_pipeline_layout, layout, pCreateInfo->layout);
1613bf215546Sopenharmony_ci   uint32_t color_count = 0;
1614bf215546Sopenharmony_ci   VkFormat color_fmts[MAX_RTS] = { 0 };
1615bf215546Sopenharmony_ci   VkFormat zs_fmt = VK_FORMAT_UNDEFINED;
1616bf215546Sopenharmony_ci   VkResult ret;
1617bf215546Sopenharmony_ci   HRESULT hres = 0;
1618bf215546Sopenharmony_ci
1619bf215546Sopenharmony_ci   struct dzn_graphics_pipeline *pipeline =
1620bf215546Sopenharmony_ci      vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*pipeline), 8,
1621bf215546Sopenharmony_ci                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1622bf215546Sopenharmony_ci   if (!pipeline)
1623bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1624bf215546Sopenharmony_ci
1625bf215546Sopenharmony_ci   D3D12_PIPELINE_STATE_STREAM_DESC *stream_desc = &pipeline->templates.stream_desc;
1626bf215546Sopenharmony_ci   stream_desc->pPipelineStateSubobjectStream = pipeline->templates.stream_buf;
1627bf215546Sopenharmony_ci
1628bf215546Sopenharmony_ci   dzn_pipeline_init(&pipeline->base, device,
1629bf215546Sopenharmony_ci                     VK_PIPELINE_BIND_POINT_GRAPHICS,
1630bf215546Sopenharmony_ci                     layout, stream_desc);
1631bf215546Sopenharmony_ci   D3D12_INPUT_ELEMENT_DESC attribs[MAX_VERTEX_GENERIC_ATTRIBS] = { 0 };
1632bf215546Sopenharmony_ci   enum pipe_format vi_conversions[MAX_VERTEX_GENERIC_ATTRIBS] = { 0 };
1633bf215546Sopenharmony_ci
1634bf215546Sopenharmony_ci   ret = dzn_graphics_pipeline_translate_vi(pipeline, pCreateInfo,
1635bf215546Sopenharmony_ci                                            attribs, vi_conversions);
1636bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
1637bf215546Sopenharmony_ci      goto out;
1638bf215546Sopenharmony_ci
1639bf215546Sopenharmony_ci   if (pCreateInfo->pDynamicState) {
1640bf215546Sopenharmony_ci      for (uint32_t i = 0; i < pCreateInfo->pDynamicState->dynamicStateCount; i++) {
1641bf215546Sopenharmony_ci         switch (pCreateInfo->pDynamicState->pDynamicStates[i]) {
1642bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_VIEWPORT:
1643bf215546Sopenharmony_ci            pipeline->vp.dynamic = true;
1644bf215546Sopenharmony_ci            break;
1645bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_SCISSOR:
1646bf215546Sopenharmony_ci            pipeline->scissor.dynamic = true;
1647bf215546Sopenharmony_ci            break;
1648bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
1649bf215546Sopenharmony_ci            pipeline->zsa.stencil_test.dynamic_ref = true;
1650bf215546Sopenharmony_ci            break;
1651bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
1652bf215546Sopenharmony_ci            pipeline->zsa.stencil_test.dynamic_compare_mask = true;
1653bf215546Sopenharmony_ci            break;
1654bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
1655bf215546Sopenharmony_ci            pipeline->zsa.stencil_test.dynamic_write_mask = true;
1656bf215546Sopenharmony_ci            break;
1657bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
1658bf215546Sopenharmony_ci            pipeline->blend.dynamic_constants = true;
1659bf215546Sopenharmony_ci            break;
1660bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
1661bf215546Sopenharmony_ci            pipeline->zsa.depth_bounds.dynamic = true;
1662bf215546Sopenharmony_ci            break;
1663bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_DEPTH_BIAS:
1664bf215546Sopenharmony_ci            pipeline->zsa.dynamic_depth_bias = true;
1665bf215546Sopenharmony_ci            ret = dzn_graphics_pipeline_prepare_for_variants(device, pipeline);
1666bf215546Sopenharmony_ci            if (ret)
1667bf215546Sopenharmony_ci               goto out;
1668bf215546Sopenharmony_ci            break;
1669bf215546Sopenharmony_ci         case VK_DYNAMIC_STATE_LINE_WIDTH:
1670bf215546Sopenharmony_ci            /* Nothing to do since we just support lineWidth = 1. */
1671bf215546Sopenharmony_ci            break;
1672bf215546Sopenharmony_ci         default: unreachable("Unsupported dynamic state");
1673bf215546Sopenharmony_ci         }
1674bf215546Sopenharmony_ci      }
1675bf215546Sopenharmony_ci   }
1676bf215546Sopenharmony_ci
1677bf215546Sopenharmony_ci   ret = dzn_graphics_pipeline_translate_ia(device, pipeline, stream_desc, pCreateInfo);
1678bf215546Sopenharmony_ci   if (ret)
1679bf215546Sopenharmony_ci      goto out;
1680bf215546Sopenharmony_ci
1681bf215546Sopenharmony_ci   dzn_graphics_pipeline_translate_rast(pipeline, stream_desc, pCreateInfo);
1682bf215546Sopenharmony_ci   dzn_graphics_pipeline_translate_ms(pipeline, stream_desc, pCreateInfo);
1683bf215546Sopenharmony_ci   dzn_graphics_pipeline_translate_zsa(pipeline, stream_desc, pCreateInfo);
1684bf215546Sopenharmony_ci   dzn_graphics_pipeline_translate_blend(pipeline, stream_desc, pCreateInfo);
1685bf215546Sopenharmony_ci
1686bf215546Sopenharmony_ci   if (pass) {
1687bf215546Sopenharmony_ci      const struct vk_subpass *subpass = &pass->subpasses[pCreateInfo->subpass];
1688bf215546Sopenharmony_ci      color_count = subpass->color_count;
1689bf215546Sopenharmony_ci      for (uint32_t i = 0; i < subpass->color_count; i++) {
1690bf215546Sopenharmony_ci         uint32_t idx = subpass->color_attachments[i].attachment;
1691bf215546Sopenharmony_ci
1692bf215546Sopenharmony_ci         if (idx == VK_ATTACHMENT_UNUSED) continue;
1693bf215546Sopenharmony_ci
1694bf215546Sopenharmony_ci         const struct vk_render_pass_attachment *attachment =
1695bf215546Sopenharmony_ci            &pass->attachments[idx];
1696bf215546Sopenharmony_ci
1697bf215546Sopenharmony_ci         color_fmts[i] = attachment->format;
1698bf215546Sopenharmony_ci      }
1699bf215546Sopenharmony_ci
1700bf215546Sopenharmony_ci      if (subpass->depth_stencil_attachment &&
1701bf215546Sopenharmony_ci          subpass->depth_stencil_attachment->attachment != VK_ATTACHMENT_UNUSED) {
1702bf215546Sopenharmony_ci         const struct vk_render_pass_attachment *attachment =
1703bf215546Sopenharmony_ci            &pass->attachments[subpass->depth_stencil_attachment->attachment];
1704bf215546Sopenharmony_ci
1705bf215546Sopenharmony_ci         zs_fmt = attachment->format;
1706bf215546Sopenharmony_ci      }
1707bf215546Sopenharmony_ci   } else if (ri) {
1708bf215546Sopenharmony_ci      color_count = ri->colorAttachmentCount;
1709bf215546Sopenharmony_ci      memcpy(color_fmts, ri->pColorAttachmentFormats,
1710bf215546Sopenharmony_ci             sizeof(color_fmts[0]) * color_count);
1711bf215546Sopenharmony_ci      if (ri->depthAttachmentFormat != VK_FORMAT_UNDEFINED)
1712bf215546Sopenharmony_ci         zs_fmt = ri->depthAttachmentFormat;
1713bf215546Sopenharmony_ci      else if (ri->stencilAttachmentFormat != VK_FORMAT_UNDEFINED)
1714bf215546Sopenharmony_ci         zs_fmt = ri->stencilAttachmentFormat;
1715bf215546Sopenharmony_ci   }
1716bf215546Sopenharmony_ci
1717bf215546Sopenharmony_ci   if (color_count > 0) {
1718bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream_desc, RENDER_TARGET_FORMATS, struct D3D12_RT_FORMAT_ARRAY, rts);
1719bf215546Sopenharmony_ci      rts->NumRenderTargets = color_count;
1720bf215546Sopenharmony_ci      for (uint32_t i = 0; i < color_count; i++) {
1721bf215546Sopenharmony_ci         rts->RTFormats[i] =
1722bf215546Sopenharmony_ci            dzn_image_get_dxgi_format(color_fmts[i],
1723bf215546Sopenharmony_ci                                      VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1724bf215546Sopenharmony_ci                                      VK_IMAGE_ASPECT_COLOR_BIT);
1725bf215546Sopenharmony_ci      }
1726bf215546Sopenharmony_ci   }
1727bf215546Sopenharmony_ci
1728bf215546Sopenharmony_ci   if (zs_fmt != VK_FORMAT_UNDEFINED) {
1729bf215546Sopenharmony_ci      d3d12_gfx_pipeline_state_stream_new_desc(stream_desc, DEPTH_STENCIL_FORMAT, DXGI_FORMAT, ds_fmt);
1730bf215546Sopenharmony_ci      *ds_fmt =
1731bf215546Sopenharmony_ci         dzn_image_get_dxgi_format(zs_fmt,
1732bf215546Sopenharmony_ci                                   VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
1733bf215546Sopenharmony_ci                                   VK_IMAGE_ASPECT_DEPTH_BIT |
1734bf215546Sopenharmony_ci                                   VK_IMAGE_ASPECT_STENCIL_BIT);
1735bf215546Sopenharmony_ci   }
1736bf215546Sopenharmony_ci
1737bf215546Sopenharmony_ci   ret = dzn_graphics_pipeline_compile_shaders(device, pipeline, pcache,
1738bf215546Sopenharmony_ci                                               layout, stream_desc,
1739bf215546Sopenharmony_ci                                               attribs, vi_conversions,
1740bf215546Sopenharmony_ci                                               pCreateInfo);
1741bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
1742bf215546Sopenharmony_ci      goto out;
1743bf215546Sopenharmony_ci
1744bf215546Sopenharmony_ci   if (!pipeline->variants) {
1745bf215546Sopenharmony_ci      hres = ID3D12Device2_CreatePipelineState(device->dev, stream_desc,
1746bf215546Sopenharmony_ci                                               &IID_ID3D12PipelineState,
1747bf215546Sopenharmony_ci                                               (void **)&pipeline->base.state);
1748bf215546Sopenharmony_ci      if (FAILED(hres)) {
1749bf215546Sopenharmony_ci         ret = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1750bf215546Sopenharmony_ci         goto out;
1751bf215546Sopenharmony_ci      }
1752bf215546Sopenharmony_ci
1753bf215546Sopenharmony_ci      dzn_graphics_pipeline_cleanup_dxil_shaders(pipeline);
1754bf215546Sopenharmony_ci   }
1755bf215546Sopenharmony_ci
1756bf215546Sopenharmony_ci   dzn_graphics_pipeline_cleanup_nir_shaders(pipeline);
1757bf215546Sopenharmony_ci   ret = VK_SUCCESS;
1758bf215546Sopenharmony_ci
1759bf215546Sopenharmony_ciout:
1760bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
1761bf215546Sopenharmony_ci      dzn_graphics_pipeline_destroy(pipeline, pAllocator);
1762bf215546Sopenharmony_ci   else
1763bf215546Sopenharmony_ci      *out = dzn_graphics_pipeline_to_handle(pipeline);
1764bf215546Sopenharmony_ci
1765bf215546Sopenharmony_ci   return ret;
1766bf215546Sopenharmony_ci}
1767bf215546Sopenharmony_ci
1768bf215546Sopenharmony_ciID3D12PipelineState *
1769bf215546Sopenharmony_cidzn_graphics_pipeline_get_state(struct dzn_graphics_pipeline *pipeline,
1770bf215546Sopenharmony_ci                                const struct dzn_graphics_pipeline_variant_key *key)
1771bf215546Sopenharmony_ci{
1772bf215546Sopenharmony_ci   if (!pipeline->variants)
1773bf215546Sopenharmony_ci      return pipeline->base.state;
1774bf215546Sopenharmony_ci
1775bf215546Sopenharmony_ci   struct dzn_graphics_pipeline_variant_key masked_key = { 0 };
1776bf215546Sopenharmony_ci
1777bf215546Sopenharmony_ci   if (dzn_graphics_pipeline_get_desc_template(pipeline, ib_strip_cut))
1778bf215546Sopenharmony_ci      masked_key.ib_strip_cut = key->ib_strip_cut;
1779bf215546Sopenharmony_ci
1780bf215546Sopenharmony_ci   if (dzn_graphics_pipeline_get_desc_template(pipeline, rast) &&
1781bf215546Sopenharmony_ci       pipeline->zsa.dynamic_depth_bias)
1782bf215546Sopenharmony_ci      masked_key.depth_bias = key->depth_bias;
1783bf215546Sopenharmony_ci
1784bf215546Sopenharmony_ci   const D3D12_DEPTH_STENCIL_DESC1 *ds_templ =
1785bf215546Sopenharmony_ci      dzn_graphics_pipeline_get_desc_template(pipeline, ds);
1786bf215546Sopenharmony_ci   if (ds_templ && ds_templ->StencilEnable) {
1787bf215546Sopenharmony_ci      if (ds_templ->FrontFace.StencilFunc != D3D12_COMPARISON_FUNC_NEVER &&
1788bf215546Sopenharmony_ci         ds_templ->FrontFace.StencilFunc != D3D12_COMPARISON_FUNC_ALWAYS)
1789bf215546Sopenharmony_ci         masked_key.stencil_test.front.compare_mask = key->stencil_test.front.compare_mask;
1790bf215546Sopenharmony_ci      if (ds_templ->BackFace.StencilFunc != D3D12_COMPARISON_FUNC_NEVER &&
1791bf215546Sopenharmony_ci          ds_templ->BackFace.StencilFunc != D3D12_COMPARISON_FUNC_ALWAYS)
1792bf215546Sopenharmony_ci         masked_key.stencil_test.back.compare_mask = key->stencil_test.back.compare_mask;
1793bf215546Sopenharmony_ci      if (pipeline->zsa.stencil_test.dynamic_write_mask) {
1794bf215546Sopenharmony_ci         masked_key.stencil_test.front.write_mask = key->stencil_test.front.write_mask;
1795bf215546Sopenharmony_ci         masked_key.stencil_test.back.write_mask = key->stencil_test.back.write_mask;
1796bf215546Sopenharmony_ci      }
1797bf215546Sopenharmony_ci   }
1798bf215546Sopenharmony_ci
1799bf215546Sopenharmony_ci   struct dzn_device *device =
1800bf215546Sopenharmony_ci      container_of(pipeline->base.base.device, struct dzn_device, vk);
1801bf215546Sopenharmony_ci   struct hash_entry *he =
1802bf215546Sopenharmony_ci      _mesa_hash_table_search(pipeline->variants, &masked_key);
1803bf215546Sopenharmony_ci
1804bf215546Sopenharmony_ci   struct dzn_graphics_pipeline_variant *variant;
1805bf215546Sopenharmony_ci
1806bf215546Sopenharmony_ci   if (!he) {
1807bf215546Sopenharmony_ci      variant = rzalloc(pipeline->variants, struct dzn_graphics_pipeline_variant);
1808bf215546Sopenharmony_ci      variant->key = masked_key;
1809bf215546Sopenharmony_ci
1810bf215546Sopenharmony_ci      uintptr_t stream_buf[MAX_GFX_PIPELINE_STATE_STREAM_SIZE / sizeof(uintptr_t)];
1811bf215546Sopenharmony_ci      D3D12_PIPELINE_STATE_STREAM_DESC stream_desc = {
1812bf215546Sopenharmony_ci         .SizeInBytes = pipeline->templates.stream_desc.SizeInBytes,
1813bf215546Sopenharmony_ci         .pPipelineStateSubobjectStream = stream_buf,
1814bf215546Sopenharmony_ci      };
1815bf215546Sopenharmony_ci
1816bf215546Sopenharmony_ci      memcpy(stream_buf, pipeline->templates.stream_buf, stream_desc.SizeInBytes);
1817bf215546Sopenharmony_ci
1818bf215546Sopenharmony_ci      D3D12_INDEX_BUFFER_STRIP_CUT_VALUE *ib_strip_cut =
1819bf215546Sopenharmony_ci         dzn_graphics_pipeline_get_desc(pipeline, stream_buf, ib_strip_cut);
1820bf215546Sopenharmony_ci      if (ib_strip_cut)
1821bf215546Sopenharmony_ci         *ib_strip_cut = masked_key.ib_strip_cut;
1822bf215546Sopenharmony_ci
1823bf215546Sopenharmony_ci      D3D12_RASTERIZER_DESC *rast =
1824bf215546Sopenharmony_ci         dzn_graphics_pipeline_get_desc(pipeline, stream_buf, rast);
1825bf215546Sopenharmony_ci      if (rast && pipeline->zsa.dynamic_depth_bias) {
1826bf215546Sopenharmony_ci         rast->DepthBias = translate_depth_bias(masked_key.depth_bias.constant_factor);
1827bf215546Sopenharmony_ci         rast->DepthBiasClamp = masked_key.depth_bias.clamp;
1828bf215546Sopenharmony_ci         rast->SlopeScaledDepthBias = masked_key.depth_bias.slope_factor;
1829bf215546Sopenharmony_ci      }
1830bf215546Sopenharmony_ci
1831bf215546Sopenharmony_ci      D3D12_DEPTH_STENCIL_DESC1 *ds =
1832bf215546Sopenharmony_ci         dzn_graphics_pipeline_get_desc(pipeline, stream_buf, ds);
1833bf215546Sopenharmony_ci      if (ds && ds->StencilEnable) {
1834bf215546Sopenharmony_ci         if (pipeline->zsa.stencil_test.dynamic_compare_mask) {
1835bf215546Sopenharmony_ci            if (ds->FrontFace.StencilFunc != D3D12_COMPARISON_FUNC_NEVER &&
1836bf215546Sopenharmony_ci                ds->FrontFace.StencilFunc != D3D12_COMPARISON_FUNC_ALWAYS) {
1837bf215546Sopenharmony_ci               ds->StencilReadMask = masked_key.stencil_test.front.compare_mask;
1838bf215546Sopenharmony_ci            }
1839bf215546Sopenharmony_ci
1840bf215546Sopenharmony_ci            if (ds->BackFace.StencilFunc != D3D12_COMPARISON_FUNC_NEVER &&
1841bf215546Sopenharmony_ci                ds->BackFace.StencilFunc != D3D12_COMPARISON_FUNC_ALWAYS) {
1842bf215546Sopenharmony_ci               ds->StencilReadMask = masked_key.stencil_test.back.compare_mask;
1843bf215546Sopenharmony_ci            }
1844bf215546Sopenharmony_ci
1845bf215546Sopenharmony_ci            if (ds->FrontFace.StencilFunc != D3D12_COMPARISON_FUNC_NEVER &&
1846bf215546Sopenharmony_ci                ds->FrontFace.StencilFunc != D3D12_COMPARISON_FUNC_ALWAYS &&
1847bf215546Sopenharmony_ci                ds->BackFace.StencilFunc != D3D12_COMPARISON_FUNC_NEVER &&
1848bf215546Sopenharmony_ci                ds->BackFace.StencilFunc != D3D12_COMPARISON_FUNC_ALWAYS)
1849bf215546Sopenharmony_ci               assert(masked_key.stencil_test.front.compare_mask == masked_key.stencil_test.back.compare_mask);
1850bf215546Sopenharmony_ci         }
1851bf215546Sopenharmony_ci
1852bf215546Sopenharmony_ci         if (pipeline->zsa.stencil_test.dynamic_write_mask) {
1853bf215546Sopenharmony_ci            assert(!masked_key.stencil_test.front.write_mask ||
1854bf215546Sopenharmony_ci                   !masked_key.stencil_test.back.write_mask ||
1855bf215546Sopenharmony_ci                   masked_key.stencil_test.front.write_mask == masked_key.stencil_test.back.write_mask);
1856bf215546Sopenharmony_ci            ds->StencilWriteMask =
1857bf215546Sopenharmony_ci               masked_key.stencil_test.front.write_mask |
1858bf215546Sopenharmony_ci               masked_key.stencil_test.back.write_mask;
1859bf215546Sopenharmony_ci         }
1860bf215546Sopenharmony_ci      }
1861bf215546Sopenharmony_ci
1862bf215546Sopenharmony_ci      ASSERTED HRESULT hres = ID3D12Device2_CreatePipelineState(device->dev, &stream_desc,
1863bf215546Sopenharmony_ci                                                                &IID_ID3D12PipelineState,
1864bf215546Sopenharmony_ci                                                                (void**)(&variant->state));
1865bf215546Sopenharmony_ci      assert(!FAILED(hres));
1866bf215546Sopenharmony_ci      he = _mesa_hash_table_insert(pipeline->variants, &variant->key, variant);
1867bf215546Sopenharmony_ci      assert(he);
1868bf215546Sopenharmony_ci   } else {
1869bf215546Sopenharmony_ci      variant = he->data;
1870bf215546Sopenharmony_ci   }
1871bf215546Sopenharmony_ci
1872bf215546Sopenharmony_ci   if (variant->state)
1873bf215546Sopenharmony_ci      ID3D12PipelineState_AddRef(variant->state);
1874bf215546Sopenharmony_ci
1875bf215546Sopenharmony_ci   if (pipeline->base.state)
1876bf215546Sopenharmony_ci      ID3D12PipelineState_Release(pipeline->base.state);
1877bf215546Sopenharmony_ci
1878bf215546Sopenharmony_ci   pipeline->base.state = variant->state;
1879bf215546Sopenharmony_ci   return variant->state;
1880bf215546Sopenharmony_ci}
1881bf215546Sopenharmony_ci
1882bf215546Sopenharmony_ci#define DZN_INDIRECT_CMD_SIG_MAX_ARGS 4
1883bf215546Sopenharmony_ci
1884bf215546Sopenharmony_ciID3D12CommandSignature *
1885bf215546Sopenharmony_cidzn_graphics_pipeline_get_indirect_cmd_sig(struct dzn_graphics_pipeline *pipeline,
1886bf215546Sopenharmony_ci                                           enum dzn_indirect_draw_cmd_sig_type type)
1887bf215546Sopenharmony_ci{
1888bf215546Sopenharmony_ci   assert(type < DZN_NUM_INDIRECT_DRAW_CMD_SIGS);
1889bf215546Sopenharmony_ci
1890bf215546Sopenharmony_ci   struct dzn_device *device =
1891bf215546Sopenharmony_ci      container_of(pipeline->base.base.device, struct dzn_device, vk);
1892bf215546Sopenharmony_ci   ID3D12CommandSignature *cmdsig = pipeline->indirect_cmd_sigs[type];
1893bf215546Sopenharmony_ci
1894bf215546Sopenharmony_ci   if (cmdsig)
1895bf215546Sopenharmony_ci      return cmdsig;
1896bf215546Sopenharmony_ci
1897bf215546Sopenharmony_ci   bool triangle_fan = type == DZN_INDIRECT_DRAW_TRIANGLE_FAN_CMD_SIG;
1898bf215546Sopenharmony_ci   bool indexed = type == DZN_INDIRECT_INDEXED_DRAW_CMD_SIG || triangle_fan;
1899bf215546Sopenharmony_ci
1900bf215546Sopenharmony_ci   uint32_t cmd_arg_count = 0;
1901bf215546Sopenharmony_ci   D3D12_INDIRECT_ARGUMENT_DESC cmd_args[DZN_INDIRECT_CMD_SIG_MAX_ARGS];
1902bf215546Sopenharmony_ci
1903bf215546Sopenharmony_ci   if (triangle_fan) {
1904bf215546Sopenharmony_ci      cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
1905bf215546Sopenharmony_ci         .Type = D3D12_INDIRECT_ARGUMENT_TYPE_INDEX_BUFFER_VIEW,
1906bf215546Sopenharmony_ci      };
1907bf215546Sopenharmony_ci   }
1908bf215546Sopenharmony_ci
1909bf215546Sopenharmony_ci   cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
1910bf215546Sopenharmony_ci      .Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
1911bf215546Sopenharmony_ci      .Constant = {
1912bf215546Sopenharmony_ci         .RootParameterIndex = pipeline->base.root.sysval_cbv_param_idx,
1913bf215546Sopenharmony_ci         .DestOffsetIn32BitValues = offsetof(struct dxil_spirv_vertex_runtime_data, first_vertex) / 4,
1914bf215546Sopenharmony_ci         .Num32BitValuesToSet = 2,
1915bf215546Sopenharmony_ci      },
1916bf215546Sopenharmony_ci   };
1917bf215546Sopenharmony_ci
1918bf215546Sopenharmony_ci   cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
1919bf215546Sopenharmony_ci      .Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
1920bf215546Sopenharmony_ci      .Constant = {
1921bf215546Sopenharmony_ci         .RootParameterIndex = pipeline->base.root.sysval_cbv_param_idx,
1922bf215546Sopenharmony_ci         .DestOffsetIn32BitValues = offsetof(struct dxil_spirv_vertex_runtime_data, draw_id) / 4,
1923bf215546Sopenharmony_ci         .Num32BitValuesToSet = 1,
1924bf215546Sopenharmony_ci      },
1925bf215546Sopenharmony_ci   };
1926bf215546Sopenharmony_ci
1927bf215546Sopenharmony_ci   cmd_args[cmd_arg_count++] = (D3D12_INDIRECT_ARGUMENT_DESC) {
1928bf215546Sopenharmony_ci      .Type = indexed ?
1929bf215546Sopenharmony_ci              D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED :
1930bf215546Sopenharmony_ci              D3D12_INDIRECT_ARGUMENT_TYPE_DRAW,
1931bf215546Sopenharmony_ci   };
1932bf215546Sopenharmony_ci
1933bf215546Sopenharmony_ci   assert(cmd_arg_count <= ARRAY_SIZE(cmd_args));
1934bf215546Sopenharmony_ci   assert(offsetof(struct dxil_spirv_vertex_runtime_data, first_vertex) == 0);
1935bf215546Sopenharmony_ci
1936bf215546Sopenharmony_ci   D3D12_COMMAND_SIGNATURE_DESC cmd_sig_desc = {
1937bf215546Sopenharmony_ci      .ByteStride =
1938bf215546Sopenharmony_ci         triangle_fan ?
1939bf215546Sopenharmony_ci         sizeof(struct dzn_indirect_triangle_fan_draw_exec_params) :
1940bf215546Sopenharmony_ci         sizeof(struct dzn_indirect_draw_exec_params),
1941bf215546Sopenharmony_ci      .NumArgumentDescs = cmd_arg_count,
1942bf215546Sopenharmony_ci      .pArgumentDescs = cmd_args,
1943bf215546Sopenharmony_ci   };
1944bf215546Sopenharmony_ci   HRESULT hres =
1945bf215546Sopenharmony_ci      ID3D12Device1_CreateCommandSignature(device->dev, &cmd_sig_desc,
1946bf215546Sopenharmony_ci                                           pipeline->base.root.sig,
1947bf215546Sopenharmony_ci                                           &IID_ID3D12CommandSignature,
1948bf215546Sopenharmony_ci                                           (void **)&cmdsig);
1949bf215546Sopenharmony_ci   if (FAILED(hres))
1950bf215546Sopenharmony_ci      return NULL;
1951bf215546Sopenharmony_ci
1952bf215546Sopenharmony_ci   pipeline->indirect_cmd_sigs[type] = cmdsig;
1953bf215546Sopenharmony_ci   return cmdsig;
1954bf215546Sopenharmony_ci}
1955bf215546Sopenharmony_ci
1956bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL
1957bf215546Sopenharmony_cidzn_CreateGraphicsPipelines(VkDevice dev,
1958bf215546Sopenharmony_ci                            VkPipelineCache pipelineCache,
1959bf215546Sopenharmony_ci                            uint32_t count,
1960bf215546Sopenharmony_ci                            const VkGraphicsPipelineCreateInfo *pCreateInfos,
1961bf215546Sopenharmony_ci                            const VkAllocationCallbacks *pAllocator,
1962bf215546Sopenharmony_ci                            VkPipeline *pPipelines)
1963bf215546Sopenharmony_ci{
1964bf215546Sopenharmony_ci   VK_FROM_HANDLE(dzn_device, device, dev);
1965bf215546Sopenharmony_ci   VkResult result = VK_SUCCESS;
1966bf215546Sopenharmony_ci
1967bf215546Sopenharmony_ci   unsigned i;
1968bf215546Sopenharmony_ci   for (i = 0; i < count; i++) {
1969bf215546Sopenharmony_ci      result = dzn_graphics_pipeline_create(device,
1970bf215546Sopenharmony_ci                                            pipelineCache,
1971bf215546Sopenharmony_ci                                            &pCreateInfos[i],
1972bf215546Sopenharmony_ci                                            pAllocator,
1973bf215546Sopenharmony_ci                                            &pPipelines[i]);
1974bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
1975bf215546Sopenharmony_ci         pPipelines[i] = VK_NULL_HANDLE;
1976bf215546Sopenharmony_ci
1977bf215546Sopenharmony_ci         /* Bail out on the first error != VK_PIPELINE_COMPILE_REQUIRED_EX as it
1978bf215546Sopenharmony_ci          * is not obvious what error should be report upon 2 different failures.
1979bf215546Sopenharmony_ci          */
1980bf215546Sopenharmony_ci         if (result != VK_PIPELINE_COMPILE_REQUIRED)
1981bf215546Sopenharmony_ci            break;
1982bf215546Sopenharmony_ci
1983bf215546Sopenharmony_ci         if (pCreateInfos[i].flags & VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT)
1984bf215546Sopenharmony_ci            break;
1985bf215546Sopenharmony_ci      }
1986bf215546Sopenharmony_ci   }
1987bf215546Sopenharmony_ci
1988bf215546Sopenharmony_ci   for (; i < count; i++)
1989bf215546Sopenharmony_ci      pPipelines[i] = VK_NULL_HANDLE;
1990bf215546Sopenharmony_ci
1991bf215546Sopenharmony_ci   return result;
1992bf215546Sopenharmony_ci}
1993bf215546Sopenharmony_ci
1994bf215546Sopenharmony_cistatic void
1995bf215546Sopenharmony_cidzn_compute_pipeline_destroy(struct dzn_compute_pipeline *pipeline,
1996bf215546Sopenharmony_ci                             const VkAllocationCallbacks *alloc)
1997bf215546Sopenharmony_ci{
1998bf215546Sopenharmony_ci   if (!pipeline)
1999bf215546Sopenharmony_ci      return;
2000bf215546Sopenharmony_ci
2001bf215546Sopenharmony_ci   if (pipeline->indirect_cmd_sig)
2002bf215546Sopenharmony_ci      ID3D12CommandSignature_Release(pipeline->indirect_cmd_sig);
2003bf215546Sopenharmony_ci
2004bf215546Sopenharmony_ci   dzn_pipeline_finish(&pipeline->base);
2005bf215546Sopenharmony_ci   vk_free2(&pipeline->base.base.device->alloc, alloc, pipeline);
2006bf215546Sopenharmony_ci}
2007bf215546Sopenharmony_ci
2008bf215546Sopenharmony_cistatic VkResult
2009bf215546Sopenharmony_cidzn_pipeline_cache_lookup_compute_pipeline(struct vk_pipeline_cache *cache,
2010bf215546Sopenharmony_ci                                           uint8_t *pipeline_hash,
2011bf215546Sopenharmony_ci                                           D3D12_PIPELINE_STATE_STREAM_DESC *stream_desc,
2012bf215546Sopenharmony_ci                                           D3D12_SHADER_BYTECODE *dxil,
2013bf215546Sopenharmony_ci                                           bool *cache_hit)
2014bf215546Sopenharmony_ci{
2015bf215546Sopenharmony_ci   *cache_hit = false;
2016bf215546Sopenharmony_ci
2017bf215546Sopenharmony_ci   if (!cache)
2018bf215546Sopenharmony_ci      return VK_SUCCESS;
2019bf215546Sopenharmony_ci
2020bf215546Sopenharmony_ci   struct vk_pipeline_cache_object *cache_obj = NULL;
2021bf215546Sopenharmony_ci
2022bf215546Sopenharmony_ci   cache_obj =
2023bf215546Sopenharmony_ci      vk_pipeline_cache_lookup_object(cache, pipeline_hash, SHA1_DIGEST_LENGTH,
2024bf215546Sopenharmony_ci                                      &dzn_cached_blob_ops,
2025bf215546Sopenharmony_ci                                      NULL);
2026bf215546Sopenharmony_ci   if (!cache_obj)
2027bf215546Sopenharmony_ci      return VK_SUCCESS;
2028bf215546Sopenharmony_ci
2029bf215546Sopenharmony_ci   struct dzn_cached_blob *cached_blob =
2030bf215546Sopenharmony_ci      container_of(cache_obj, struct dzn_cached_blob, base);
2031bf215546Sopenharmony_ci
2032bf215546Sopenharmony_ci   assert(cached_blob->size == SHA1_DIGEST_LENGTH);
2033bf215546Sopenharmony_ci
2034bf215546Sopenharmony_ci   const uint8_t *dxil_hash = cached_blob->data;
2035bf215546Sopenharmony_ci   gl_shader_stage stage;
2036bf215546Sopenharmony_ci
2037bf215546Sopenharmony_ci   VkResult ret =
2038bf215546Sopenharmony_ci      dzn_pipeline_cache_lookup_dxil_shader(cache, dxil_hash, &stage, dxil);
2039bf215546Sopenharmony_ci
2040bf215546Sopenharmony_ci   if (ret != VK_SUCCESS || stage == MESA_SHADER_NONE)
2041bf215546Sopenharmony_ci      goto out;
2042bf215546Sopenharmony_ci
2043bf215546Sopenharmony_ci   assert(stage == MESA_SHADER_COMPUTE);
2044bf215546Sopenharmony_ci
2045bf215546Sopenharmony_ci   d3d12_compute_pipeline_state_stream_new_desc(stream_desc, CS, D3D12_SHADER_BYTECODE, slot);
2046bf215546Sopenharmony_ci   *slot = *dxil;
2047bf215546Sopenharmony_ci   *cache_hit = true;
2048bf215546Sopenharmony_ci
2049bf215546Sopenharmony_ciout:
2050bf215546Sopenharmony_ci   vk_pipeline_cache_object_unref(cache_obj);
2051bf215546Sopenharmony_ci   return ret;
2052bf215546Sopenharmony_ci}
2053bf215546Sopenharmony_ci
2054bf215546Sopenharmony_cistatic void
2055bf215546Sopenharmony_cidzn_pipeline_cache_add_compute_pipeline(struct vk_pipeline_cache *cache,
2056bf215546Sopenharmony_ci                                        uint8_t *pipeline_hash,
2057bf215546Sopenharmony_ci                                        uint8_t *dxil_hash)
2058bf215546Sopenharmony_ci{
2059bf215546Sopenharmony_ci   struct vk_pipeline_cache_object *cache_obj =
2060bf215546Sopenharmony_ci      dzn_cached_blob_create(cache->base.device, pipeline_hash, NULL, SHA1_DIGEST_LENGTH);
2061bf215546Sopenharmony_ci   if (!cache_obj)
2062bf215546Sopenharmony_ci      return;
2063bf215546Sopenharmony_ci
2064bf215546Sopenharmony_ci   struct dzn_cached_blob *cached_blob =
2065bf215546Sopenharmony_ci      container_of(cache_obj, struct dzn_cached_blob, base);
2066bf215546Sopenharmony_ci
2067bf215546Sopenharmony_ci   memcpy((void *)cached_blob->data, dxil_hash, SHA1_DIGEST_LENGTH);
2068bf215546Sopenharmony_ci
2069bf215546Sopenharmony_ci   cache_obj = vk_pipeline_cache_add_object(cache, cache_obj);
2070bf215546Sopenharmony_ci   vk_pipeline_cache_object_unref(cache_obj);
2071bf215546Sopenharmony_ci}
2072bf215546Sopenharmony_ci
2073bf215546Sopenharmony_cistatic VkResult
2074bf215546Sopenharmony_cidzn_compute_pipeline_compile_shader(struct dzn_device *device,
2075bf215546Sopenharmony_ci                                    struct dzn_compute_pipeline *pipeline,
2076bf215546Sopenharmony_ci                                    struct vk_pipeline_cache *cache,
2077bf215546Sopenharmony_ci                                    const struct dzn_pipeline_layout *layout,
2078bf215546Sopenharmony_ci                                    D3D12_PIPELINE_STATE_STREAM_DESC *stream_desc,
2079bf215546Sopenharmony_ci                                    D3D12_SHADER_BYTECODE *shader,
2080bf215546Sopenharmony_ci                                    const VkComputePipelineCreateInfo *info)
2081bf215546Sopenharmony_ci{
2082bf215546Sopenharmony_ci   uint8_t spirv_hash[SHA1_DIGEST_LENGTH], pipeline_hash[SHA1_DIGEST_LENGTH];
2083bf215546Sopenharmony_ci   VkResult ret = VK_SUCCESS;
2084bf215546Sopenharmony_ci   nir_shader *nir = NULL;
2085bf215546Sopenharmony_ci
2086bf215546Sopenharmony_ci   if (cache) {
2087bf215546Sopenharmony_ci      struct mesa_sha1 pipeline_hash_ctx;
2088bf215546Sopenharmony_ci
2089bf215546Sopenharmony_ci      _mesa_sha1_init(&pipeline_hash_ctx);
2090bf215546Sopenharmony_ci      vk_pipeline_hash_shader_stage(&info->stage, spirv_hash);
2091bf215546Sopenharmony_ci      _mesa_sha1_update(&pipeline_hash_ctx, spirv_hash, sizeof(spirv_hash));
2092bf215546Sopenharmony_ci      _mesa_sha1_update(&pipeline_hash_ctx, layout->stages[MESA_SHADER_COMPUTE].hash,
2093bf215546Sopenharmony_ci                        sizeof(layout->stages[MESA_SHADER_COMPUTE].hash));
2094bf215546Sopenharmony_ci      _mesa_sha1_final(&pipeline_hash_ctx, pipeline_hash);
2095bf215546Sopenharmony_ci
2096bf215546Sopenharmony_ci      bool cache_hit = false;
2097bf215546Sopenharmony_ci      ret = dzn_pipeline_cache_lookup_compute_pipeline(cache, pipeline_hash,
2098bf215546Sopenharmony_ci                                                       stream_desc, shader,
2099bf215546Sopenharmony_ci                                                       &cache_hit);
2100bf215546Sopenharmony_ci      if (ret != VK_SUCCESS || cache_hit)
2101bf215546Sopenharmony_ci         goto out;
2102bf215546Sopenharmony_ci   }
2103bf215546Sopenharmony_ci
2104bf215546Sopenharmony_ci   ret = dzn_pipeline_get_nir_shader(device, layout, cache, spirv_hash,
2105bf215546Sopenharmony_ci                                     &info->stage, MESA_SHADER_COMPUTE,
2106bf215546Sopenharmony_ci                                     DXIL_SPIRV_YZ_FLIP_NONE, 0, 0,
2107bf215546Sopenharmony_ci                                     false, NULL,
2108bf215546Sopenharmony_ci                                     dxil_get_nir_compiler_options(), &nir);
2109bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
2110bf215546Sopenharmony_ci      return ret;
2111bf215546Sopenharmony_ci
2112bf215546Sopenharmony_ci   uint8_t bindings_hash[SHA1_DIGEST_LENGTH], dxil_hash[SHA1_DIGEST_LENGTH];
2113bf215546Sopenharmony_ci
2114bf215546Sopenharmony_ci   NIR_PASS_V(nir, adjust_var_bindings, layout, cache ? bindings_hash : NULL);
2115bf215546Sopenharmony_ci
2116bf215546Sopenharmony_ci   if (cache) {
2117bf215546Sopenharmony_ci      struct mesa_sha1 dxil_hash_ctx;
2118bf215546Sopenharmony_ci
2119bf215546Sopenharmony_ci      _mesa_sha1_init(&dxil_hash_ctx);
2120bf215546Sopenharmony_ci      _mesa_sha1_update(&dxil_hash_ctx, spirv_hash, sizeof(spirv_hash));
2121bf215546Sopenharmony_ci      _mesa_sha1_update(&dxil_hash_ctx, bindings_hash, sizeof(bindings_hash));
2122bf215546Sopenharmony_ci      _mesa_sha1_final(&dxil_hash_ctx, dxil_hash);
2123bf215546Sopenharmony_ci
2124bf215546Sopenharmony_ci      gl_shader_stage stage;
2125bf215546Sopenharmony_ci
2126bf215546Sopenharmony_ci      ret = dzn_pipeline_cache_lookup_dxil_shader(cache, dxil_hash, &stage, shader);
2127bf215546Sopenharmony_ci      if (ret != VK_SUCCESS)
2128bf215546Sopenharmony_ci         goto out;
2129bf215546Sopenharmony_ci
2130bf215546Sopenharmony_ci      if (stage != MESA_SHADER_NONE) {
2131bf215546Sopenharmony_ci         assert(stage == MESA_SHADER_COMPUTE);
2132bf215546Sopenharmony_ci         d3d12_compute_pipeline_state_stream_new_desc(stream_desc, CS, D3D12_SHADER_BYTECODE, cs);
2133bf215546Sopenharmony_ci         *cs = *shader;
2134bf215546Sopenharmony_ci         dzn_pipeline_cache_add_compute_pipeline(cache, pipeline_hash, dxil_hash);
2135bf215546Sopenharmony_ci         goto out;
2136bf215546Sopenharmony_ci      }
2137bf215546Sopenharmony_ci   }
2138bf215546Sopenharmony_ci
2139bf215546Sopenharmony_ci   ret = dzn_pipeline_compile_shader(device, nir, shader);
2140bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
2141bf215546Sopenharmony_ci      goto out;
2142bf215546Sopenharmony_ci
2143bf215546Sopenharmony_ci   d3d12_compute_pipeline_state_stream_new_desc(stream_desc, CS, D3D12_SHADER_BYTECODE, cs);
2144bf215546Sopenharmony_ci   *cs = *shader;
2145bf215546Sopenharmony_ci
2146bf215546Sopenharmony_ci   if (cache) {
2147bf215546Sopenharmony_ci      dzn_pipeline_cache_add_dxil_shader(cache, dxil_hash, MESA_SHADER_COMPUTE, shader);
2148bf215546Sopenharmony_ci      dzn_pipeline_cache_add_compute_pipeline(cache, pipeline_hash, dxil_hash);
2149bf215546Sopenharmony_ci   }
2150bf215546Sopenharmony_ci
2151bf215546Sopenharmony_ciout:
2152bf215546Sopenharmony_ci   ralloc_free(nir);
2153bf215546Sopenharmony_ci   return ret;
2154bf215546Sopenharmony_ci}
2155bf215546Sopenharmony_ci
2156bf215546Sopenharmony_cistatic VkResult
2157bf215546Sopenharmony_cidzn_compute_pipeline_create(struct dzn_device *device,
2158bf215546Sopenharmony_ci                            VkPipelineCache cache,
2159bf215546Sopenharmony_ci                            const VkComputePipelineCreateInfo *pCreateInfo,
2160bf215546Sopenharmony_ci                            const VkAllocationCallbacks *pAllocator,
2161bf215546Sopenharmony_ci                            VkPipeline *out)
2162bf215546Sopenharmony_ci{
2163bf215546Sopenharmony_ci   VK_FROM_HANDLE(dzn_pipeline_layout, layout, pCreateInfo->layout);
2164bf215546Sopenharmony_ci   VK_FROM_HANDLE(vk_pipeline_cache, pcache, cache);
2165bf215546Sopenharmony_ci
2166bf215546Sopenharmony_ci   struct dzn_compute_pipeline *pipeline =
2167bf215546Sopenharmony_ci      vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*pipeline), 8,
2168bf215546Sopenharmony_ci                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2169bf215546Sopenharmony_ci   if (!pipeline)
2170bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2171bf215546Sopenharmony_ci
2172bf215546Sopenharmony_ci   uintptr_t state_buf[MAX_COMPUTE_PIPELINE_STATE_STREAM_SIZE / sizeof(uintptr_t)];
2173bf215546Sopenharmony_ci   D3D12_PIPELINE_STATE_STREAM_DESC stream_desc = {
2174bf215546Sopenharmony_ci      .pPipelineStateSubobjectStream = state_buf,
2175bf215546Sopenharmony_ci   };
2176bf215546Sopenharmony_ci
2177bf215546Sopenharmony_ci   dzn_pipeline_init(&pipeline->base, device,
2178bf215546Sopenharmony_ci                     VK_PIPELINE_BIND_POINT_COMPUTE,
2179bf215546Sopenharmony_ci                     layout, &stream_desc);
2180bf215546Sopenharmony_ci
2181bf215546Sopenharmony_ci   D3D12_SHADER_BYTECODE shader = { 0 };
2182bf215546Sopenharmony_ci   VkResult ret =
2183bf215546Sopenharmony_ci      dzn_compute_pipeline_compile_shader(device, pipeline, pcache, layout,
2184bf215546Sopenharmony_ci                                          &stream_desc, &shader, pCreateInfo);
2185bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
2186bf215546Sopenharmony_ci      goto out;
2187bf215546Sopenharmony_ci
2188bf215546Sopenharmony_ci   if (FAILED(ID3D12Device2_CreatePipelineState(device->dev, &stream_desc,
2189bf215546Sopenharmony_ci                                                &IID_ID3D12PipelineState,
2190bf215546Sopenharmony_ci                                                (void **)&pipeline->base.state)))
2191bf215546Sopenharmony_ci      ret = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2192bf215546Sopenharmony_ci
2193bf215546Sopenharmony_ciout:
2194bf215546Sopenharmony_ci   free((void *)shader.pShaderBytecode);
2195bf215546Sopenharmony_ci   if (ret != VK_SUCCESS)
2196bf215546Sopenharmony_ci      dzn_compute_pipeline_destroy(pipeline, pAllocator);
2197bf215546Sopenharmony_ci   else
2198bf215546Sopenharmony_ci      *out = dzn_compute_pipeline_to_handle(pipeline);
2199bf215546Sopenharmony_ci
2200bf215546Sopenharmony_ci   return ret;
2201bf215546Sopenharmony_ci}
2202bf215546Sopenharmony_ci
2203bf215546Sopenharmony_ciID3D12CommandSignature *
2204bf215546Sopenharmony_cidzn_compute_pipeline_get_indirect_cmd_sig(struct dzn_compute_pipeline *pipeline)
2205bf215546Sopenharmony_ci{
2206bf215546Sopenharmony_ci   if (pipeline->indirect_cmd_sig)
2207bf215546Sopenharmony_ci      return pipeline->indirect_cmd_sig;
2208bf215546Sopenharmony_ci
2209bf215546Sopenharmony_ci   struct dzn_device *device =
2210bf215546Sopenharmony_ci      container_of(pipeline->base.base.device, struct dzn_device, vk);
2211bf215546Sopenharmony_ci
2212bf215546Sopenharmony_ci   D3D12_INDIRECT_ARGUMENT_DESC indirect_dispatch_args[] = {
2213bf215546Sopenharmony_ci      {
2214bf215546Sopenharmony_ci         .Type = D3D12_INDIRECT_ARGUMENT_TYPE_CONSTANT,
2215bf215546Sopenharmony_ci         .Constant = {
2216bf215546Sopenharmony_ci            .RootParameterIndex = pipeline->base.root.sysval_cbv_param_idx,
2217bf215546Sopenharmony_ci            .DestOffsetIn32BitValues = 0,
2218bf215546Sopenharmony_ci            .Num32BitValuesToSet = 3,
2219bf215546Sopenharmony_ci         },
2220bf215546Sopenharmony_ci      },
2221bf215546Sopenharmony_ci      {
2222bf215546Sopenharmony_ci         .Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH,
2223bf215546Sopenharmony_ci      },
2224bf215546Sopenharmony_ci   };
2225bf215546Sopenharmony_ci
2226bf215546Sopenharmony_ci   D3D12_COMMAND_SIGNATURE_DESC indirect_dispatch_desc = {
2227bf215546Sopenharmony_ci      .ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS) * 2,
2228bf215546Sopenharmony_ci      .NumArgumentDescs = ARRAY_SIZE(indirect_dispatch_args),
2229bf215546Sopenharmony_ci      .pArgumentDescs = indirect_dispatch_args,
2230bf215546Sopenharmony_ci   };
2231bf215546Sopenharmony_ci
2232bf215546Sopenharmony_ci   HRESULT hres =
2233bf215546Sopenharmony_ci      ID3D12Device1_CreateCommandSignature(device->dev, &indirect_dispatch_desc,
2234bf215546Sopenharmony_ci                                           pipeline->base.root.sig,
2235bf215546Sopenharmony_ci                                           &IID_ID3D12CommandSignature,
2236bf215546Sopenharmony_ci                                           (void **)&pipeline->indirect_cmd_sig);
2237bf215546Sopenharmony_ci   if (FAILED(hres))
2238bf215546Sopenharmony_ci      return NULL;
2239bf215546Sopenharmony_ci
2240bf215546Sopenharmony_ci   return pipeline->indirect_cmd_sig;
2241bf215546Sopenharmony_ci}
2242bf215546Sopenharmony_ci
2243bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL
2244bf215546Sopenharmony_cidzn_CreateComputePipelines(VkDevice dev,
2245bf215546Sopenharmony_ci                           VkPipelineCache pipelineCache,
2246bf215546Sopenharmony_ci                           uint32_t count,
2247bf215546Sopenharmony_ci                           const VkComputePipelineCreateInfo *pCreateInfos,
2248bf215546Sopenharmony_ci                           const VkAllocationCallbacks *pAllocator,
2249bf215546Sopenharmony_ci                           VkPipeline *pPipelines)
2250bf215546Sopenharmony_ci{
2251bf215546Sopenharmony_ci   VK_FROM_HANDLE(dzn_device, device, dev);
2252bf215546Sopenharmony_ci   VkResult result = VK_SUCCESS;
2253bf215546Sopenharmony_ci
2254bf215546Sopenharmony_ci   unsigned i;
2255bf215546Sopenharmony_ci   for (i = 0; i < count; i++) {
2256bf215546Sopenharmony_ci      result = dzn_compute_pipeline_create(device,
2257bf215546Sopenharmony_ci                                           pipelineCache,
2258bf215546Sopenharmony_ci                                           &pCreateInfos[i],
2259bf215546Sopenharmony_ci                                           pAllocator,
2260bf215546Sopenharmony_ci                                           &pPipelines[i]);
2261bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
2262bf215546Sopenharmony_ci         pPipelines[i] = VK_NULL_HANDLE;
2263bf215546Sopenharmony_ci
2264bf215546Sopenharmony_ci         /* Bail out on the first error != VK_PIPELINE_COMPILE_REQUIRED_EX as it
2265bf215546Sopenharmony_ci          * is not obvious what error should be report upon 2 different failures.
2266bf215546Sopenharmony_ci          */
2267bf215546Sopenharmony_ci         if (result != VK_PIPELINE_COMPILE_REQUIRED)
2268bf215546Sopenharmony_ci            break;
2269bf215546Sopenharmony_ci
2270bf215546Sopenharmony_ci         if (pCreateInfos[i].flags & VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT)
2271bf215546Sopenharmony_ci            break;
2272bf215546Sopenharmony_ci      }
2273bf215546Sopenharmony_ci   }
2274bf215546Sopenharmony_ci
2275bf215546Sopenharmony_ci   for (; i < count; i++)
2276bf215546Sopenharmony_ci      pPipelines[i] = VK_NULL_HANDLE;
2277bf215546Sopenharmony_ci
2278bf215546Sopenharmony_ci   return result;
2279bf215546Sopenharmony_ci}
2280bf215546Sopenharmony_ci
2281bf215546Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL
2282bf215546Sopenharmony_cidzn_DestroyPipeline(VkDevice device,
2283bf215546Sopenharmony_ci                    VkPipeline pipeline,
2284bf215546Sopenharmony_ci                    const VkAllocationCallbacks *pAllocator)
2285bf215546Sopenharmony_ci{
2286bf215546Sopenharmony_ci   VK_FROM_HANDLE(dzn_pipeline, pipe, pipeline);
2287bf215546Sopenharmony_ci
2288bf215546Sopenharmony_ci   if (!pipe)
2289bf215546Sopenharmony_ci      return;
2290bf215546Sopenharmony_ci
2291bf215546Sopenharmony_ci   if (pipe->type == VK_PIPELINE_BIND_POINT_GRAPHICS) {
2292bf215546Sopenharmony_ci      struct dzn_graphics_pipeline *gfx = container_of(pipe, struct dzn_graphics_pipeline, base);
2293bf215546Sopenharmony_ci      dzn_graphics_pipeline_destroy(gfx, pAllocator);
2294bf215546Sopenharmony_ci   } else {
2295bf215546Sopenharmony_ci      assert(pipe->type == VK_PIPELINE_BIND_POINT_COMPUTE);
2296bf215546Sopenharmony_ci      struct dzn_compute_pipeline *compute = container_of(pipe, struct dzn_compute_pipeline, base);
2297bf215546Sopenharmony_ci      dzn_compute_pipeline_destroy(compute, pAllocator);
2298bf215546Sopenharmony_ci   }
2299bf215546Sopenharmony_ci}
2300