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  * Largely a copy of llvmpipe's lp_tex_sample.c
30  */
31 
32 /**
33  * Texture sampling code generation
34  *
35  * This file is nothing more than ugly glue between three largely independent
36  * entities:
37  * - TGSI -> LLVM translation (i.e., lp_build_tgsi_soa)
38  * - texture sampling code generation (i.e., lp_build_sample_soa)
39  * - SWR driver
40  *
41  * All interesting code is in the functions mentioned above. There is really
42  * nothing to see here.
43  *
44  * @author Jose Fonseca <jfonseca@vmware.com>
45  */
46 
47 #include "state.h"
48 #include "JitManager.h"
49 #include "gen_state_llvm.h"
50 
51 #include "pipe/p_defines.h"
52 #include "pipe/p_shader_tokens.h"
53 #include "gallivm/lp_bld_debug.h"
54 #include "gallivm/lp_bld_const.h"
55 #include "gallivm/lp_bld_type.h"
56 #include "gallivm/lp_bld_sample.h"
57 #include "gallivm/lp_bld_tgsi.h"
58 #include "util/u_memory.h"
59 
60 #include "swr_tex_sample.h"
61 #include "gen_swr_context_llvm.h"
62 
63 using namespace SwrJit;
64 
65 /**
66  * This provides the bridge between the sampler state store in
67  * lp_jit_context and lp_jit_texture and the sampler code
68  * generator. It provides the texture layout information required by
69  * the texture sampler code generator in terms of the state stored in
70  * lp_jit_context and lp_jit_texture in runtime.
71  */
72 struct swr_sampler_dynamic_state {
73    struct lp_sampler_dynamic_state base;
74 
75    const struct swr_sampler_static_state *static_state;
76 
77    enum pipe_shader_type shader_type;
78 };
79 
80 
81 /**
82  * This is the bridge between our sampler and the TGSI translator.
83  */
84 struct swr_sampler_soa {
85    struct lp_build_sampler_soa base;
86 
87    struct swr_sampler_dynamic_state dynamic_state;
88 };
89 
90 
91 /**
92  * Fetch the specified member of the lp_jit_texture structure.
93  * \param emit_load  if TRUE, emit the LLVM load instruction to actually
94  *                   fetch the field's value.  Otherwise, just emit the
95  *                   GEP code to address the field.
96  *
97  * @sa http://llvm.org/docs/GetElementPtr.html
98  */
99 static LLVMValueRef
swr_texture_member(const struct lp_sampler_dynamic_state * base,struct gallivm_state * gallivm,LLVMValueRef context_ptr,unsigned texture_unit,unsigned member_index,const char * member_name,boolean emit_load)100 swr_texture_member(const struct lp_sampler_dynamic_state *base,
101                    struct gallivm_state *gallivm,
102                    LLVMValueRef context_ptr,
103                    unsigned texture_unit,
104                    unsigned member_index,
105                    const char *member_name,
106                    boolean emit_load)
107 {
108    LLVMBuilderRef builder = gallivm->builder;
109    LLVMValueRef indices[4];
110    LLVMValueRef ptr;
111    LLVMValueRef res;
112 
113    assert(texture_unit < PIPE_MAX_SHADER_SAMPLER_VIEWS);
114 
115    /* context[0] */
116    indices[0] = lp_build_const_int32(gallivm, 0);
117    /* context[0].textures */
118    auto dynamic = (const struct swr_sampler_dynamic_state *)base;
119    switch (dynamic->shader_type) {
120    case PIPE_SHADER_FRAGMENT:
121       indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesFS);
122       break;
123    case PIPE_SHADER_VERTEX:
124       indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesVS);
125       break;
126    case PIPE_SHADER_GEOMETRY:
127       indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesGS);
128       break;
129    default:
130       assert(0 && "unsupported shader type");
131       break;
132    }
133    /* context[0].textures[unit] */
134    indices[2] = lp_build_const_int32(gallivm, texture_unit);
135    /* context[0].textures[unit].member */
136    indices[3] = lp_build_const_int32(gallivm, member_index);
137 
138    ptr = LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), "");
139 
140    if (emit_load)
141       res = LLVMBuildLoad(builder, ptr, "");
142    else
143       res = ptr;
144 
145    lp_build_name(res, "context.texture%u.%s", texture_unit, member_name);
146 
147    return res;
148 }
149 
150 
151 /**
152  * Helper macro to instantiate the functions that generate the code to
153  * fetch the members of lp_jit_texture to fulfill the sampler code
154  * generator requests.
155  *
156  * This complexity is the price we have to pay to keep the texture
157  * sampler code generator a reusable module without dependencies to
158  * swr internals.
159  */
160 #define SWR_TEXTURE_MEMBER(_name, _emit_load)                                \
161    static LLVMValueRef swr_texture_##_name(                                  \
162       const struct lp_sampler_dynamic_state *base,                           \
163       struct gallivm_state *gallivm,                                         \
164       LLVMValueRef context_ptr,                                              \
165       unsigned texture_unit)                                                 \
166    {                                                                         \
167       return swr_texture_member(base,                                        \
168                                 gallivm,                                     \
169                                 context_ptr,                                 \
170                                 texture_unit,                                \
171                                 swr_jit_texture_##_name,                     \
172                                 #_name,                                      \
173                                 _emit_load);                                 \
174    }
175 
176 
SWR_TEXTURE_MEMBER(width,TRUE)177 SWR_TEXTURE_MEMBER(width, TRUE)
178 SWR_TEXTURE_MEMBER(height, TRUE)
179 SWR_TEXTURE_MEMBER(depth, TRUE)
180 SWR_TEXTURE_MEMBER(first_level, TRUE)
181 SWR_TEXTURE_MEMBER(last_level, TRUE)
182 SWR_TEXTURE_MEMBER(base_ptr, TRUE)
183 SWR_TEXTURE_MEMBER(row_stride, FALSE)
184 SWR_TEXTURE_MEMBER(img_stride, FALSE)
185 SWR_TEXTURE_MEMBER(mip_offsets, FALSE)
186 
187 
188 /**
189  * Fetch the specified member of the lp_jit_sampler structure.
190  * \param emit_load  if TRUE, emit the LLVM load instruction to actually
191  *                   fetch the field's value.  Otherwise, just emit the
192  *                   GEP code to address the field.
193  *
194  * @sa http://llvm.org/docs/GetElementPtr.html
195  */
196 static LLVMValueRef
197 swr_sampler_member(const struct lp_sampler_dynamic_state *base,
198                    struct gallivm_state *gallivm,
199                    LLVMValueRef context_ptr,
200                    unsigned sampler_unit,
201                    unsigned member_index,
202                    const char *member_name,
203                    boolean emit_load)
204 {
205    LLVMBuilderRef builder = gallivm->builder;
206    LLVMValueRef indices[4];
207    LLVMValueRef ptr;
208    LLVMValueRef res;
209 
210    assert(sampler_unit < PIPE_MAX_SAMPLERS);
211 
212    /* context[0] */
213    indices[0] = lp_build_const_int32(gallivm, 0);
214    /* context[0].samplers */
215    auto dynamic = (const struct swr_sampler_dynamic_state *)base;
216    switch (dynamic->shader_type) {
217    case PIPE_SHADER_FRAGMENT:
218       indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersFS);
219       break;
220    case PIPE_SHADER_VERTEX:
221       indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersVS);
222       break;
223    case PIPE_SHADER_GEOMETRY:
224       indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersGS);
225       break;
226    default:
227       assert(0 && "unsupported shader type");
228       break;
229    }
230    /* context[0].samplers[unit] */
231    indices[2] = lp_build_const_int32(gallivm, sampler_unit);
232    /* context[0].samplers[unit].member */
233    indices[3] = lp_build_const_int32(gallivm, member_index);
234 
235    ptr = LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), "");
236 
237    if (emit_load)
238       res = LLVMBuildLoad(builder, ptr, "");
239    else
240       res = ptr;
241 
242    lp_build_name(res, "context.sampler%u.%s", sampler_unit, member_name);
243 
244    return res;
245 }
246 
247 
248 #define SWR_SAMPLER_MEMBER(_name, _emit_load)                                \
249    static LLVMValueRef swr_sampler_##_name(                                  \
250       const struct lp_sampler_dynamic_state *base,                           \
251       struct gallivm_state *gallivm,                                         \
252       LLVMValueRef context_ptr,                                              \
253       unsigned sampler_unit)                                                 \
254    {                                                                         \
255       return swr_sampler_member(base,                                        \
256                                 gallivm,                                     \
257                                 context_ptr,                                 \
258                                 sampler_unit,                                \
259                                 swr_jit_sampler_##_name,                     \
260                                 #_name,                                      \
261                                 _emit_load);                                 \
262    }
263 
264 
SWR_SAMPLER_MEMBER(min_lod,TRUE)265 SWR_SAMPLER_MEMBER(min_lod, TRUE)
266 SWR_SAMPLER_MEMBER(max_lod, TRUE)
267 SWR_SAMPLER_MEMBER(lod_bias, TRUE)
268 SWR_SAMPLER_MEMBER(border_color, FALSE)
269 
270 
271 static void
272 swr_sampler_soa_destroy(struct lp_build_sampler_soa *sampler)
273 {
274    FREE(sampler);
275 }
276 
277 
278 /**
279  * Fetch filtered values from texture.
280  * The 'texel' parameter returns four vectors corresponding to R, G, B, A.
281  */
282 static void
swr_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa * base,struct gallivm_state * gallivm,const struct lp_sampler_params * params)283 swr_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base,
284                                  struct gallivm_state *gallivm,
285                                  const struct lp_sampler_params *params)
286 {
287    struct swr_sampler_soa *sampler = (struct swr_sampler_soa *)base;
288    unsigned texture_index = params->texture_index;
289    unsigned sampler_index = params->sampler_index;
290 
291    assert(sampler_index < PIPE_MAX_SAMPLERS);
292    assert(texture_index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
293 
294 #if 0
295       lp_build_sample_nop(gallivm, params->type, params->coords, params->texel);
296 #else
297    lp_build_sample_soa(
298       &sampler->dynamic_state.static_state[texture_index].texture_state,
299       &sampler->dynamic_state.static_state[sampler_index].sampler_state,
300       &sampler->dynamic_state.base,
301       gallivm,
302       params);
303 #endif
304 }
305 
306 /**
307  * Fetch the texture size.
308  */
309 static void
swr_sampler_soa_emit_size_query(const struct lp_build_sampler_soa * base,struct gallivm_state * gallivm,const struct lp_sampler_size_query_params * params)310 swr_sampler_soa_emit_size_query(const struct lp_build_sampler_soa *base,
311                                 struct gallivm_state *gallivm,
312                                 const struct lp_sampler_size_query_params *params)
313 {
314    struct swr_sampler_soa *sampler = (struct swr_sampler_soa *)base;
315 
316    assert(params->texture_unit < PIPE_MAX_SHADER_SAMPLER_VIEWS);
317 
318    lp_build_size_query_soa(
319       gallivm,
320       &sampler->dynamic_state.static_state[params->texture_unit].texture_state,
321       &sampler->dynamic_state.base,
322       params);
323 }
324 
325 
326 struct lp_build_sampler_soa *
swr_sampler_soa_create(const struct swr_sampler_static_state * static_state,enum pipe_shader_type shader_type)327 swr_sampler_soa_create(const struct swr_sampler_static_state *static_state,
328                        enum pipe_shader_type shader_type)
329 {
330    struct swr_sampler_soa *sampler;
331 
332    sampler = CALLOC_STRUCT(swr_sampler_soa);
333    if (!sampler)
334       return NULL;
335 
336    sampler->base.destroy = swr_sampler_soa_destroy;
337    sampler->base.emit_tex_sample = swr_sampler_soa_emit_fetch_texel;
338    sampler->base.emit_size_query = swr_sampler_soa_emit_size_query;
339    sampler->dynamic_state.base.width = swr_texture_width;
340    sampler->dynamic_state.base.height = swr_texture_height;
341    sampler->dynamic_state.base.depth = swr_texture_depth;
342    sampler->dynamic_state.base.first_level = swr_texture_first_level;
343    sampler->dynamic_state.base.last_level = swr_texture_last_level;
344    sampler->dynamic_state.base.base_ptr = swr_texture_base_ptr;
345    sampler->dynamic_state.base.row_stride = swr_texture_row_stride;
346    sampler->dynamic_state.base.img_stride = swr_texture_img_stride;
347    sampler->dynamic_state.base.mip_offsets = swr_texture_mip_offsets;
348    sampler->dynamic_state.base.min_lod = swr_sampler_min_lod;
349    sampler->dynamic_state.base.max_lod = swr_sampler_max_lod;
350    sampler->dynamic_state.base.lod_bias = swr_sampler_lod_bias;
351    sampler->dynamic_state.base.border_color = swr_sampler_border_color;
352 
353    sampler->dynamic_state.static_state = static_state;
354 
355    sampler->dynamic_state.shader_type = shader_type;
356 
357    return &sampler->base;
358 }
359