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_surf_state_llvm.h" 62#include "gen_swr_context_llvm.h" 63 64using namespace SwrJit; 65 66/** 67 * This provides the bridge between the sampler state store in 68 * lp_jit_context and lp_jit_texture and the sampler code 69 * generator. It provides the texture layout information required by 70 * the texture sampler code generator in terms of the state stored in 71 * lp_jit_context and lp_jit_texture in runtime. 72 */ 73struct swr_sampler_dynamic_state { 74 struct lp_sampler_dynamic_state base; 75 76 const struct swr_sampler_static_state *static_state; 77 78 enum pipe_shader_type shader_type; 79}; 80 81 82/** 83 * This is the bridge between our sampler and the TGSI translator. 84 */ 85struct swr_sampler_soa { 86 struct lp_build_sampler_soa base; 87 88 struct swr_sampler_dynamic_state dynamic_state; 89}; 90 91 92/** 93 * Fetch the specified member of the lp_jit_texture structure. 94 * \param emit_load if TRUE, emit the LLVM load instruction to actually 95 * fetch the field's value. Otherwise, just emit the 96 * GEP code to address the field. 97 * 98 * @sa http://llvm.org/docs/GetElementPtr.html 99 */ 100static LLVMValueRef 101swr_texture_member(const struct lp_sampler_dynamic_state *base, 102 struct gallivm_state *gallivm, 103 LLVMValueRef context_ptr, 104 unsigned texture_unit, 105 unsigned member_index, 106 const char *member_name, 107 boolean emit_load) 108{ 109 LLVMBuilderRef builder = gallivm->builder; 110 LLVMValueRef indices[4]; 111 LLVMValueRef ptr; 112 LLVMValueRef res; 113 114 assert(texture_unit < PIPE_MAX_SHADER_SAMPLER_VIEWS); 115 116 /* context[0] */ 117 indices[0] = lp_build_const_int32(gallivm, 0); 118 /* context[0].textures */ 119 auto dynamic = (const struct swr_sampler_dynamic_state *)base; 120 switch (dynamic->shader_type) { 121 case PIPE_SHADER_FRAGMENT: 122 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesFS); 123 break; 124 case PIPE_SHADER_VERTEX: 125 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesVS); 126 break; 127 case PIPE_SHADER_GEOMETRY: 128 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesGS); 129 break; 130 case PIPE_SHADER_TESS_CTRL: 131 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesTCS); 132 break; 133 case PIPE_SHADER_TESS_EVAL: 134 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_texturesTES); 135 break; 136 default: 137 assert(0 && "unsupported shader type"); 138 break; 139 } 140 /* context[0].textures[unit] */ 141 indices[2] = lp_build_const_int32(gallivm, texture_unit); 142 /* context[0].textures[unit].member */ 143 indices[3] = lp_build_const_int32(gallivm, member_index); 144 145 ptr = LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), ""); 146 147 if (emit_load) 148 res = LLVMBuildLoad(builder, ptr, ""); 149 else 150 res = 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 * swr internals. 166 */ 167#define SWR_TEXTURE_MEMBER(_name, _emit_load) \ 168 static LLVMValueRef swr_texture_##_name( \ 169 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 swr_texture_member(base, \ 176 gallivm, \ 177 context_ptr, \ 178 texture_unit, \ 179 swr_jit_texture_##_name, \ 180 #_name, \ 181 _emit_load); \ 182 } 183 184 185SWR_TEXTURE_MEMBER(width, TRUE) 186SWR_TEXTURE_MEMBER(height, TRUE) 187SWR_TEXTURE_MEMBER(depth, TRUE) 188SWR_TEXTURE_MEMBER(first_level, TRUE) 189SWR_TEXTURE_MEMBER(last_level, TRUE) 190SWR_TEXTURE_MEMBER(base_ptr, TRUE) 191SWR_TEXTURE_MEMBER(num_samples, TRUE) 192SWR_TEXTURE_MEMBER(sample_stride, TRUE) 193SWR_TEXTURE_MEMBER(row_stride, FALSE) 194SWR_TEXTURE_MEMBER(img_stride, FALSE) 195SWR_TEXTURE_MEMBER(mip_offsets, FALSE) 196 197 198/** 199 * Fetch the specified member of the lp_jit_sampler structure. 200 * \param emit_load if TRUE, emit the LLVM load instruction to actually 201 * fetch the field's value. Otherwise, just emit the 202 * GEP code to address the field. 203 * 204 * @sa http://llvm.org/docs/GetElementPtr.html 205 */ 206static LLVMValueRef 207swr_sampler_member(const struct lp_sampler_dynamic_state *base, 208 struct gallivm_state *gallivm, 209 LLVMValueRef context_ptr, 210 unsigned sampler_unit, 211 unsigned member_index, 212 const char *member_name, 213 boolean emit_load) 214{ 215 LLVMBuilderRef builder = gallivm->builder; 216 LLVMValueRef indices[4]; 217 LLVMValueRef ptr; 218 LLVMValueRef res; 219 220 assert(sampler_unit < PIPE_MAX_SAMPLERS); 221 222 /* context[0] */ 223 indices[0] = lp_build_const_int32(gallivm, 0); 224 /* context[0].samplers */ 225 auto dynamic = (const struct swr_sampler_dynamic_state *)base; 226 switch (dynamic->shader_type) { 227 case PIPE_SHADER_FRAGMENT: 228 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersFS); 229 break; 230 case PIPE_SHADER_VERTEX: 231 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersVS); 232 break; 233 case PIPE_SHADER_GEOMETRY: 234 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersGS); 235 break; 236 case PIPE_SHADER_TESS_CTRL: 237 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersTCS); 238 break; 239 case PIPE_SHADER_TESS_EVAL: 240 indices[1] = lp_build_const_int32(gallivm, swr_draw_context_samplersTES); 241 break; 242 default: 243 assert(0 && "unsupported shader type"); 244 break; 245 } 246 /* context[0].samplers[unit] */ 247 indices[2] = lp_build_const_int32(gallivm, sampler_unit); 248 /* context[0].samplers[unit].member */ 249 indices[3] = lp_build_const_int32(gallivm, member_index); 250 251 ptr = LLVMBuildGEP(builder, context_ptr, indices, ARRAY_SIZE(indices), ""); 252 253 if (emit_load) 254 res = LLVMBuildLoad(builder, ptr, ""); 255 else 256 res = ptr; 257 258 lp_build_name(res, "context.sampler%u.%s", sampler_unit, member_name); 259 260 return res; 261} 262 263 264#define SWR_SAMPLER_MEMBER(_name, _emit_load) \ 265 static LLVMValueRef swr_sampler_##_name( \ 266 const struct lp_sampler_dynamic_state *base, \ 267 struct gallivm_state *gallivm, \ 268 LLVMValueRef context_ptr, \ 269 unsigned sampler_unit) \ 270 { \ 271 return swr_sampler_member(base, \ 272 gallivm, \ 273 context_ptr, \ 274 sampler_unit, \ 275 swr_jit_sampler_##_name, \ 276 #_name, \ 277 _emit_load); \ 278 } 279 280 281SWR_SAMPLER_MEMBER(min_lod, TRUE) 282SWR_SAMPLER_MEMBER(max_lod, TRUE) 283SWR_SAMPLER_MEMBER(lod_bias, TRUE) 284SWR_SAMPLER_MEMBER(border_color, FALSE) 285 286 287static void 288swr_sampler_soa_destroy(struct lp_build_sampler_soa *sampler) 289{ 290 FREE(sampler); 291} 292 293 294/** 295 * Fetch filtered values from texture. 296 * The 'texel' parameter returns four vectors corresponding to R, G, B, A. 297 */ 298static void 299swr_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base, 300 struct gallivm_state *gallivm, 301 const struct lp_sampler_params *params) 302{ 303 struct swr_sampler_soa *sampler = (struct swr_sampler_soa *)base; 304 unsigned texture_index = params->texture_index; 305 unsigned sampler_index = params->sampler_index; 306 307 assert(sampler_index < PIPE_MAX_SAMPLERS); 308 assert(texture_index < PIPE_MAX_SHADER_SAMPLER_VIEWS); 309 310#if 0 311 lp_build_sample_nop(gallivm, params->type, params->coords, params->texel); 312#else 313 lp_build_sample_soa( 314 &sampler->dynamic_state.static_state[texture_index].texture_state, 315 &sampler->dynamic_state.static_state[sampler_index].sampler_state, 316 &sampler->dynamic_state.base, 317 gallivm, 318 params); 319#endif 320} 321 322/** 323 * Fetch the texture size. 324 */ 325static void 326swr_sampler_soa_emit_size_query(const struct lp_build_sampler_soa *base, 327 struct gallivm_state *gallivm, 328 const struct lp_sampler_size_query_params *params) 329{ 330 struct swr_sampler_soa *sampler = (struct swr_sampler_soa *)base; 331 332 assert(params->texture_unit < PIPE_MAX_SHADER_SAMPLER_VIEWS); 333 334 lp_build_size_query_soa( 335 gallivm, 336 &sampler->dynamic_state.static_state[params->texture_unit].texture_state, 337 &sampler->dynamic_state.base, 338 params); 339} 340 341 342struct lp_build_sampler_soa * 343swr_sampler_soa_create(const struct swr_sampler_static_state *static_state, 344 enum pipe_shader_type shader_type) 345{ 346 struct swr_sampler_soa *sampler; 347 348 sampler = CALLOC_STRUCT(swr_sampler_soa); 349 if (!sampler) 350 return NULL; 351 352 sampler->base.destroy = swr_sampler_soa_destroy; 353 sampler->base.emit_tex_sample = swr_sampler_soa_emit_fetch_texel; 354 sampler->base.emit_size_query = swr_sampler_soa_emit_size_query; 355 sampler->dynamic_state.base.width = swr_texture_width; 356 sampler->dynamic_state.base.height = swr_texture_height; 357 sampler->dynamic_state.base.depth = swr_texture_depth; 358 sampler->dynamic_state.base.first_level = swr_texture_first_level; 359 sampler->dynamic_state.base.last_level = swr_texture_last_level; 360 sampler->dynamic_state.base.base_ptr = swr_texture_base_ptr; 361 sampler->dynamic_state.base.row_stride = swr_texture_row_stride; 362 sampler->dynamic_state.base.img_stride = swr_texture_img_stride; 363 sampler->dynamic_state.base.mip_offsets = swr_texture_mip_offsets; 364 sampler->dynamic_state.base.num_samples = swr_texture_num_samples; 365 sampler->dynamic_state.base.sample_stride = swr_texture_sample_stride; 366 sampler->dynamic_state.base.min_lod = swr_sampler_min_lod; 367 sampler->dynamic_state.base.max_lod = swr_sampler_max_lod; 368 sampler->dynamic_state.base.lod_bias = swr_sampler_lod_bias; 369 sampler->dynamic_state.base.border_color = swr_sampler_border_color; 370 371 sampler->dynamic_state.static_state = static_state; 372 373 sampler->dynamic_state.shader_type = shader_type; 374 375 return &sampler->base; 376} 377