env.Program(
target = 'lp_test_blend',
- source = ['lp_test_blend.c'],
+ source = ['lp_test_blend.c', 'lp_test_main.c'],
)
Export('llvmpipe')
*/
#define LP_MAX_VECTOR_LENGTH 16
+#define LP_MAX_TYPE_WIDTH 64
+
/**
* The LLVM type system can't conveniently express all the things we care about
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * Shared testing code.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ */
+
+
+#ifndef LP_TEST_H
+#define LP_TEST_H
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <float.h>
+
+#include <llvm-c/Core.h>
+#include <llvm-c/Analysis.h>
+#include <llvm-c/ExecutionEngine.h>
+#include <llvm-c/Target.h>
+#include <llvm-c/BitWriter.h>
+#include <llvm-c/Transforms/Scalar.h>
+
+#include "pipe/p_state.h"
+#include "util/u_format.h"
+#include "util/u_math.h"
+#include "util/u_debug_dump.h"
+
+#include "lp_bld_type.h"
+
+
+void
+write_tsv_header(FILE *fp);
+
+
+boolean
+test_some(unsigned verbose, FILE *fp, unsigned long n);
+
+
+boolean
+test_all(unsigned verbose, FILE *fp);
+
+
+static INLINE uint64_t
+rdtsc(void)
+{
+#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
+ uint32_t hi, lo;
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((uint64_t)lo) | (((uint64_t)hi) << 32);
+#else
+ return 0;
+#endif
+}
+
+
+float
+random_float(void);
+
+
+void
+dump_type(FILE *fp, union lp_type type);
+
+
+double
+read_elem(union lp_type type, const void *src, unsigned index);
+
+
+void
+write_elem(union lp_type type, void *dst, unsigned index, double src);
+
+
+void
+random_elem(union lp_type type, void *dst, unsigned index);
+
+
+void
+read_vec(union lp_type type, const void *src, double *dst);
+
+
+void
+write_vec(union lp_type type, void *dst, const double *src);
+
+
+void
+random_vec(union lp_type type, void *dst);
+
+
+boolean
+compare_vec(union lp_type type, const void *res, const double *ref);
+
+
+void
+dump_vec(FILE *fp, union lp_type type, const void *src);
+
+
+#endif /* !LP_TEST_H */
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <float.h>
-
-#include <llvm-c/Core.h>
-#include <llvm-c/Analysis.h>
-#include <llvm-c/ExecutionEngine.h>
-#include <llvm-c/Target.h>
-#include <llvm-c/BitWriter.h>
-#include <llvm-c/Transforms/Scalar.h>
-
-#include "pipe/p_state.h"
-#include "util/u_format.h"
-#include "util/u_math.h"
-#include "util/u_debug_dump.h"
-
#include "lp_bld.h"
#include "lp_bld_type.h"
#include "lp_bld_arit.h"
-
-
-unsigned verbose = 0;
+#include "lp_test.h"
typedef void (*blend_test_ptr_t)(const void *src, const void *dst, const void *con, void *res);
-static void
+void
write_tsv_header(FILE *fp)
{
fprintf(fp,
}
-static INLINE uint64_t
-rdtsc(void)
-{
-#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
- uint32_t hi, lo;
- __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
- return ((uint64_t)lo) | (((uint64_t)hi) << 32);
-#else
- return 0;
-#endif
-}
-
-
static LLVMValueRef
add_blend_test(LLVMModuleRef module,
const struct pipe_blend_state *blend,
}
-static float
-random_float(void)
-{
- return (float)((double)random()/(double)RAND_MAX);
-}
-
-
/** Add and limit result to ceiling of 1.0 */
#define ADD_SAT(R, A, B) \
do { \
static void
compute_blend_ref_term(unsigned rgb_factor,
unsigned alpha_factor,
- const float *factor,
- const float *src,
- const float *dst,
- const float *con,
- float *term)
+ const double *factor,
+ const double *src,
+ const double *dst,
+ const double *con,
+ double *term)
{
- float temp;
+ double temp;
switch (rgb_factor) {
case PIPE_BLENDFACTOR_ONE:
static void
compute_blend_ref(const struct pipe_blend_state *blend,
- const float *src,
- const float *dst,
- const float *con,
- float *res)
+ const double *src,
+ const double *dst,
+ const double *con,
+ double *res)
{
- float src_term[4];
- float dst_term[4];
+ double src_term[4];
+ double dst_term[4];
compute_blend_ref_term(blend->rgb_src_factor, blend->alpha_src_factor, src, src, dst, con, src_term);
compute_blend_ref_term(blend->rgb_dst_factor, blend->alpha_dst_factor, dst, src, dst, con, dst_term);
static boolean
-test_one(FILE *fp,
+test_one(unsigned verbose,
+ FILE *fp,
const struct pipe_blend_state *blend,
union lp_type type)
{
const unsigned n = 32;
int64_t cycles[n];
double cycles_avg = 0.0;
- unsigned i, j, k;
+ unsigned i, j;
if(verbose >= 1)
dump_blend_type(stdout, blend, type);
success = TRUE;
for(i = 0; i < n && success; ++i) {
+ uint8_t src[LP_MAX_VECTOR_LENGTH*LP_MAX_TYPE_WIDTH/8];
+ uint8_t dst[LP_MAX_VECTOR_LENGTH*LP_MAX_TYPE_WIDTH/8];
+ uint8_t con[LP_MAX_VECTOR_LENGTH*LP_MAX_TYPE_WIDTH/8];
+ uint8_t res[LP_MAX_VECTOR_LENGTH*LP_MAX_TYPE_WIDTH/8];
+ double ref[LP_MAX_VECTOR_LENGTH];
int64_t start_counter = 0;
int64_t end_counter = 0;
- if(type.floating && type.width == 32) {
- float src[LP_MAX_VECTOR_LENGTH];
- float dst[LP_MAX_VECTOR_LENGTH];
- float con[LP_MAX_VECTOR_LENGTH];
- float ref[LP_MAX_VECTOR_LENGTH];
- float res[LP_MAX_VECTOR_LENGTH];
-
- for(j = 0; j < type.length; ++j) {
- src[j] = random_float();
- dst[j] = random_float();
- con[j] = random_float();
- }
+ random_vec(type, src);
+ random_vec(type, dst);
+ random_vec(type, con);
+
+ {
+ double fsrc[LP_MAX_VECTOR_LENGTH];
+ double fdst[LP_MAX_VECTOR_LENGTH];
+ double fcon[LP_MAX_VECTOR_LENGTH];
+
+ read_vec(type, src, fsrc);
+ read_vec(type, dst, fdst);
+ read_vec(type, con, fcon);
for(j = 0; j < type.length; j += 4)
- compute_blend_ref(blend, src + j, dst + j, con + j, ref + j);
-
- start_counter = rdtsc();
- blend_test_ptr(src, dst, con, res);
- end_counter = rdtsc();
-
- for(j = 0; j < type.length; ++j)
- if(fabs(res[j] - ref[j]) > FLT_EPSILON)
- success = FALSE;
-
- if (!success) {
- dump_blend_type(stderr, blend, type);
- fprintf(stderr, "\n");
- fprintf(stderr, "MISMATCH\n");
- fprintf(stderr, " Result: ");
- for(j = 0; j < type.length; ++j)
- fprintf(stderr, " %f", res[j]);
- fprintf(stderr, "\n");
- fprintf(stderr, " Expected: ");
- for(j = 0; j < type.length; ++j)
- fprintf(stderr, " %f", ref[j]);
- fprintf(stderr, "\n");
- }
+ compute_blend_ref(blend, fsrc + j, fdst + j, fcon + j, ref + j);
}
- else if(!type.floating && !type.fixed && !type.sign && type.norm && type.width == 8) {
- uint8_t src[LP_MAX_VECTOR_LENGTH];
- uint8_t dst[LP_MAX_VECTOR_LENGTH];
- uint8_t con[LP_MAX_VECTOR_LENGTH];
- uint8_t ref[LP_MAX_VECTOR_LENGTH];
- uint8_t res[LP_MAX_VECTOR_LENGTH];
-
- for(j = 0; j < type.length; ++j) {
- src[j] = random() & 0xff;
- dst[j] = random() & 0xff;
- con[j] = random() & 0xff;
- }
- for(j = 0; j < type.length; j += 4) {
- float srcf[4];
- float dstf[4];
- float conf[4];
- float reff[4];
+ start_counter = rdtsc();
+ blend_test_ptr(src, dst, con, res);
+ end_counter = rdtsc();
- for(k = 0; k < 4; ++k) {
- srcf[k] = (1.0f/255.0f)*src[j + k];
- dstf[k] = (1.0f/255.0f)*dst[j + k];
- conf[k] = (1.0f/255.0f)*con[j + k];
- }
+ cycles[i] = end_counter - start_counter;
- compute_blend_ref(blend, srcf, dstf, conf, reff);
+ success = compare_vec(type, res, ref);
- for(k = 0; k < 4; ++k)
- ref[j + k] = (uint8_t)(reff[k]*255.0f + 0.5f);
- }
+ if (!success) {
+ dump_blend_type(stderr, blend, type);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "MISMATCH\n");
- start_counter = rdtsc();
- blend_test_ptr(src, dst, con, res);
- end_counter = rdtsc();
+ fprintf(stderr, " Src: ");
+ dump_vec(stderr, type, src);
+ fprintf(stderr, "\n");
- for(j = 0; j < type.length; ++j) {
- int delta = (int)res[j] - (int)ref[j];
- if (delta < 0)
- delta = -delta;
- if(delta > 1)
- success = FALSE;
- }
+ fprintf(stderr, " Dst: ");
+ dump_vec(stderr, type, dst);
+ fprintf(stderr, "\n");
- if (!success) {
- dump_blend_type(stderr, blend, type);
- fprintf(stderr, "\n");
- fprintf(stderr, "MISMATCH\n");
- fprintf(stderr, " Result: ");
- for(j = 0; j < type.length; ++j)
- fprintf(stderr, " %3u", res[j]);
- fprintf(stderr, "\n");
- fprintf(stderr, " Expected: ");
- for(j = 0; j < type.length; ++j)
- fprintf(stderr, " %3u", ref[j]);
- fprintf(stderr, "\n");
- }
- }
- else
- assert(0);
+ fprintf(stderr, " Con: ");
+ dump_vec(stderr, type, con);
+ fprintf(stderr, "\n");
- cycles[i] = end_counter - start_counter;
+ fprintf(stderr, " Res: ");
+ dump_vec(stderr, type, res);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, " Ref: ");
+ dump_vec(stderr, type, ref);
+ fprintf(stderr, "\n");
+ }
}
/*
const unsigned num_types = sizeof(blend_types)/sizeof(blend_types[0]);
-static boolean
-test_all(FILE *fp)
+boolean
+test_all(unsigned verbose, FILE *fp)
{
const unsigned *rgb_func;
const unsigned *rgb_src_factor;
blend.alpha_src_factor = *alpha_src_factor;
blend.alpha_dst_factor = *alpha_dst_factor;
- if(!test_one(fp, &blend, *type))
+ if(!test_one(verbose, fp, &blend, *type))
success = FALSE;
}
}
-static boolean
-test_some(FILE *fp, unsigned long n)
+boolean
+test_some(unsigned verbose, FILE *fp, unsigned long n)
{
const unsigned *rgb_func;
const unsigned *rgb_src_factor;
blend.alpha_src_factor = *alpha_src_factor;
blend.alpha_dst_factor = *alpha_dst_factor;
- if(!test_one(fp, &blend, *type))
+ if(!test_one(verbose, fp, &blend, *type))
success = FALSE;
}
}
return success;
}
-
-
-int main(int argc, char **argv)
-{
- unsigned long n = 1000;
- FILE *fp = NULL;
- unsigned i;
- boolean success;
-
- for(i = 1; i < argc; ++i) {
- if(strcmp(argv[i], "-v") == 0)
- ++verbose;
- else if(strcmp(argv[i], "-o") == 0)
- fp = fopen(argv[++i], "wt");
- else
- n = atoi(argv[i]);
- }
-
- if(fp) {
- /* Warm up the caches */
- test_some(NULL, 100);
-
- write_tsv_header(fp);
- }
-
- if(n)
- success = test_some(fp, n);
- else
- success = test_all(fp);
-
- if(fp)
- fclose(fp);
-
- return success ? 0 : 1;
-}
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2009 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+/**
+ * @file
+ * Shared testing code.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ */
+
+
+#include "lp_bld_const.h"
+#include "lp_test.h"
+
+
+void
+dump_type(FILE *fp,
+ union lp_type type)
+{
+ fprintf(fp, "%s%u%sx%u",
+ type.floating ? "f" : (type.fixed ? "h" : (type.sign ? "s" : "u")),
+ type.width,
+ type.norm ? "n" : "",
+ type.length);
+}
+
+
+double
+read_elem(union lp_type type, const void *src, unsigned index)
+{
+ double scale = lp_const_scale(type);
+ double value;
+ assert(index < type.length);
+ if (type.floating) {
+ switch(type.width) {
+ case 32:
+ value = *((const float *)src + index);
+ break;
+ case 64:
+ value = *((const double *)src + index);
+ break;
+ default:
+ assert(0);
+ return 0.0;
+ }
+ }
+ else {
+ if(type.sign) {
+ switch(type.width) {
+ case 8:
+ value = *((const int8_t *)src + index);
+ break;
+ case 16:
+ value = *((const int16_t *)src + index);
+ break;
+ case 32:
+ value = *((const int32_t *)src + index);
+ break;
+ case 64:
+ value = *((const int64_t *)src + index);
+ break;
+ default:
+ assert(0);
+ return 0.0;
+ }
+ }
+ else {
+ switch(type.width) {
+ case 8:
+ value = *((const uint8_t *)src + index);
+ break;
+ case 16:
+ value = *((const uint16_t *)src + index);
+ break;
+ case 32:
+ value = *((const uint32_t *)src + index);
+ break;
+ case 64:
+ value = *((const uint64_t *)src + index);
+ break;
+ default:
+ assert(0);
+ return 0.0;
+ }
+ }
+ }
+ return value/scale;
+}
+
+
+void
+write_elem(union lp_type type, void *dst, unsigned index, double src)
+{
+ double scale = lp_const_scale(type);
+ double value = scale*src;
+ assert(index < type.length);
+ if (type.floating) {
+ switch(type.width) {
+ case 32:
+ *((float *)dst + index) = (float)(value);
+ break;
+ case 64:
+ *((double *)dst + index) = value;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ else {
+ if(type.sign) {
+ switch(type.width) {
+ case 8:
+ *((int8_t *)dst + index) = (int8_t)round(value);
+ break;
+ case 16:
+ *((int16_t *)dst + index) = (int16_t)round(value);
+ break;
+ case 32:
+ *((int32_t *)dst + index) = (int32_t)round(value);
+ break;
+ case 64:
+ *((int64_t *)dst + index) = (int32_t)round(value);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ else {
+ switch(type.width) {
+ case 8:
+ *((uint8_t *)dst + index) = (uint8_t)round(value);
+ break;
+ case 16:
+ *((uint16_t *)dst + index) = (uint16_t)round(value);
+ break;
+ case 32:
+ *((uint32_t *)dst + index) = (uint32_t)round(value);
+ break;
+ case 64:
+ *((uint64_t *)dst + index) = (uint64_t)round(value);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ }
+}
+
+
+void
+random_elem(union lp_type type, void *dst, unsigned index)
+{
+ assert(index < type.length);
+ if (type.floating) {
+ double value = (double)random()/(double)RAND_MAX;
+ if(!type.norm)
+ value += (double)random();
+ if(type.sign)
+ if(random() & 1)
+ value = -value;
+ switch(type.width) {
+ case 32:
+ *((float *)dst + index) = (float)value;
+ break;
+ case 64:
+ *((double *)dst + index) = value;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ else {
+ switch(type.width) {
+ case 8:
+ *((uint8_t *)dst + index) = (uint8_t)random();
+ break;
+ case 16:
+ *((uint16_t *)dst + index) = (uint16_t)random();
+ break;
+ case 32:
+ *((uint32_t *)dst + index) = (uint32_t)random();
+ break;
+ case 64:
+ *((uint64_t *)dst + index) = (uint64_t)random();
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+
+void
+read_vec(union lp_type type, const void *src, double *dst)
+{
+ unsigned i;
+ for (i = 0; i < type.length; ++i)
+ dst[i] = read_elem(type, src, i);
+}
+
+
+void
+write_vec(union lp_type type, void *dst, const double *src)
+{
+ unsigned i;
+ for (i = 0; i < type.length; ++i)
+ write_elem(type, dst, i, src[i]);
+}
+
+
+float
+random_float(void)
+{
+ return (float)((double)random()/(double)RAND_MAX);
+}
+
+
+void
+random_vec(union lp_type type, void *dst)
+{
+ unsigned i;
+ for (i = 0; i < type.length; ++i)
+ random_elem(type, dst, i);
+}
+
+
+boolean
+compare_vec(union lp_type type, const void *res, const double *ref)
+{
+ double eps;
+ unsigned i;
+
+ if (type.floating) {
+ switch(type.width) {
+ case 32:
+ eps = FLT_EPSILON;
+ break;
+ case 64:
+ eps = DBL_EPSILON;
+ break;
+ default:
+ assert(0);
+ eps = 0.0;
+ break;
+ }
+ }
+ else {
+ double scale = lp_const_scale(type);
+ eps = 1.0/scale;
+ }
+
+ for (i = 0; i < type.length; ++i) {
+ double res_elem = read_elem(type, res, i);
+ double ref_elem = ref[i];
+ double delta = fabs(res_elem - ref_elem);
+ if(delta >= 2.0*eps)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void
+dump_vec(FILE *fp, union lp_type type, const void *src)
+{
+ unsigned i;
+ for (i = 0; i < type.length; ++i) {
+ if(i)
+ fprintf(fp, " ");
+ if (type.floating) {
+ double value;
+ switch(type.width) {
+ case 32:
+ value = *((const float *)src + i);
+ break;
+ case 64:
+ value = *((const double *)src + i);
+ break;
+ default:
+ assert(0);
+ value = 0.0;
+ }
+ fprintf(fp, "%f", value);
+ }
+ else {
+ if(type.sign) {
+ long long value;
+ const char *format;
+ switch(type.width) {
+ case 8:
+ value = *((const int8_t *)src + i);
+ format = "%3lli";
+ break;
+ case 16:
+ value = *((const int16_t *)src + i);
+ format = "%5lli";
+ break;
+ case 32:
+ value = *((const int32_t *)src + i);
+ format = "%10lli";
+ break;
+ case 64:
+ value = *((const int64_t *)src + i);
+ format = "%20lli";
+ break;
+ default:
+ assert(0);
+ value = 0.0;
+ format = "?";
+ }
+ fprintf(fp, format, value);
+ }
+ else {
+ unsigned long long value;
+ const char *format;
+ switch(type.width) {
+ case 8:
+ value = *((const uint8_t *)src + i);
+ format = "%4llu";
+ break;
+ case 16:
+ value = *((const uint16_t *)src + i);
+ format = "%6llu";
+ break;
+ case 32:
+ value = *((const uint32_t *)src + i);
+ format = "%11llu";
+ break;
+ case 64:
+ value = *((const uint64_t *)src + i);
+ format = "%21llu";
+ break;
+ default:
+ assert(0);
+ value = 0.0;
+ format = "?";
+ }
+ fprintf(fp, format, value);
+ }
+ }
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ unsigned verbose = 0;
+ FILE *fp = NULL;
+ unsigned long n = 1000;
+ unsigned i;
+ boolean success;
+
+ for(i = 1; i < argc; ++i) {
+ if(strcmp(argv[i], "-v") == 0)
+ ++verbose;
+ else if(strcmp(argv[i], "-o") == 0)
+ fp = fopen(argv[++i], "wt");
+ else
+ n = atoi(argv[i]);
+ }
+
+ if(fp) {
+ /* Warm up the caches */
+ test_some(0, NULL, 100);
+
+ write_tsv_header(fp);
+ }
+
+ if(n)
+ success = test_some(verbose, fp, n);
+ else
+ success = test_all(verbose, fp);
+
+ if(fp)
+ fclose(fp);
+
+ return success ? 0 : 1;
+}