1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * Texture sampling code generation
30 *
31 * This file is nothing more than ugly glue between three largely independent
32 * entities:
33 * - TGSI -> LLVM translation (i.e., lp_build_tgsi_soa)
34 * - texture sampling code generation (i.e., lp_build_sample_soa)
35 * - LLVM pipe driver
36 *
37 * All interesting code is in the functions mentioned above. There is really
38 * nothing to see here.
39 *
40 * @author Jose Fonseca <jfonseca@vmware.com>
41 */
42
43 #include "pipe/p_defines.h"
44 #include "pipe/p_shader_tokens.h"
45 #include "gallivm/lp_bld_debug.h"
46 #include "gallivm/lp_bld_const.h"
47 #include "gallivm/lp_bld_type.h"
48 #include "gallivm/lp_bld_sample.h"
49 #include "gallivm/lp_bld_tgsi.h"
50 #include "lp_jit.h"
51 #include "lp_tex_sample.h"
52 #include "lp_state_fs.h"
53 #include "lp_debug.h"
54
55
56 /**
57 * This provides the bridge between the sampler state store in
58 * lp_jit_context and lp_jit_texture and the sampler code
59 * generator. It provides the texture layout information required by
60 * the texture sampler code generator in terms of the state stored in
61 * lp_jit_context and lp_jit_texture in runtime.
62 */
63 struct llvmpipe_sampler_dynamic_state
64 {
65 struct lp_sampler_dynamic_state base;
66
67 const struct lp_sampler_static_state *static_state;
68 };
69
70
71 /**
72 * This is the bridge between our sampler and the TGSI translator.
73 */
74 struct lp_llvm_sampler_soa
75 {
76 struct lp_build_sampler_soa base;
77
78 struct llvmpipe_sampler_dynamic_state dynamic_state;
79 unsigned nr_samplers;
80 };
81
82
83 struct llvmpipe_image_dynamic_state
84 {
85 struct lp_sampler_dynamic_state base;
86
87 const struct lp_image_static_state *static_state;
88 };
89
90
91 /**
92 * This is the bridge between our images and the TGSI translator.
93 */
94 struct lp_llvm_image_soa
95 {
96 struct lp_build_image_soa base;
97
98 struct llvmpipe_image_dynamic_state dynamic_state;
99 unsigned nr_images;
100 };
101
102
103 /**
104 * Fetch the specified member of the lp_jit_texture structure.
105 * \param emit_load if TRUE, emit the LLVM load instruction to actually
106 * fetch the field's value. Otherwise, just emit the
107 * GEP code to address the field.
108 *
109 * @sa http://llvm.org/docs/GetElementPtr.html
110 */
111 static LLVMValueRef
lp_llvm_texture_member(const struct lp_sampler_dynamic_state * base,struct gallivm_state * gallivm,LLVMValueRef context_ptr,unsigned texture_unit,LLVMValueRef texture_unit_offset,unsigned member_index,const char * member_name,boolean emit_load)112 lp_llvm_texture_member(const struct lp_sampler_dynamic_state *base,
113 struct gallivm_state *gallivm,
114 LLVMValueRef context_ptr,
115 unsigned texture_unit,
116 LLVMValueRef texture_unit_offset,
117 unsigned member_index,
118 const char *member_name,
119 boolean emit_load)
120 {
121 LLVMBuilderRef builder = gallivm->builder;
122 LLVMValueRef indices[4];
123
124 assert(texture_unit < PIPE_MAX_SHADER_SAMPLER_VIEWS);
125
126 /* context[0] */
127 indices[0] = lp_build_const_int32(gallivm, 0);
128 /* context[0].textures */
129 indices[1] = lp_build_const_int32(gallivm, LP_JIT_CTX_TEXTURES);
130 /* context[0].textures[unit] */
131 indices[2] = lp_build_const_int32(gallivm, texture_unit);
132 if (texture_unit_offset) {
133 indices[2] = LLVMBuildAdd(gallivm->builder, indices[2],
134 texture_unit_offset, "");
135 LLVMValueRef cond =
136 LLVMBuildICmp(gallivm->builder, LLVMIntULT,
137 indices[2],
138 lp_build_const_int32(gallivm,
139 PIPE_MAX_SHADER_SAMPLER_VIEWS), "");
140 indices[2] = LLVMBuildSelect(gallivm->builder, cond, indices[2],
141 lp_build_const_int32(gallivm,
142 texture_unit), "");
143 }
144 /* context[0].textures[unit].member */
145 indices[3] = lp_build_const_int32(gallivm, member_index);
146
147 LLVMValueRef ptr =
148 LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), "");
149
150 LLVMValueRef res = emit_load ? LLVMBuildLoad(builder, ptr, "") : ptr;
151
152 lp_build_name(res, "context.texture%u.%s", texture_unit, member_name);
153
154 return res;
155 }
156
157
158 /**
159 * Helper macro to instantiate the functions that generate the code to
160 * fetch the members of lp_jit_texture to fulfill the sampler code
161 * generator requests.
162 *
163 * This complexity is the price we have to pay to keep the texture
164 * sampler code generator a reusable module without dependencies to
165 * llvmpipe internals.
166 */
167 #define LP_LLVM_TEXTURE_MEMBER(_name, _index, _emit_load) \
168 static LLVMValueRef \
169 lp_llvm_texture_##_name( const struct lp_sampler_dynamic_state *base, \
170 struct gallivm_state *gallivm, \
171 LLVMValueRef context_ptr, \
172 unsigned texture_unit, \
173 LLVMValueRef texture_unit_offset) \
174 { \
175 return lp_llvm_texture_member(base, gallivm, context_ptr, \
176 texture_unit, texture_unit_offset, \
177 _index, #_name, _emit_load ); \
178 }
179
180
LP_LLVM_TEXTURE_MEMBER(width,LP_JIT_TEXTURE_WIDTH,TRUE)181 LP_LLVM_TEXTURE_MEMBER(width, LP_JIT_TEXTURE_WIDTH, TRUE)
182 LP_LLVM_TEXTURE_MEMBER(height, LP_JIT_TEXTURE_HEIGHT, TRUE)
183 LP_LLVM_TEXTURE_MEMBER(depth, LP_JIT_TEXTURE_DEPTH, TRUE)
184 LP_LLVM_TEXTURE_MEMBER(first_level, LP_JIT_TEXTURE_FIRST_LEVEL, TRUE)
185 LP_LLVM_TEXTURE_MEMBER(last_level, LP_JIT_TEXTURE_LAST_LEVEL, TRUE)
186 LP_LLVM_TEXTURE_MEMBER(base_ptr, LP_JIT_TEXTURE_BASE, TRUE)
187 LP_LLVM_TEXTURE_MEMBER(row_stride, LP_JIT_TEXTURE_ROW_STRIDE, FALSE)
188 LP_LLVM_TEXTURE_MEMBER(img_stride, LP_JIT_TEXTURE_IMG_STRIDE, FALSE)
189 LP_LLVM_TEXTURE_MEMBER(mip_offsets, LP_JIT_TEXTURE_MIP_OFFSETS, FALSE)
190 LP_LLVM_TEXTURE_MEMBER(num_samples, LP_JIT_TEXTURE_NUM_SAMPLES, TRUE)
191 LP_LLVM_TEXTURE_MEMBER(sample_stride, LP_JIT_TEXTURE_SAMPLE_STRIDE, TRUE)
192
193
194 /**
195 * Fetch the specified member of the lp_jit_sampler structure.
196 * \param emit_load if TRUE, emit the LLVM load instruction to actually
197 * fetch the field's value. Otherwise, just emit the
198 * GEP code to address the field.
199 *
200 * @sa http://llvm.org/docs/GetElementPtr.html
201 */
202 static LLVMValueRef
203 lp_llvm_sampler_member(const struct lp_sampler_dynamic_state *base,
204 struct gallivm_state *gallivm,
205 LLVMValueRef context_ptr,
206 unsigned sampler_unit,
207 unsigned member_index,
208 const char *member_name,
209 boolean emit_load)
210 {
211 LLVMBuilderRef builder = gallivm->builder;
212 LLVMValueRef indices[4];
213
214 assert(sampler_unit < PIPE_MAX_SAMPLERS);
215
216 /* context[0] */
217 indices[0] = lp_build_const_int32(gallivm, 0);
218 /* context[0].samplers */
219 indices[1] = lp_build_const_int32(gallivm, LP_JIT_CTX_SAMPLERS);
220 /* context[0].samplers[unit] */
221 indices[2] = lp_build_const_int32(gallivm, sampler_unit);
222 /* context[0].samplers[unit].member */
223 indices[3] = lp_build_const_int32(gallivm, member_index);
224
225 LLVMValueRef ptr =
226 LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), "");
227
228 LLVMValueRef res = emit_load ? LLVMBuildLoad(builder, ptr, "") : ptr;
229
230 lp_build_name(res, "context.sampler%u.%s", sampler_unit, member_name);
231
232 return res;
233 }
234
235
236 #define LP_LLVM_SAMPLER_MEMBER(_name, _index, _emit_load) \
237 static LLVMValueRef \
238 lp_llvm_sampler_##_name( const struct lp_sampler_dynamic_state *base, \
239 struct gallivm_state *gallivm, \
240 LLVMValueRef context_ptr, \
241 unsigned sampler_unit) \
242 { \
243 return lp_llvm_sampler_member(base, gallivm, context_ptr, \
244 sampler_unit, _index, #_name, _emit_load ); \
245 }
246
247
LP_LLVM_SAMPLER_MEMBER(min_lod,LP_JIT_SAMPLER_MIN_LOD,TRUE)248 LP_LLVM_SAMPLER_MEMBER(min_lod, LP_JIT_SAMPLER_MIN_LOD, TRUE)
249 LP_LLVM_SAMPLER_MEMBER(max_lod, LP_JIT_SAMPLER_MAX_LOD, TRUE)
250 LP_LLVM_SAMPLER_MEMBER(lod_bias, LP_JIT_SAMPLER_LOD_BIAS, TRUE)
251 LP_LLVM_SAMPLER_MEMBER(border_color, LP_JIT_SAMPLER_BORDER_COLOR, FALSE)
252 LP_LLVM_SAMPLER_MEMBER(max_aniso, LP_JIT_SAMPLER_MAX_ANISO, TRUE)
253
254
255 /**
256 * Fetch the specified member of the lp_jit_image structure.
257 * \param emit_load if TRUE, emit the LLVM load instruction to actually
258 * fetch the field's value. Otherwise, just emit the
259 * GEP code to address the field.
260 *
261 * @sa http://llvm.org/docs/GetElementPtr.html
262 */
263 static LLVMValueRef
264 lp_llvm_image_member(const struct lp_sampler_dynamic_state *base,
265 struct gallivm_state *gallivm,
266 LLVMValueRef context_ptr,
267 unsigned image_unit,
268 LLVMValueRef image_unit_offset,
269 unsigned member_index,
270 const char *member_name,
271 boolean emit_load)
272 {
273 LLVMBuilderRef builder = gallivm->builder;
274 LLVMValueRef indices[4];
275
276 assert(image_unit < PIPE_MAX_SHADER_IMAGES);
277
278 /* context[0] */
279 indices[0] = lp_build_const_int32(gallivm, 0);
280 /* context[0].images */
281 indices[1] = lp_build_const_int32(gallivm, LP_JIT_CTX_IMAGES);
282 /* context[0].images[unit] */
283 indices[2] = lp_build_const_int32(gallivm, image_unit);
284 if (image_unit_offset) {
285 indices[2] = LLVMBuildAdd(gallivm->builder, indices[2], image_unit_offset, "");
286 LLVMValueRef cond = LLVMBuildICmp(gallivm->builder, LLVMIntULT, indices[2], lp_build_const_int32(gallivm, PIPE_MAX_SHADER_IMAGES), "");
287 indices[2] = LLVMBuildSelect(gallivm->builder, cond, indices[2], lp_build_const_int32(gallivm, image_unit), "");
288 }
289 /* context[0].images[unit].member */
290 indices[3] = lp_build_const_int32(gallivm, member_index);
291
292 LLVMValueRef ptr =
293 LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), "");
294
295 LLVMValueRef res = emit_load ? LLVMBuildLoad(builder, ptr, "") : ptr;
296
297 lp_build_name(res, "context.image%u.%s", image_unit, member_name);
298
299 return res;
300 }
301
302
303 /**
304 * Helper macro to instantiate the functions that generate the code to
305 * fetch the members of lp_jit_image to fulfill the sampler code
306 * generator requests.
307 *
308 * This complexity is the price we have to pay to keep the image
309 * sampler code generator a reusable module without dependencies to
310 * llvmpipe internals.
311 */
312 #define LP_LLVM_IMAGE_MEMBER(_name, _index, _emit_load) \
313 static LLVMValueRef \
314 lp_llvm_image_##_name( const struct lp_sampler_dynamic_state *base, \
315 struct gallivm_state *gallivm, \
316 LLVMValueRef context_ptr, \
317 unsigned image_unit, LLVMValueRef image_unit_offset) \
318 { \
319 return lp_llvm_image_member(base, gallivm, context_ptr, \
320 image_unit, image_unit_offset, \
321 _index, #_name, _emit_load ); \
322 }
323
324
LP_LLVM_IMAGE_MEMBER(width,LP_JIT_IMAGE_WIDTH,TRUE)325 LP_LLVM_IMAGE_MEMBER(width, LP_JIT_IMAGE_WIDTH, TRUE)
326 LP_LLVM_IMAGE_MEMBER(height, LP_JIT_IMAGE_HEIGHT, TRUE)
327 LP_LLVM_IMAGE_MEMBER(depth, LP_JIT_IMAGE_DEPTH, TRUE)
328 LP_LLVM_IMAGE_MEMBER(base_ptr, LP_JIT_IMAGE_BASE, TRUE)
329 LP_LLVM_IMAGE_MEMBER(row_stride, LP_JIT_IMAGE_ROW_STRIDE, TRUE)
330 LP_LLVM_IMAGE_MEMBER(img_stride, LP_JIT_IMAGE_IMG_STRIDE, TRUE)
331 LP_LLVM_IMAGE_MEMBER(num_samples, LP_JIT_IMAGE_NUM_SAMPLES, TRUE)
332 LP_LLVM_IMAGE_MEMBER(sample_stride, LP_JIT_IMAGE_SAMPLE_STRIDE, TRUE)
333
334
335 #if LP_USE_TEXTURE_CACHE
336 static LLVMValueRef
337 lp_llvm_texture_cache_ptr(const struct lp_sampler_dynamic_state *base,
338 struct gallivm_state *gallivm,
339 LLVMValueRef thread_data_ptr,
340 unsigned unit)
341 {
342 /* We use the same cache for all units */
343 (void)unit;
344
345 return lp_jit_thread_data_cache(gallivm, thread_data_ptr);
346 }
347 #endif
348
349
350 static void
lp_llvm_sampler_soa_destroy(struct lp_build_sampler_soa * sampler)351 lp_llvm_sampler_soa_destroy(struct lp_build_sampler_soa *sampler)
352 {
353 FREE(sampler);
354 }
355
356
357 /**
358 * Fetch filtered values from texture.
359 * The 'texel' parameter returns four vectors corresponding to R, G, B, A.
360 */
361 static void
lp_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa * base,struct gallivm_state * gallivm,const struct lp_sampler_params * params)362 lp_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
363 struct gallivm_state *gallivm,
364 const struct lp_sampler_params *params)
365 {
366 struct lp_llvm_sampler_soa *sampler = (struct lp_llvm_sampler_soa *)base;
367 const unsigned texture_index = params->texture_index;
368 const unsigned sampler_index = params->sampler_index;
369
370 assert(sampler_index < PIPE_MAX_SAMPLERS);
371 assert(texture_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
372
373 if (LP_PERF & PERF_NO_TEX) {
374 lp_build_sample_nop(gallivm, params->type, params->coords, params->texel);
375 return;
376 }
377
378 if (params->texture_index_offset) {
379 LLVMValueRef unit =
380 LLVMBuildAdd(gallivm->builder, params->texture_index_offset,
381 lp_build_const_int32(gallivm, texture_index), "");
382
383 struct lp_build_sample_array_switch switch_info;
384 memset(&switch_info, 0, sizeof(switch_info));
385 lp_build_sample_array_init_soa(&switch_info, gallivm, params, unit,
386 0, sampler->nr_samplers);
387 // build the switch cases
388 for (unsigned i = 0; i < sampler->nr_samplers; i++) {
389 lp_build_sample_array_case_soa(&switch_info, i,
390 &sampler->dynamic_state.static_state[i].texture_state,
391 &sampler->dynamic_state.static_state[i].sampler_state,
392 &sampler->dynamic_state.base);
393 }
394 lp_build_sample_array_fini_soa(&switch_info);
395 } else {
396 lp_build_sample_soa(&sampler->dynamic_state.static_state[texture_index].texture_state,
397 &sampler->dynamic_state.static_state[sampler_index].sampler_state,
398 &sampler->dynamic_state.base,
399 gallivm, params);
400 }
401 }
402
403
404 /**
405 * Fetch the texture size.
406 */
407 static void
lp_llvm_sampler_soa_emit_size_query(const struct lp_build_sampler_soa * base,struct gallivm_state * gallivm,const struct lp_sampler_size_query_params * params)408 lp_llvm_sampler_soa_emit_size_query(const struct lp_build_sampler_soa *base,
409 struct gallivm_state *gallivm,
410 const struct lp_sampler_size_query_params *params)
411 {
412 struct lp_llvm_sampler_soa *sampler = (struct lp_llvm_sampler_soa *)base;
413
414 assert(params->texture_unit < PIPE_MAX_SHADER_SAMPLER_VIEWS);
415
416 lp_build_size_query_soa(gallivm,
417 &sampler->dynamic_state.static_state[params->texture_unit].texture_state,
418 &sampler->dynamic_state.base,
419 params);
420 }
421
422
423 struct lp_build_sampler_soa *
lp_llvm_sampler_soa_create(const struct lp_sampler_static_state * static_state,unsigned nr_samplers)424 lp_llvm_sampler_soa_create(const struct lp_sampler_static_state *static_state,
425 unsigned nr_samplers)
426 {
427 assert(static_state);
428
429 struct lp_llvm_sampler_soa *sampler = CALLOC_STRUCT(lp_llvm_sampler_soa);
430 if (!sampler)
431 return NULL;
432
433 sampler->base.destroy = lp_llvm_sampler_soa_destroy;
434 sampler->base.emit_tex_sample = lp_llvm_sampler_soa_emit_fetch_texel;
435 sampler->base.emit_size_query = lp_llvm_sampler_soa_emit_size_query;
436 sampler->dynamic_state.base.width = lp_llvm_texture_width;
437 sampler->dynamic_state.base.height = lp_llvm_texture_height;
438 sampler->dynamic_state.base.depth = lp_llvm_texture_depth;
439 sampler->dynamic_state.base.first_level = lp_llvm_texture_first_level;
440 sampler->dynamic_state.base.last_level = lp_llvm_texture_last_level;
441 sampler->dynamic_state.base.base_ptr = lp_llvm_texture_base_ptr;
442 sampler->dynamic_state.base.row_stride = lp_llvm_texture_row_stride;
443 sampler->dynamic_state.base.img_stride = lp_llvm_texture_img_stride;
444 sampler->dynamic_state.base.mip_offsets = lp_llvm_texture_mip_offsets;
445 sampler->dynamic_state.base.num_samples = lp_llvm_texture_num_samples;
446 sampler->dynamic_state.base.sample_stride = lp_llvm_texture_sample_stride;
447 sampler->dynamic_state.base.min_lod = lp_llvm_sampler_min_lod;
448 sampler->dynamic_state.base.max_lod = lp_llvm_sampler_max_lod;
449 sampler->dynamic_state.base.lod_bias = lp_llvm_sampler_lod_bias;
450 sampler->dynamic_state.base.border_color = lp_llvm_sampler_border_color;
451 sampler->dynamic_state.base.max_aniso = lp_llvm_sampler_max_aniso;
452
453 #if LP_USE_TEXTURE_CACHE
454 sampler->dynamic_state.base.cache_ptr = lp_llvm_texture_cache_ptr;
455 #endif
456
457 sampler->dynamic_state.static_state = static_state;
458
459 sampler->nr_samplers = nr_samplers;
460 return &sampler->base;
461 }
462
463
464 static void
lp_llvm_image_soa_destroy(struct lp_build_image_soa * image)465 lp_llvm_image_soa_destroy(struct lp_build_image_soa *image)
466 {
467 FREE(image);
468 }
469
470
471 static void
lp_llvm_image_soa_emit_op(const struct lp_build_image_soa * base,struct gallivm_state * gallivm,const struct lp_img_params * params)472 lp_llvm_image_soa_emit_op(const struct lp_build_image_soa *base,
473 struct gallivm_state *gallivm,
474 const struct lp_img_params *params)
475 {
476 struct lp_llvm_image_soa *image = (struct lp_llvm_image_soa *)base;
477 const unsigned image_index = params->image_index;
478 assert(image_index < PIPE_MAX_SHADER_IMAGES);
479
480 if (params->image_index_offset) {
481 struct lp_build_img_op_array_switch switch_info;
482 memset(&switch_info, 0, sizeof(switch_info));
483 LLVMValueRef unit = LLVMBuildAdd(gallivm->builder,
484 params->image_index_offset,
485 lp_build_const_int32(gallivm,
486 image_index), "");
487
488 lp_build_image_op_switch_soa(&switch_info, gallivm, params,
489 unit, 0, image->nr_images);
490
491 for (unsigned i = 0; i < image->nr_images; i++) {
492 lp_build_image_op_array_case(&switch_info, i,
493 &image->dynamic_state.static_state[i].image_state,
494 &image->dynamic_state.base);
495 }
496 lp_build_image_op_array_fini_soa(&switch_info);
497 } else {
498 lp_build_img_op_soa(&image->dynamic_state.static_state[image_index].image_state,
499 &image->dynamic_state.base,
500 gallivm, params, params->outdata);
501 }
502 }
503
504
505 /**
506 * Fetch the texture size.
507 */
508 static void
lp_llvm_image_soa_emit_size_query(const struct lp_build_image_soa * base,struct gallivm_state * gallivm,const struct lp_sampler_size_query_params * params)509 lp_llvm_image_soa_emit_size_query(const struct lp_build_image_soa *base,
510 struct gallivm_state *gallivm,
511 const struct lp_sampler_size_query_params *params)
512 {
513 struct lp_llvm_image_soa *image = (struct lp_llvm_image_soa *)base;
514
515 assert(params->texture_unit < PIPE_MAX_SHADER_IMAGES);
516
517 lp_build_size_query_soa(gallivm,
518 &image->dynamic_state.static_state[params->texture_unit].image_state,
519 &image->dynamic_state.base,
520 params);
521 }
522
523
524 struct lp_build_image_soa *
lp_llvm_image_soa_create(const struct lp_image_static_state * static_state,unsigned nr_images)525 lp_llvm_image_soa_create(const struct lp_image_static_state *static_state,
526 unsigned nr_images)
527 {
528 struct lp_llvm_image_soa *image = CALLOC_STRUCT(lp_llvm_image_soa);
529 if (!image)
530 return NULL;
531
532 image->base.destroy = lp_llvm_image_soa_destroy;
533 image->base.emit_op = lp_llvm_image_soa_emit_op;
534 image->base.emit_size_query = lp_llvm_image_soa_emit_size_query;
535
536 image->dynamic_state.base.width = lp_llvm_image_width;
537 image->dynamic_state.base.height = lp_llvm_image_height;
538
539 image->dynamic_state.base.depth = lp_llvm_image_depth;
540 image->dynamic_state.base.base_ptr = lp_llvm_image_base_ptr;
541 image->dynamic_state.base.row_stride = lp_llvm_image_row_stride;
542 image->dynamic_state.base.img_stride = lp_llvm_image_img_stride;
543 image->dynamic_state.base.num_samples = lp_llvm_image_num_samples;
544 image->dynamic_state.base.sample_stride = lp_llvm_image_sample_stride;
545
546 image->dynamic_state.static_state = static_state;
547
548 image->nr_images = nr_images;
549 return &image->base;
550 }
551