mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-09 04:38:03 +02:00
llvmpipe: Further abstract the texture sampling generation from TGSI translation.
This commit is contained in:
parent
970823978c
commit
8be72bb764
5 changed files with 186 additions and 125 deletions
|
|
@ -44,14 +44,30 @@ struct lp_build_context;
|
||||||
struct lp_build_mask_context;
|
struct lp_build_mask_context;
|
||||||
|
|
||||||
|
|
||||||
typedef void
|
/**
|
||||||
(*lp_emit_fetch_texel_soa_callback)( LLVMBuilderRef builder,
|
* Sampler code generation interface.
|
||||||
void *context,
|
*
|
||||||
unsigned unit,
|
* Although texture sampling is a requirement for TGSI translation, it is
|
||||||
unsigned num_coords,
|
* a very different problem with several different approaches to it. This
|
||||||
const LLVMValueRef *coords,
|
* structure establishes an interface for texture sampling code generation, so
|
||||||
LLVMValueRef lodbias,
|
* that we can easily use different texture sampling strategies.
|
||||||
LLVMValueRef *texel);
|
*/
|
||||||
|
struct lp_build_sampler_soa
|
||||||
|
{
|
||||||
|
void
|
||||||
|
(*destroy)( struct lp_build_sampler_soa *sampler );
|
||||||
|
|
||||||
|
void
|
||||||
|
(*emit_fetch_texel)( struct lp_build_sampler_soa *sampler,
|
||||||
|
LLVMBuilderRef builder,
|
||||||
|
union lp_type type,
|
||||||
|
unsigned unit,
|
||||||
|
unsigned num_coords,
|
||||||
|
const LLVMValueRef *coords,
|
||||||
|
LLVMValueRef lodbias,
|
||||||
|
LLVMValueRef *texel);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
lp_build_tgsi_soa(LLVMBuilderRef builder,
|
lp_build_tgsi_soa(LLVMBuilderRef builder,
|
||||||
|
|
@ -62,8 +78,7 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
|
||||||
const LLVMValueRef *pos,
|
const LLVMValueRef *pos,
|
||||||
const LLVMValueRef (*inputs)[4],
|
const LLVMValueRef (*inputs)[4],
|
||||||
LLVMValueRef (*outputs)[4],
|
LLVMValueRef (*outputs)[4],
|
||||||
lp_emit_fetch_texel_soa_callback emit_fetch_texel,
|
struct lp_build_sampler_soa *sampler);
|
||||||
void *emit_fetch_texel_context);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* LP_BLD_TGSI_H */
|
#endif /* LP_BLD_TGSI_H */
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,7 @@ struct lp_build_tgsi_soa_context
|
||||||
const LLVMValueRef (*inputs)[NUM_CHANNELS];
|
const LLVMValueRef (*inputs)[NUM_CHANNELS];
|
||||||
LLVMValueRef (*outputs)[NUM_CHANNELS];
|
LLVMValueRef (*outputs)[NUM_CHANNELS];
|
||||||
|
|
||||||
lp_emit_fetch_texel_soa_callback emit_fetch_texel;
|
struct lp_build_sampler_soa *sampler;
|
||||||
void *emit_fetch_texel_context;
|
|
||||||
|
|
||||||
LLVMValueRef immediates[LP_MAX_IMMEDIATES][NUM_CHANNELS];
|
LLVMValueRef immediates[LP_MAX_IMMEDIATES][NUM_CHANNELS];
|
||||||
LLVMValueRef temps[LP_MAX_TEMPS][NUM_CHANNELS];
|
LLVMValueRef temps[LP_MAX_TEMPS][NUM_CHANNELS];
|
||||||
|
|
@ -289,8 +288,11 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
|
||||||
coords[i] = lp_build_mul(&bld->base, coords[i], oow);
|
coords[i] = lp_build_mul(&bld->base, coords[i], oow);
|
||||||
}
|
}
|
||||||
|
|
||||||
bld->emit_fetch_texel(bld->base.builder, bld->emit_fetch_texel_context,
|
bld->sampler->emit_fetch_texel(bld->sampler,
|
||||||
unit, num_coords, coords, lodbias, texel);
|
bld->base.builder,
|
||||||
|
bld->base.type,
|
||||||
|
unit, num_coords, coords, lodbias,
|
||||||
|
texel);
|
||||||
|
|
||||||
FOR_EACH_DST0_ENABLED_CHANNEL( inst, i ) {
|
FOR_EACH_DST0_ENABLED_CHANNEL( inst, i ) {
|
||||||
emit_store( bld, inst, 0, i, texel[i] );
|
emit_store( bld, inst, 0, i, texel[i] );
|
||||||
|
|
@ -1283,8 +1285,7 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
|
||||||
const LLVMValueRef *pos,
|
const LLVMValueRef *pos,
|
||||||
const LLVMValueRef (*inputs)[NUM_CHANNELS],
|
const LLVMValueRef (*inputs)[NUM_CHANNELS],
|
||||||
LLVMValueRef (*outputs)[NUM_CHANNELS],
|
LLVMValueRef (*outputs)[NUM_CHANNELS],
|
||||||
lp_emit_fetch_texel_soa_callback emit_fetch_texel,
|
struct lp_build_sampler_soa *sampler)
|
||||||
void *emit_fetch_texel_context)
|
|
||||||
{
|
{
|
||||||
struct lp_build_tgsi_soa_context bld;
|
struct lp_build_tgsi_soa_context bld;
|
||||||
struct tgsi_parse_context parse;
|
struct tgsi_parse_context parse;
|
||||||
|
|
@ -1299,8 +1300,7 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
|
||||||
bld.inputs = inputs;
|
bld.inputs = inputs;
|
||||||
bld.outputs = outputs;
|
bld.outputs = outputs;
|
||||||
bld.consts_ptr = consts_ptr;
|
bld.consts_ptr = consts_ptr;
|
||||||
bld.emit_fetch_texel = emit_fetch_texel;
|
bld.sampler = sampler;
|
||||||
bld.emit_fetch_texel_context = emit_fetch_texel_context;
|
|
||||||
|
|
||||||
tgsi_parse_init( &parse, tokens );
|
tgsi_parse_init( &parse, tokens );
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@
|
||||||
#include "lp_context.h"
|
#include "lp_context.h"
|
||||||
#include "lp_state.h"
|
#include "lp_state.h"
|
||||||
#include "lp_quad.h"
|
#include "lp_quad.h"
|
||||||
|
#include "lp_tex_sample.h"
|
||||||
|
|
||||||
|
|
||||||
static const unsigned char quad_offset_x[4] = {0, 1, 0, 1};
|
static const unsigned char quad_offset_x[4] = {0, 1, 0, 1};
|
||||||
|
|
@ -173,107 +174,6 @@ generate_depth(struct llvmpipe_context *lp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct build_fetch_texel_context
|
|
||||||
{
|
|
||||||
LLVMValueRef context_ptr;
|
|
||||||
|
|
||||||
LLVMValueRef samplers_ptr;
|
|
||||||
|
|
||||||
/** Coords/texels store */
|
|
||||||
LLVMValueRef store_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void PIPE_CDECL
|
|
||||||
lp_fetch_texel_soa( struct tgsi_sampler **samplers,
|
|
||||||
uint32_t unit,
|
|
||||||
float *store )
|
|
||||||
{
|
|
||||||
struct tgsi_sampler *sampler = samplers[unit];
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
uint j;
|
|
||||||
|
|
||||||
debug_printf("%s sampler: %p (%p) store: %p\n",
|
|
||||||
__FUNCTION__,
|
|
||||||
sampler, *sampler,
|
|
||||||
store );
|
|
||||||
|
|
||||||
debug_printf("lodbias %f\n", store[12]);
|
|
||||||
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
debug_printf("sample %d texcoord %f %f\n",
|
|
||||||
j,
|
|
||||||
store[0+j],
|
|
||||||
store[4+j]);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
|
||||||
float rgba[NUM_CHANNELS][QUAD_SIZE];
|
|
||||||
sampler->get_samples(sampler,
|
|
||||||
&store[0],
|
|
||||||
&store[4],
|
|
||||||
&store[8],
|
|
||||||
0.0f, /*store[12], lodbias */
|
|
||||||
rgba);
|
|
||||||
memcpy(store, rgba, sizeof rgba);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
debug_printf("sample %d result %f %f %f %f\n",
|
|
||||||
j,
|
|
||||||
store[0+j],
|
|
||||||
store[4+j],
|
|
||||||
store[8+j],
|
|
||||||
store[12+j]);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
emit_fetch_texel( LLVMBuilderRef builder,
|
|
||||||
void *context,
|
|
||||||
unsigned unit,
|
|
||||||
unsigned num_coords,
|
|
||||||
const LLVMValueRef *coords,
|
|
||||||
LLVMValueRef lodbias,
|
|
||||||
LLVMValueRef *texel)
|
|
||||||
{
|
|
||||||
struct build_fetch_texel_context *bld = context;
|
|
||||||
LLVMTypeRef vec_type = LLVMTypeOf(coords[0]);
|
|
||||||
LLVMValueRef args[3];
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
if(!bld->samplers_ptr)
|
|
||||||
bld->samplers_ptr = lp_jit_context_samplers(builder, bld->context_ptr);
|
|
||||||
|
|
||||||
if(!bld->store_ptr)
|
|
||||||
bld->store_ptr = LLVMBuildArrayAlloca(builder,
|
|
||||||
vec_type,
|
|
||||||
LLVMConstInt(LLVMInt32Type(), 4, 0),
|
|
||||||
"texel_store");
|
|
||||||
|
|
||||||
for (i = 0; i < num_coords; i++) {
|
|
||||||
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
|
||||||
LLVMValueRef coord_ptr = LLVMBuildGEP(builder, bld->store_ptr, &index, 1, "");
|
|
||||||
LLVMBuildStore(builder, coords[i], coord_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
args[0] = bld->samplers_ptr;
|
|
||||||
args[1] = LLVMConstInt(LLVMInt32Type(), unit, 0);
|
|
||||||
args[2] = bld->store_ptr;
|
|
||||||
|
|
||||||
lp_build_intrinsic(builder, "fetch_texel", LLVMVoidType(), args, 3);
|
|
||||||
|
|
||||||
for (i = 0; i < NUM_CHANNELS; ++i) {
|
|
||||||
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
|
||||||
LLVMValueRef texel_ptr = LLVMBuildGEP(builder, bld->store_ptr, &index, 1, "");
|
|
||||||
texel[i] = LLVMBuildLoad(builder, texel_ptr, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the fragment shader, depth/stencil test, and alpha tests.
|
* Generate the fragment shader, depth/stencil test, and alpha tests.
|
||||||
*/
|
*/
|
||||||
|
|
@ -286,7 +186,7 @@ generate_fs(struct llvmpipe_context *lp,
|
||||||
LLVMValueRef context_ptr,
|
LLVMValueRef context_ptr,
|
||||||
unsigned i,
|
unsigned i,
|
||||||
const struct lp_build_interp_soa_context *interp,
|
const struct lp_build_interp_soa_context *interp,
|
||||||
struct build_fetch_texel_context *sampler,
|
struct lp_build_sampler_soa *sampler,
|
||||||
LLVMValueRef *pmask,
|
LLVMValueRef *pmask,
|
||||||
LLVMValueRef *color,
|
LLVMValueRef *color,
|
||||||
LLVMValueRef depth_ptr)
|
LLVMValueRef depth_ptr)
|
||||||
|
|
@ -327,7 +227,7 @@ generate_fs(struct llvmpipe_context *lp,
|
||||||
|
|
||||||
lp_build_tgsi_soa(builder, tokens, type, &mask,
|
lp_build_tgsi_soa(builder, tokens, type, &mask,
|
||||||
consts_ptr, interp->pos, interp->inputs,
|
consts_ptr, interp->pos, interp->inputs,
|
||||||
outputs, emit_fetch_texel, sampler);
|
outputs, sampler);
|
||||||
|
|
||||||
for (attrib = 0; attrib < shader->info.num_outputs; ++attrib) {
|
for (attrib = 0; attrib < shader->info.num_outputs; ++attrib) {
|
||||||
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
|
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
|
||||||
|
|
@ -462,7 +362,7 @@ generate_fragment(struct llvmpipe_context *lp,
|
||||||
LLVMBuilderRef builder;
|
LLVMBuilderRef builder;
|
||||||
LLVMValueRef x0;
|
LLVMValueRef x0;
|
||||||
LLVMValueRef y0;
|
LLVMValueRef y0;
|
||||||
struct build_fetch_texel_context sampler;
|
struct lp_build_sampler_soa *sampler;
|
||||||
struct lp_build_interp_soa_context interp;
|
struct lp_build_interp_soa_context interp;
|
||||||
LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
|
LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
|
||||||
LLVMValueRef fs_out_color[NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
|
LLVMValueRef fs_out_color[NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
|
||||||
|
|
@ -586,8 +486,7 @@ generate_fragment(struct llvmpipe_context *lp,
|
||||||
a0_ptr, dadx_ptr, dady_ptr,
|
a0_ptr, dadx_ptr, dady_ptr,
|
||||||
x0, y0, 2, 0);
|
x0, y0, 2, 0);
|
||||||
|
|
||||||
memset(&sampler, 0, sizeof sampler);
|
sampler = lp_c_sampler_soa_create(context_ptr);
|
||||||
sampler.context_ptr = context_ptr;
|
|
||||||
|
|
||||||
for(i = 0; i < num_fs; ++i) {
|
for(i = 0; i < num_fs; ++i) {
|
||||||
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
||||||
|
|
@ -606,7 +505,7 @@ generate_fragment(struct llvmpipe_context *lp,
|
||||||
context_ptr,
|
context_ptr,
|
||||||
i,
|
i,
|
||||||
&interp,
|
&interp,
|
||||||
&sampler,
|
sampler,
|
||||||
&fs_mask[i],
|
&fs_mask[i],
|
||||||
out_color,
|
out_color,
|
||||||
depth_ptr_i);
|
depth_ptr_i);
|
||||||
|
|
@ -615,6 +514,8 @@ generate_fragment(struct llvmpipe_context *lp,
|
||||||
fs_out_color[chan][i] = out_color[chan];
|
fs_out_color[chan][i] = out_color[chan];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sampler->destroy(sampler);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert the fs's output color and mask to fit to the blending type.
|
* Convert the fs's output color and mask to fit to the blending type.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1578,3 +1578,136 @@ out:
|
||||||
tgsi_sampler->get_samples( tgsi_sampler, s, t, p, lodbias, rgba );
|
tgsi_sampler->get_samples( tgsi_sampler, s, t, p, lodbias, rgba );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIPE_CDECL
|
||||||
|
lp_fetch_texel_soa( struct tgsi_sampler **samplers,
|
||||||
|
uint32_t unit,
|
||||||
|
float *store )
|
||||||
|
{
|
||||||
|
struct tgsi_sampler *sampler = samplers[unit];
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
uint j;
|
||||||
|
|
||||||
|
debug_printf("%s sampler: %p (%p) store: %p\n",
|
||||||
|
__FUNCTION__,
|
||||||
|
sampler, *sampler,
|
||||||
|
store );
|
||||||
|
|
||||||
|
debug_printf("lodbias %f\n", store[12]);
|
||||||
|
|
||||||
|
for (j = 0; j < 4; j++)
|
||||||
|
debug_printf("sample %d texcoord %f %f\n",
|
||||||
|
j,
|
||||||
|
store[0+j],
|
||||||
|
store[4+j]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
float rgba[NUM_CHANNELS][QUAD_SIZE];
|
||||||
|
sampler->get_samples(sampler,
|
||||||
|
&store[0],
|
||||||
|
&store[4],
|
||||||
|
&store[8],
|
||||||
|
0.0f, /*store[12], lodbias */
|
||||||
|
rgba);
|
||||||
|
memcpy(store, rgba, sizeof rgba);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
for (j = 0; j < 4; j++)
|
||||||
|
debug_printf("sample %d result %f %f %f %f\n",
|
||||||
|
j,
|
||||||
|
store[0+j],
|
||||||
|
store[4+j],
|
||||||
|
store[8+j],
|
||||||
|
store[12+j]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "lp_bld_type.h"
|
||||||
|
#include "lp_bld_intr.h"
|
||||||
|
#include "lp_bld_tgsi.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct lp_c_sampler_soa
|
||||||
|
{
|
||||||
|
struct lp_build_sampler_soa base;
|
||||||
|
|
||||||
|
LLVMValueRef context_ptr;
|
||||||
|
|
||||||
|
LLVMValueRef samplers_ptr;
|
||||||
|
|
||||||
|
/** Coords/texels store */
|
||||||
|
LLVMValueRef store_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
lp_c_sampler_soa_destroy(struct lp_build_sampler_soa *sampler)
|
||||||
|
{
|
||||||
|
FREE(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
lp_c_sampler_soa_emit_fetch_texel(struct lp_build_sampler_soa *_sampler,
|
||||||
|
LLVMBuilderRef builder,
|
||||||
|
union lp_type type,
|
||||||
|
unsigned unit,
|
||||||
|
unsigned num_coords,
|
||||||
|
const LLVMValueRef *coords,
|
||||||
|
LLVMValueRef lodbias,
|
||||||
|
LLVMValueRef *texel)
|
||||||
|
{
|
||||||
|
struct lp_c_sampler_soa *sampler = (struct lp_c_sampler_soa *)_sampler;
|
||||||
|
LLVMTypeRef vec_type = LLVMTypeOf(coords[0]);
|
||||||
|
LLVMValueRef args[3];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if(!sampler->samplers_ptr)
|
||||||
|
sampler->samplers_ptr = lp_jit_context_samplers(builder, sampler->context_ptr);
|
||||||
|
|
||||||
|
if(!sampler->store_ptr)
|
||||||
|
sampler->store_ptr = LLVMBuildArrayAlloca(builder,
|
||||||
|
vec_type,
|
||||||
|
LLVMConstInt(LLVMInt32Type(), 4, 0),
|
||||||
|
"texel_store");
|
||||||
|
|
||||||
|
for (i = 0; i < num_coords; i++) {
|
||||||
|
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
||||||
|
LLVMValueRef coord_ptr = LLVMBuildGEP(builder, sampler->store_ptr, &index, 1, "");
|
||||||
|
LLVMBuildStore(builder, coords[i], coord_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
args[0] = sampler->samplers_ptr;
|
||||||
|
args[1] = LLVMConstInt(LLVMInt32Type(), unit, 0);
|
||||||
|
args[2] = sampler->store_ptr;
|
||||||
|
|
||||||
|
lp_build_intrinsic(builder, "fetch_texel", LLVMVoidType(), args, 3);
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_CHANNELS; ++i) {
|
||||||
|
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
|
||||||
|
LLVMValueRef texel_ptr = LLVMBuildGEP(builder, sampler->store_ptr, &index, 1, "");
|
||||||
|
texel[i] = LLVMBuildLoad(builder, texel_ptr, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct lp_build_sampler_soa *
|
||||||
|
lp_c_sampler_soa_create(LLVMValueRef context_ptr)
|
||||||
|
{
|
||||||
|
struct lp_c_sampler_soa *sampler;
|
||||||
|
|
||||||
|
sampler = CALLOC_STRUCT(lp_c_sampler_soa);
|
||||||
|
if(!sampler)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sampler->base.destroy = lp_c_sampler_soa_destroy;
|
||||||
|
sampler->base.emit_fetch_texel = lp_c_sampler_soa_emit_fetch_texel;
|
||||||
|
sampler->context_ptr = context_ptr;
|
||||||
|
|
||||||
|
return &sampler->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@
|
||||||
#define LP_TEX_SAMPLE_H
|
#define LP_TEX_SAMPLE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <llvm-c/Core.h>
|
||||||
|
|
||||||
#include "tgsi/tgsi_exec.h"
|
#include "tgsi/tgsi_exec.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -75,4 +77,14 @@ lp_get_samples(struct tgsi_sampler *tgsi_sampler,
|
||||||
float rgba[NUM_CHANNELS][QUAD_SIZE]);
|
float rgba[NUM_CHANNELS][QUAD_SIZE]);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Texture sampling code generator that just calls lp_get_samples C function
|
||||||
|
* for the actual sampling computation.
|
||||||
|
*
|
||||||
|
* @param context_ptr LLVM value with the pointer to the struct lp_jit_context.
|
||||||
|
*/
|
||||||
|
struct lp_build_sampler_soa *
|
||||||
|
lp_c_sampler_soa_create(LLVMValueRef context_ptr);
|
||||||
|
|
||||||
|
|
||||||
#endif /* LP_TEX_SAMPLE_H */
|
#endif /* LP_TEX_SAMPLE_H */
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue