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 63using 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 */ 72struct 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 */ 84struct 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 */ 99static LLVMValueRef 100swr_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 177SWR_TEXTURE_MEMBER(width, TRUE) 178SWR_TEXTURE_MEMBER(height, TRUE) 179SWR_TEXTURE_MEMBER(depth, TRUE) 180SWR_TEXTURE_MEMBER(first_level, TRUE) 181SWR_TEXTURE_MEMBER(last_level, TRUE) 182SWR_TEXTURE_MEMBER(base_ptr, TRUE) 183SWR_TEXTURE_MEMBER(row_stride, FALSE) 184SWR_TEXTURE_MEMBER(img_stride, FALSE) 185SWR_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 */ 196static LLVMValueRef 197swr_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 265SWR_SAMPLER_MEMBER(min_lod, TRUE) 266SWR_SAMPLER_MEMBER(max_lod, TRUE) 267SWR_SAMPLER_MEMBER(lod_bias, TRUE) 268SWR_SAMPLER_MEMBER(border_color, FALSE) 269 270 271static void 272swr_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 */ 282static void 283swr_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 */ 309static void 310swr_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 326struct lp_build_sampler_soa * 327swr_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