diff options
author | marha <marha@users.sourceforge.net> | 2011-11-07 07:22:24 +0100 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-11-07 07:22:24 +0100 |
commit | af3f3672e5f77a06a24b1e648ee118f1420b45ae (patch) | |
tree | 2f08e1da8d47d44fcbf78f660ee8d99bf162b5f2 /mesalib | |
parent | 60f8ca2d5842b40b8585c58095787c84edfa9803 (diff) | |
parent | 1ed503a856d9753a813951796bc6ba56c42ecd28 (diff) | |
download | vcxsrv-af3f3672e5f77a06a24b1e648ee118f1420b45ae.tar.gz vcxsrv-af3f3672e5f77a06a24b1e648ee118f1420b45ae.tar.bz2 vcxsrv-af3f3672e5f77a06a24b1e648ee118f1420b45ae.zip |
Merge remote-tracking branch 'origin/released'
Conflicts:
pixman/pixman/pixman-mmx.c
Diffstat (limited to 'mesalib')
23 files changed, 2358 insertions, 2502 deletions
diff --git a/mesalib/Android.mk b/mesalib/Android.mk index 29453bc34..0c07d5e02 100644 --- a/mesalib/Android.mk +++ b/mesalib/Android.mk @@ -135,9 +135,9 @@ endif ifneq ($(filter nouveau, $(MESA_GPU_DRIVERS)),) gallium_DRIVERS += \ libmesa_winsys_nouveau \ - libmesa_pipe_nvc0 \ - libmesa_pipe_nv50 \ libmesa_pipe_nvfx \ + libmesa_pipe_nv50 \ + libmesa_pipe_nvc0 \ libmesa_pipe_nouveau LOCAL_SHARED_LIBRARIES += libdrm_nouveau endif diff --git a/mesalib/configure.ac b/mesalib/configure.ac index 30b3b96c3..8885a6d74 100644 --- a/mesalib/configure.ac +++ b/mesalib/configure.ac @@ -1052,7 +1052,7 @@ AC_SUBST([GLESv1_CM_PC_LIB_PRIV]) AC_SUBST([GLESv2_LIB_DEPS]) AC_SUBST([GLESv2_PC_LIB_PRIV]) -GLAPI_LIB_DEPS="-lpthread" +GLAPI_LIB_DEPS="-lpthread $SELINUX_LIBS" AC_SUBST([GLAPI_LIB_DEPS]) @@ -1427,8 +1427,8 @@ dnl dnl gbm Gallium configuration dnl if test "x$enable_gallium_gbm" = xauto; then - case "$enable_gbm$HAVE_ST_EGL$with_egl_platforms" in - yesyes*drm*) + case "$enable_gbm$HAVE_ST_EGL$enable_dri$with_egl_platforms" in + yesyesyes*drm*) enable_gallium_gbm=yes ;; *) enable_gallium_gbm=no ;; @@ -1441,6 +1441,10 @@ if test "x$enable_gallium_gbm" = xyes; then if test "x$enable_gbm" = xno; then AC_MSG_ERROR([cannot enable gbm_gallium without gbm]) fi + # gbm_gallium abuses DRI_LIB_DEPS to link. Make sure it is set. + if test "x$enable_dri" = xno; then + AC_MSG_ERROR([gbm_gallium requires --enable-dri to build]) + fi GALLIUM_STATE_TRACKERS_DIRS="gbm $GALLIUM_STATE_TRACKERS_DIRS" GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS gbm" diff --git a/mesalib/docs/GL3.txt b/mesalib/docs/GL3.txt index 54099451a..3716a376d 100644 --- a/mesalib/docs/GL3.txt +++ b/mesalib/docs/GL3.txt @@ -118,7 +118,7 @@ GLSL 4.2 not started GL_ARB_texture_compression_bptc not started GL_ARB_compressed_texture_pixel_storage not started GL_ARB_shader_atomic_counters not started -GL_ARB_texture_storage not started +GL_ARB_texture_storage DONE (gallium, swrast) GL_ARB_transform_feedback_instanced not started GL_ARB_base_instance not started GL_ARB_shader_image_load_store not started diff --git a/mesalib/docs/llvmpipe.html b/mesalib/docs/llvmpipe.html index 5f4e9de3b..bd9cc26f2 100644 --- a/mesalib/docs/llvmpipe.html +++ b/mesalib/docs/llvmpipe.html @@ -1,204 +1,202 @@ -<HTML>
-
-<TITLE>llvmpipe</TITLE>
-
-<link rel="stylesheet" type="text/css" href="mesa.css"></head>
-
-<BODY>
-
-<H1>Introduction</H1>
-
-<p>
-The Gallium llvmpipe driver is a software rasterizer that uses LLVM to
-do runtime code generation.
-Shaders, point/line/triangle rasterization and vertex processing are
-implemented with LLVM IR which is translated to x86 or x86-64 machine
-code.
-Also, the driver is multithreaded to take advantage of multiple CPU cores
-(up to 8 at this time).
-It's the fastest software rasterizer for Mesa.
-</p>
-
-
-<h1>Requirements</h1>
-
-<dl>
-<dt>An x86 or amd64 processor. 64-bit mode is preferred.</dt>
-<dd>
- <p>
- Support for sse2 is strongly encouraged. Support for ssse3, and sse4.1 will
- yield the most efficient code. The less features the CPU has the more
- likely is that you ran into underperforming, buggy, or incomplete code.
- </p>
- <p>
- See /proc/cpuinfo to know what your CPU supports.
- </p>
-</dd>
-<dt>LLVM. Version 2.8 recommended. 2.6 or later required.</dt>
-<dd>
- <p>
- <b>NOTE</b>: LLVM 2.8 and earlier will not work on systems that support the
- Intel AVX extensions (e.g. Sandybridge). LLVM's code generator will
- fail when trying to emit AVX instructions. This was fixed in LLVM 2.9.
- </p>
- <p>
- For Linux, on a recent Debian based distribution do:
- </p>
-<pre>
- aptitude install llvm-dev
-</pre>
- For a RPM-based distribution do:
- </p>
-<pre>
- yum install llvm-devel
-</pre>
-
- <p>
- For Windows download pre-built MSVC 9.0 or MinGW binaries from
- http://people.freedesktop.org/~jrfonseca/llvm/ and set the LLVM environment
- variable to the extracted path.
- </p>
-
- <p>
- For MSVC there are two set of binaries: llvm-x.x-msvc32mt.7z and
- llvm-x.x-msvc32mtd.7z .
- </p>
-
- <p>
- You have to set the LLVM=/path/to/llvm-x.x-msvc32mtd env var when passing
- debug=yes to scons, and LLVM=/path/to/llvm-x.x-msvc32mt when building with
- debug=no. This is necessary as LLVM builds as static library so the chosen
- MS CRT must match.
- </p>
-</dd>
-
-<dt>scons (optional)</dt>
-</dl>
-
-
-
-<h1>Building</h1>
-
-To build everything on Linux invoke scons as:
-
-<pre>
- scons build=debug libgl-xlib
-</pre>
-
-Alternatively, you can build it with GNU make, if you prefer, by invoking it as
-
-<pre>
- make linux-llvm
-</pre>
-
-but the rest of these instructions assume that scons is used.
-
-For windows is everything the except except the winsys:
-
-<pre>
- scons build=debug libgl-gdi
-</pre>
-
-
-<h1>Using</h1>
-
-On Linux, building will create a drop-in alternative for libGL.so into
-
-<pre>
- build/foo/gallium/targets/libgl-xlib/libGL.so
-</pre>
-or
-<pre>
- lib/gallium/libGL.so
-</pre>
-
-To use it set the LD_LIBRARY_PATH environment variable accordingly.
-
-For performance evaluation pass debug=no to scons, and use the corresponding
-lib directory without the "-debug" suffix.
-
-On Windows, building will create a drop-in alternative for opengl32.dll. To use
-it put it in the same directory as the application. It can also be used by
-replacing the native ICD driver, but it's quite an advanced usage, so if you
-need to ask, don't even try it.
-
-
-<h1>Profiling</h1>
-
-To profile llvmpipe you should pass the options
-
-<pre>
- scons build=profile <same-as-before>
-</pre>
-
-This will ensure that frame pointers are used both in C and JIT functions, and
-that no tail call optimizations are done by gcc.
-
-To better profile JIT code you'll need to build LLVM with oprofile integration.
-
-<pre>
- ./configure \
- --prefix=$install_dir \
- --enable-optimized \
- --disable-profiling \
- --enable-targets=host-only \
- --with-oprofile
-
- make -C "$build_dir"
- make -C "$build_dir" install
-
- find "$install_dir/lib" -iname '*.a' -print0 | xargs -0 strip --strip-debug
-</pre>
-
-The you should define
-
-<pre>
- export LLVM=/path/to/llvm-2.6-profile
-</pre>
-
-and rebuild.
-
-
-<h1>Unit testing</h1>
-
-<p>
-Building will also create several unit tests in
-build/linux-???-debug/gallium/drivers/llvmpipe:
-</p>
-
-</ul>
-<li> lp_test_blend: blending
-<li> lp_test_conv: SIMD vector conversion
-<li> lp_test_format: pixel unpacking/packing
-</ul>
-
-<p>
-Some of this tests can output results and benchmarks to a tab-separated-file
-for posterior analysis, e.g.:
-</p>
-<pre>
- build/linux-x86_64-debug/gallium/drivers/llvmpipe/lp_test_blend -o blend.tsv
-</pre>
-
-
-<h1>Development Notes</h1>
-
-<ul>
-<li>
- When looking to this code by the first time start in lp_state_fs.c, and
- then skim through the lp_bld_* functions called in there, and the comments
- at the top of the lp_bld_*.c functions.
-</li>
-<li>
- The driver-independent parts of the LLVM / Gallium code are found in
- src/gallium/auxiliary/gallivm/. The filenames and function prefixes
- need to be renamed from "lp_bld_" to something else though.
-</li>
-<li>
- We use LLVM-C bindings for now. They are not documented, but follow the C++
- interfaces very closely, and appear to be complete enough for code
- generation. See
- http://npcontemplation.blogspot.com/2008/06/secret-of-llvm-c-bindings.html
- for a stand-alone example. See the llvm-c/Core.h file for reference.
-</li>
-</ul>
+<HTML> + +<TITLE>llvmpipe</TITLE> + +<link rel="stylesheet" type="text/css" href="mesa.css"></head> + +<BODY> + +<H1>Introduction</H1> + +<p> +The Gallium llvmpipe driver is a software rasterizer that uses LLVM to +do runtime code generation. +Shaders, point/line/triangle rasterization and vertex processing are +implemented with LLVM IR which is translated to x86 or x86-64 machine +code. +Also, the driver is multithreaded to take advantage of multiple CPU cores +(up to 8 at this time). +It's the fastest software rasterizer for Mesa. +</p> + + +<h1>Requirements</h1> + +<ul> +<li> + <p>An x86 or amd64 processor; 64-bit mode recommended.</p + <p> + Support for SSE2 is strongly encouraged. Support for SSSE3 and SSE4.1 will + yield the most efficient code. The fewer features the CPU has the more + likely is that you run into underperforming, buggy, or incomplete code. + </p> + <p> + See /proc/cpuinfo to know what your CPU supports. + </p> +</li> +<li> + <p>LLVM: version 2.9 recommended; 2.6 or later required.</p> + <b>NOTE</b>: LLVM 2.8 and earlier will not work on systems that support the + Intel AVX extensions (e.g. Sandybridge). LLVM's code generator will + fail when trying to emit AVX instructions. This was fixed in LLVM 2.9. + </p> + <p> + For Linux, on a recent Debian based distribution do: + </p> +<pre> + aptitude install llvm-dev +</pre> + For a RPM-based distribution do: + </p> +<pre> + yum install llvm-devel +</pre> + + <p> + For Windows you will need to build LLVM from source with MSVC or MINGW + (either natively or through cross compilers) and CMake, and set the LLVM + environment variable to the directory you installed it to. + + LLVM will be statically linked, so when building on MSVC it needs to be + built with a matching CRT as Mesa, and you'll need to pass + -DLLVM_USE_CRT_RELEASE=MTd for debug and checked builds, + -DLLVM_USE_CRT_RELEASE=MTd for profile and release builds. + + You can build only the x86 target by passing -DLLVM_TARGETS_TO_BUILD=X86 + to cmake. + </p> +</li> + +<li> + <p>scons (optional)</p> +</li> +</ul> + + + + +<h1>Building</h1> + +To build everything on Linux invoke scons as: + +<pre> + scons build=debug libgl-xlib +</pre> + +Alternatively, you can build it with GNU make, if you prefer, by invoking it as + +<pre> + make linux-llvm +</pre> + +but the rest of these instructions assume that scons is used. + +For Windows the procedure is similar except the target: + +<pre> + scons build=debug libgl-gdi +</pre> + + +<h1>Using</h1> + +On Linux, building will create a drop-in alternative for libGL.so into + +<pre> + build/foo/gallium/targets/libgl-xlib/libGL.so +</pre> +or +<pre> + lib/gallium/libGL.so +</pre> + +To use it set the LD_LIBRARY_PATH environment variable accordingly. + +For performance evaluation pass debug=no to scons, and use the corresponding +lib directory without the "-debug" suffix. + +On Windows, building will create a drop-in alternative for opengl32.dll. To use +it put it in the same directory as the application. It can also be used by +replacing the native ICD driver, but it's quite an advanced usage, so if you +need to ask, don't even try it. + + +<h1>Profiling</h1> + +To profile llvmpipe you should pass the options + +<pre> + scons build=profile <same-as-before> +</pre> + +This will ensure that frame pointers are used both in C and JIT functions, and +that no tail call optimizations are done by gcc. + +To better profile JIT code you'll need to build LLVM with oprofile integration. + +<pre> + ./configure \ + --prefix=$install_dir \ + --enable-optimized \ + --disable-profiling \ + --enable-targets=host-only \ + --with-oprofile + + make -C "$build_dir" + make -C "$build_dir" install + + find "$install_dir/lib" -iname '*.a' -print0 | xargs -0 strip --strip-debug +</pre> + +The you should define + +<pre> + export LLVM=/path/to/llvm-2.6-profile +</pre> + +and rebuild. + + +<h1>Unit testing</h1> + +<p> +Building will also create several unit tests in +build/linux-???-debug/gallium/drivers/llvmpipe: +</p> + +</ul> +<li> lp_test_blend: blending +<li> lp_test_conv: SIMD vector conversion +<li> lp_test_format: pixel unpacking/packing +</ul> + +<p> +Some of this tests can output results and benchmarks to a tab-separated-file +for posterior analysis, e.g.: +</p> +<pre> + build/linux-x86_64-debug/gallium/drivers/llvmpipe/lp_test_blend -o blend.tsv +</pre> + + +<h1>Development Notes</h1> + +<ul> +<li> + When looking to this code by the first time start in lp_state_fs.c, and + then skim through the lp_bld_* functions called in there, and the comments + at the top of the lp_bld_*.c functions. +</li> +<li> + The driver-independent parts of the LLVM / Gallium code are found in + src/gallium/auxiliary/gallivm/. The filenames and function prefixes + need to be renamed from "lp_bld_" to something else though. +</li> +<li> + We use LLVM-C bindings for now. They are not documented, but follow the C++ + interfaces very closely, and appear to be complete enough for code + generation. See + http://npcontemplation.blogspot.com/2008/06/secret-of-llvm-c-bindings.html + for a stand-alone example. See the llvm-c/Core.h file for reference. +</li> +</ul> diff --git a/mesalib/src/gallium/auxiliary/util/u_blit.c b/mesalib/src/gallium/auxiliary/util/u_blit.c index 87530e94a..6a4324bc2 100644 --- a/mesalib/src/gallium/auxiliary/util/u_blit.c +++ b/mesalib/src/gallium/auxiliary/util/u_blit.c @@ -531,6 +531,7 @@ util_blit_pixels_writemask(struct blit_state *ctx, cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); + cso_save_geometry_shader(ctx->cso); cso_save_clip(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_vertex_buffers(ctx->cso); @@ -574,6 +575,7 @@ util_blit_pixels_writemask(struct blit_state *ctx, set_fragment_shader(ctx, writemask); } set_vertex_shader(ctx); + cso_set_geometry_shader_handle(ctx->cso, NULL); /* drawing dest */ memset(&fb, 0, sizeof(fb)); @@ -612,6 +614,7 @@ util_blit_pixels_writemask(struct blit_state *ctx, cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); + cso_restore_geometry_shader(ctx->cso); cso_restore_clip(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_vertex_buffers(ctx->cso); @@ -719,6 +722,7 @@ util_blit_pixels_tex(struct blit_state *ctx, cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); + cso_save_geometry_shader(ctx->cso); cso_save_clip(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_vertex_buffers(ctx->cso); @@ -754,6 +758,7 @@ util_blit_pixels_tex(struct blit_state *ctx, /* shaders */ set_fragment_shader(ctx, TGSI_WRITEMASK_XYZW); set_vertex_shader(ctx); + cso_set_geometry_shader_handle(ctx->cso, NULL); /* drawing dest */ memset(&fb, 0, sizeof(fb)); @@ -788,6 +793,7 @@ util_blit_pixels_tex(struct blit_state *ctx, cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); + cso_restore_geometry_shader(ctx->cso); cso_restore_clip(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_vertex_buffers(ctx->cso); diff --git a/mesalib/src/gallium/auxiliary/util/u_format.c b/mesalib/src/gallium/auxiliary/util/u_format.c index e07462a75..cfc4a17a0 100644 --- a/mesalib/src/gallium/auxiliary/util/u_format.c +++ b/mesalib/src/gallium/auxiliary/util/u_format.c @@ -443,11 +443,16 @@ util_format_fits_8unorm(const struct util_format_description *format_desc) switch (format_desc->layout) { case UTIL_FORMAT_LAYOUT_S3TC: - case UTIL_FORMAT_LAYOUT_RGTC: /* * These are straight forward. */ - + return TRUE; + case UTIL_FORMAT_LAYOUT_RGTC: + if (format_desc->format == PIPE_FORMAT_RGTC1_SNORM || + format_desc->format == PIPE_FORMAT_RGTC2_SNORM || + format_desc->format == PIPE_FORMAT_LATC1_SNORM || + format_desc->format == PIPE_FORMAT_LATC2_SNORM) + return FALSE; return TRUE; case UTIL_FORMAT_LAYOUT_PLAIN: diff --git a/mesalib/src/gallium/auxiliary/util/u_gen_mipmap.c b/mesalib/src/gallium/auxiliary/util/u_gen_mipmap.c index c04e3645e..436a0e424 100644 --- a/mesalib/src/gallium/auxiliary/util/u_gen_mipmap.c +++ b/mesalib/src/gallium/auxiliary/util/u_gen_mipmap.c @@ -1,1688 +1,1691 @@ -/**************************************************************************
- *
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- * Copyright 2008 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 TUNGSTEN GRAPHICS 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
- * Mipmap generation utility
- *
- * @author Brian Paul
- */
-
-
-#include "pipe/p_context.h"
-#include "util/u_debug.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-#include "pipe/p_shader_tokens.h"
-#include "pipe/p_state.h"
-
-#include "util/u_format.h"
-#include "util/u_memory.h"
-#include "util/u_draw_quad.h"
-#include "util/u_gen_mipmap.h"
-#include "util/u_simple_shaders.h"
-#include "util/u_math.h"
-#include "util/u_texture.h"
-#include "util/u_half.h"
-#include "util/u_surface.h"
-
-#include "cso_cache/cso_context.h"
-
-
-struct gen_mipmap_state
-{
- struct pipe_context *pipe;
- struct cso_context *cso;
-
- struct pipe_blend_state blend;
- struct pipe_depth_stencil_alpha_state depthstencil;
- struct pipe_rasterizer_state rasterizer;
- struct pipe_sampler_state sampler;
- struct pipe_clip_state clip;
- struct pipe_vertex_element velem[2];
-
- void *vs;
- void *fs[TGSI_TEXTURE_COUNT]; /**< Not all are used, but simplifies code */
-
- struct pipe_resource *vbuf; /**< quad vertices */
- unsigned vbuf_slot;
-
- float vertices[4][2][4]; /**< vertex/texcoords for quad */
-};
-
-
-
-enum dtype
-{
- DTYPE_UBYTE,
- DTYPE_UBYTE_3_3_2,
- DTYPE_USHORT,
- DTYPE_USHORT_4_4_4_4,
- DTYPE_USHORT_5_6_5,
- DTYPE_USHORT_1_5_5_5_REV,
- DTYPE_UINT,
- DTYPE_FLOAT,
- DTYPE_HALF_FLOAT
-};
-
-
-typedef uint16_t half_float;
-
-
-/**
- * \name Support macros for do_row and do_row_3d
- *
- * The macro madness is here for two reasons. First, it compacts the code
- * slightly. Second, it makes it much easier to adjust the specifics of the
- * filter to tune the rounding characteristics.
- */
-/*@{*/
-#define DECLARE_ROW_POINTERS(t, e) \
- const t(*rowA)[e] = (const t(*)[e]) srcRowA; \
- const t(*rowB)[e] = (const t(*)[e]) srcRowB; \
- const t(*rowC)[e] = (const t(*)[e]) srcRowC; \
- const t(*rowD)[e] = (const t(*)[e]) srcRowD; \
- t(*dst)[e] = (t(*)[e]) dstRow
-
-#define DECLARE_ROW_POINTERS0(t) \
- const t *rowA = (const t *) srcRowA; \
- const t *rowB = (const t *) srcRowB; \
- const t *rowC = (const t *) srcRowC; \
- const t *rowD = (const t *) srcRowD; \
- t *dst = (t *) dstRow
-
-#define FILTER_SUM_3D(Aj, Ak, Bj, Bk, Cj, Ck, Dj, Dk) \
- ((unsigned) Aj + (unsigned) Ak \
- + (unsigned) Bj + (unsigned) Bk \
- + (unsigned) Cj + (unsigned) Ck \
- + (unsigned) Dj + (unsigned) Dk \
- + 4) >> 3
-
-#define FILTER_3D(e) \
- do { \
- dst[i][e] = FILTER_SUM_3D(rowA[j][e], rowA[k][e], \
- rowB[j][e], rowB[k][e], \
- rowC[j][e], rowC[k][e], \
- rowD[j][e], rowD[k][e]); \
- } while(0)
-
-#define FILTER_F_3D(e) \
- do { \
- dst[i][e] = (rowA[j][e] + rowA[k][e] \
- + rowB[j][e] + rowB[k][e] \
- + rowC[j][e] + rowC[k][e] \
- + rowD[j][e] + rowD[k][e]) * 0.125F; \
- } while(0)
-
-#define FILTER_HF_3D(e) \
- do { \
- const float aj = util_half_to_float(rowA[j][e]); \
- const float ak = util_half_to_float(rowA[k][e]); \
- const float bj = util_half_to_float(rowB[j][e]); \
- const float bk = util_half_to_float(rowB[k][e]); \
- const float cj = util_half_to_float(rowC[j][e]); \
- const float ck = util_half_to_float(rowC[k][e]); \
- const float dj = util_half_to_float(rowD[j][e]); \
- const float dk = util_half_to_float(rowD[k][e]); \
- dst[i][e] = util_float_to_half((aj + ak + bj + bk + cj + ck + dj + dk) \
- * 0.125F); \
- } while(0)
-/*@}*/
-
-
-/**
- * Average together two rows of a source image to produce a single new
- * row in the dest image. It's legal for the two source rows to point
- * to the same data. The source width must be equal to either the
- * dest width or two times the dest width.
- * \param datatype GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc.
- * \param comps number of components per pixel (1..4)
- */
-static void
-do_row(enum dtype datatype, uint comps, int srcWidth,
- const void *srcRowA, const void *srcRowB,
- int dstWidth, void *dstRow)
-{
- const uint k0 = (srcWidth == dstWidth) ? 0 : 1;
- const uint colStride = (srcWidth == dstWidth) ? 1 : 2;
-
- assert(comps >= 1);
- assert(comps <= 4);
-
- /* This assertion is no longer valid with non-power-of-2 textures
- assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth);
- */
-
- if (datatype == DTYPE_UBYTE && comps == 4) {
- uint i, j, k;
- const ubyte(*rowA)[4] = (const ubyte(*)[4]) srcRowA;
- const ubyte(*rowB)[4] = (const ubyte(*)[4]) srcRowB;
- ubyte(*dst)[4] = (ubyte(*)[4]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
- dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
- dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
- dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
- }
- }
- else if (datatype == DTYPE_UBYTE && comps == 3) {
- uint i, j, k;
- const ubyte(*rowA)[3] = (const ubyte(*)[3]) srcRowA;
- const ubyte(*rowB)[3] = (const ubyte(*)[3]) srcRowB;
- ubyte(*dst)[3] = (ubyte(*)[3]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
- dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
- dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
- }
- }
- else if (datatype == DTYPE_UBYTE && comps == 2) {
- uint i, j, k;
- const ubyte(*rowA)[2] = (const ubyte(*)[2]) srcRowA;
- const ubyte(*rowB)[2] = (const ubyte(*)[2]) srcRowB;
- ubyte(*dst)[2] = (ubyte(*)[2]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) >> 2;
- dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) >> 2;
- }
- }
- else if (datatype == DTYPE_UBYTE && comps == 1) {
- uint i, j, k;
- const ubyte *rowA = (const ubyte *) srcRowA;
- const ubyte *rowB = (const ubyte *) srcRowB;
- ubyte *dst = (ubyte *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2;
- }
- }
-
- else if (datatype == DTYPE_USHORT && comps == 4) {
- uint i, j, k;
- const ushort(*rowA)[4] = (const ushort(*)[4]) srcRowA;
- const ushort(*rowB)[4] = (const ushort(*)[4]) srcRowB;
- ushort(*dst)[4] = (ushort(*)[4]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
- dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
- dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
- dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4;
- }
- }
- else if (datatype == DTYPE_USHORT && comps == 3) {
- uint i, j, k;
- const ushort(*rowA)[3] = (const ushort(*)[3]) srcRowA;
- const ushort(*rowB)[3] = (const ushort(*)[3]) srcRowB;
- ushort(*dst)[3] = (ushort(*)[3]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
- dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
- dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4;
- }
- }
- else if (datatype == DTYPE_USHORT && comps == 2) {
- uint i, j, k;
- const ushort(*rowA)[2] = (const ushort(*)[2]) srcRowA;
- const ushort(*rowB)[2] = (const ushort(*)[2]) srcRowB;
- ushort(*dst)[2] = (ushort(*)[2]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4;
- dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4;
- }
- }
- else if (datatype == DTYPE_USHORT && comps == 1) {
- uint i, j, k;
- const ushort *rowA = (const ushort *) srcRowA;
- const ushort *rowB = (const ushort *) srcRowB;
- ushort *dst = (ushort *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4;
- }
- }
-
- else if (datatype == DTYPE_FLOAT && comps == 4) {
- uint i, j, k;
- const float(*rowA)[4] = (const float(*)[4]) srcRowA;
- const float(*rowB)[4] = (const float(*)[4]) srcRowB;
- float(*dst)[4] = (float(*)[4]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] +
- rowB[j][0] + rowB[k][0]) * 0.25F;
- dst[i][1] = (rowA[j][1] + rowA[k][1] +
- rowB[j][1] + rowB[k][1]) * 0.25F;
- dst[i][2] = (rowA[j][2] + rowA[k][2] +
- rowB[j][2] + rowB[k][2]) * 0.25F;
- dst[i][3] = (rowA[j][3] + rowA[k][3] +
- rowB[j][3] + rowB[k][3]) * 0.25F;
- }
- }
- else if (datatype == DTYPE_FLOAT && comps == 3) {
- uint i, j, k;
- const float(*rowA)[3] = (const float(*)[3]) srcRowA;
- const float(*rowB)[3] = (const float(*)[3]) srcRowB;
- float(*dst)[3] = (float(*)[3]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] +
- rowB[j][0] + rowB[k][0]) * 0.25F;
- dst[i][1] = (rowA[j][1] + rowA[k][1] +
- rowB[j][1] + rowB[k][1]) * 0.25F;
- dst[i][2] = (rowA[j][2] + rowA[k][2] +
- rowB[j][2] + rowB[k][2]) * 0.25F;
- }
- }
- else if (datatype == DTYPE_FLOAT && comps == 2) {
- uint i, j, k;
- const float(*rowA)[2] = (const float(*)[2]) srcRowA;
- const float(*rowB)[2] = (const float(*)[2]) srcRowB;
- float(*dst)[2] = (float(*)[2]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i][0] = (rowA[j][0] + rowA[k][0] +
- rowB[j][0] + rowB[k][0]) * 0.25F;
- dst[i][1] = (rowA[j][1] + rowA[k][1] +
- rowB[j][1] + rowB[k][1]) * 0.25F;
- }
- }
- else if (datatype == DTYPE_FLOAT && comps == 1) {
- uint i, j, k;
- const float *rowA = (const float *) srcRowA;
- const float *rowB = (const float *) srcRowB;
- float *dst = (float *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F;
- }
- }
-
- else if (datatype == DTYPE_HALF_FLOAT && comps == 4) {
- uint i, j, k, comp;
- const half_float(*rowA)[4] = (const half_float(*)[4]) srcRowA;
- const half_float(*rowB)[4] = (const half_float(*)[4]) srcRowB;
- half_float(*dst)[4] = (half_float(*)[4]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- for (comp = 0; comp < 4; comp++) {
- float aj, ak, bj, bk;
- aj = util_half_to_float(rowA[j][comp]);
- ak = util_half_to_float(rowA[k][comp]);
- bj = util_half_to_float(rowB[j][comp]);
- bk = util_half_to_float(rowB[k][comp]);
- dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
- }
- }
- }
- else if (datatype == DTYPE_HALF_FLOAT && comps == 3) {
- uint i, j, k, comp;
- const half_float(*rowA)[3] = (const half_float(*)[3]) srcRowA;
- const half_float(*rowB)[3] = (const half_float(*)[3]) srcRowB;
- half_float(*dst)[3] = (half_float(*)[3]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- for (comp = 0; comp < 3; comp++) {
- float aj, ak, bj, bk;
- aj = util_half_to_float(rowA[j][comp]);
- ak = util_half_to_float(rowA[k][comp]);
- bj = util_half_to_float(rowB[j][comp]);
- bk = util_half_to_float(rowB[k][comp]);
- dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
- }
- }
- }
- else if (datatype == DTYPE_HALF_FLOAT && comps == 2) {
- uint i, j, k, comp;
- const half_float(*rowA)[2] = (const half_float(*)[2]) srcRowA;
- const half_float(*rowB)[2] = (const half_float(*)[2]) srcRowB;
- half_float(*dst)[2] = (half_float(*)[2]) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- for (comp = 0; comp < 2; comp++) {
- float aj, ak, bj, bk;
- aj = util_half_to_float(rowA[j][comp]);
- ak = util_half_to_float(rowA[k][comp]);
- bj = util_half_to_float(rowB[j][comp]);
- bk = util_half_to_float(rowB[k][comp]);
- dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
- }
- }
- }
- else if (datatype == DTYPE_HALF_FLOAT && comps == 1) {
- uint i, j, k;
- const half_float *rowA = (const half_float *) srcRowA;
- const half_float *rowB = (const half_float *) srcRowB;
- half_float *dst = (half_float *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- float aj, ak, bj, bk;
- aj = util_half_to_float(rowA[j]);
- ak = util_half_to_float(rowA[k]);
- bj = util_half_to_float(rowB[j]);
- bk = util_half_to_float(rowB[k]);
- dst[i] = util_float_to_half((aj + ak + bj + bk) * 0.25F);
- }
- }
-
- else if (datatype == DTYPE_UINT && comps == 1) {
- uint i, j, k;
- const uint *rowA = (const uint *) srcRowA;
- const uint *rowB = (const uint *) srcRowB;
- uint *dst = (uint *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4;
- }
- }
-
- else if (datatype == DTYPE_USHORT_5_6_5 && comps == 3) {
- uint i, j, k;
- const ushort *rowA = (const ushort *) srcRowA;
- const ushort *rowB = (const ushort *) srcRowB;
- ushort *dst = (ushort *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0x1f;
- const int rowAr1 = rowA[k] & 0x1f;
- const int rowBr0 = rowB[j] & 0x1f;
- const int rowBr1 = rowB[k] & 0x1f;
- const int rowAg0 = (rowA[j] >> 5) & 0x3f;
- const int rowAg1 = (rowA[k] >> 5) & 0x3f;
- const int rowBg0 = (rowB[j] >> 5) & 0x3f;
- const int rowBg1 = (rowB[k] >> 5) & 0x3f;
- const int rowAb0 = (rowA[j] >> 11) & 0x1f;
- const int rowAb1 = (rowA[k] >> 11) & 0x1f;
- const int rowBb0 = (rowB[j] >> 11) & 0x1f;
- const int rowBb1 = (rowB[k] >> 11) & 0x1f;
- const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
- const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
- const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
- dst[i] = (blue << 11) | (green << 5) | red;
- }
- }
- else if (datatype == DTYPE_USHORT_4_4_4_4 && comps == 4) {
- uint i, j, k;
- const ushort *rowA = (const ushort *) srcRowA;
- const ushort *rowB = (const ushort *) srcRowB;
- ushort *dst = (ushort *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0xf;
- const int rowAr1 = rowA[k] & 0xf;
- const int rowBr0 = rowB[j] & 0xf;
- const int rowBr1 = rowB[k] & 0xf;
- const int rowAg0 = (rowA[j] >> 4) & 0xf;
- const int rowAg1 = (rowA[k] >> 4) & 0xf;
- const int rowBg0 = (rowB[j] >> 4) & 0xf;
- const int rowBg1 = (rowB[k] >> 4) & 0xf;
- const int rowAb0 = (rowA[j] >> 8) & 0xf;
- const int rowAb1 = (rowA[k] >> 8) & 0xf;
- const int rowBb0 = (rowB[j] >> 8) & 0xf;
- const int rowBb1 = (rowB[k] >> 8) & 0xf;
- const int rowAa0 = (rowA[j] >> 12) & 0xf;
- const int rowAa1 = (rowA[k] >> 12) & 0xf;
- const int rowBa0 = (rowB[j] >> 12) & 0xf;
- const int rowBa1 = (rowB[k] >> 12) & 0xf;
- const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
- const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
- const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
- const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
- dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red;
- }
- }
- else if (datatype == DTYPE_USHORT_1_5_5_5_REV && comps == 4) {
- uint i, j, k;
- const ushort *rowA = (const ushort *) srcRowA;
- const ushort *rowB = (const ushort *) srcRowB;
- ushort *dst = (ushort *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0x1f;
- const int rowAr1 = rowA[k] & 0x1f;
- const int rowBr0 = rowB[j] & 0x1f;
- const int rowBr1 = rowB[k] & 0x1f;
- const int rowAg0 = (rowA[j] >> 5) & 0x1f;
- const int rowAg1 = (rowA[k] >> 5) & 0x1f;
- const int rowBg0 = (rowB[j] >> 5) & 0x1f;
- const int rowBg1 = (rowB[k] >> 5) & 0x1f;
- const int rowAb0 = (rowA[j] >> 10) & 0x1f;
- const int rowAb1 = (rowA[k] >> 10) & 0x1f;
- const int rowBb0 = (rowB[j] >> 10) & 0x1f;
- const int rowBb1 = (rowB[k] >> 10) & 0x1f;
- const int rowAa0 = (rowA[j] >> 15) & 0x1;
- const int rowAa1 = (rowA[k] >> 15) & 0x1;
- const int rowBa0 = (rowB[j] >> 15) & 0x1;
- const int rowBa1 = (rowB[k] >> 15) & 0x1;
- const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
- const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
- const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
- const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2;
- dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red;
- }
- }
- else if (datatype == DTYPE_UBYTE_3_3_2 && comps == 3) {
- uint i, j, k;
- const ubyte *rowA = (const ubyte *) srcRowA;
- const ubyte *rowB = (const ubyte *) srcRowB;
- ubyte *dst = (ubyte *) dstRow;
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0x3;
- const int rowAr1 = rowA[k] & 0x3;
- const int rowBr0 = rowB[j] & 0x3;
- const int rowBr1 = rowB[k] & 0x3;
- const int rowAg0 = (rowA[j] >> 2) & 0x7;
- const int rowAg1 = (rowA[k] >> 2) & 0x7;
- const int rowBg0 = (rowB[j] >> 2) & 0x7;
- const int rowBg1 = (rowB[k] >> 2) & 0x7;
- const int rowAb0 = (rowA[j] >> 5) & 0x7;
- const int rowAb1 = (rowA[k] >> 5) & 0x7;
- const int rowBb0 = (rowB[j] >> 5) & 0x7;
- const int rowBb1 = (rowB[k] >> 5) & 0x7;
- const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2;
- const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2;
- const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2;
- dst[i] = (blue << 5) | (green << 2) | red;
- }
- }
- else {
- debug_printf("bad format in do_row()");
- }
-}
-
-
-/**
- * Average together four rows of a source image to produce a single new
- * row in the dest image. It's legal for the two source rows to point
- * to the same data. The source width must be equal to either the
- * dest width or two times the dest width.
- *
- * \param datatype GL pixel type \c GL_UNSIGNED_BYTE, \c GL_UNSIGNED_SHORT,
- * \c GL_FLOAT, etc.
- * \param comps number of components per pixel (1..4)
- * \param srcWidth Width of a row in the source data
- * \param srcRowA Pointer to one of the rows of source data
- * \param srcRowB Pointer to one of the rows of source data
- * \param srcRowC Pointer to one of the rows of source data
- * \param srcRowD Pointer to one of the rows of source data
- * \param dstWidth Width of a row in the destination data
- * \param srcRowA Pointer to the row of destination data
- */
-static void
-do_row_3D(enum dtype datatype, uint comps, int srcWidth,
- const void *srcRowA, const void *srcRowB,
- const void *srcRowC, const void *srcRowD,
- int dstWidth, void *dstRow)
-{
- const uint k0 = (srcWidth == dstWidth) ? 0 : 1;
- const uint colStride = (srcWidth == dstWidth) ? 1 : 2;
- uint i, j, k;
-
- assert(comps >= 1);
- assert(comps <= 4);
-
- if ((datatype == DTYPE_UBYTE) && (comps == 4)) {
- DECLARE_ROW_POINTERS(ubyte, 4);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- FILTER_3D(1);
- FILTER_3D(2);
- FILTER_3D(3);
- }
- }
- else if ((datatype == DTYPE_UBYTE) && (comps == 3)) {
- DECLARE_ROW_POINTERS(ubyte, 3);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- FILTER_3D(1);
- FILTER_3D(2);
- }
- }
- else if ((datatype == DTYPE_UBYTE) && (comps == 2)) {
- DECLARE_ROW_POINTERS(ubyte, 2);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- FILTER_3D(1);
- }
- }
- else if ((datatype == DTYPE_UBYTE) && (comps == 1)) {
- DECLARE_ROW_POINTERS(ubyte, 1);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- }
- }
- else if ((datatype == DTYPE_USHORT) && (comps == 4)) {
- DECLARE_ROW_POINTERS(ushort, 4);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- FILTER_3D(1);
- FILTER_3D(2);
- FILTER_3D(3);
- }
- }
- else if ((datatype == DTYPE_USHORT) && (comps == 3)) {
- DECLARE_ROW_POINTERS(ushort, 3);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- FILTER_3D(1);
- FILTER_3D(2);
- }
- }
- else if ((datatype == DTYPE_USHORT) && (comps == 2)) {
- DECLARE_ROW_POINTERS(ushort, 2);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- FILTER_3D(1);
- }
- }
- else if ((datatype == DTYPE_USHORT) && (comps == 1)) {
- DECLARE_ROW_POINTERS(ushort, 1);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_3D(0);
- }
- }
- else if ((datatype == DTYPE_FLOAT) && (comps == 4)) {
- DECLARE_ROW_POINTERS(float, 4);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_F_3D(0);
- FILTER_F_3D(1);
- FILTER_F_3D(2);
- FILTER_F_3D(3);
- }
- }
- else if ((datatype == DTYPE_FLOAT) && (comps == 3)) {
- DECLARE_ROW_POINTERS(float, 3);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_F_3D(0);
- FILTER_F_3D(1);
- FILTER_F_3D(2);
- }
- }
- else if ((datatype == DTYPE_FLOAT) && (comps == 2)) {
- DECLARE_ROW_POINTERS(float, 2);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_F_3D(0);
- FILTER_F_3D(1);
- }
- }
- else if ((datatype == DTYPE_FLOAT) && (comps == 1)) {
- DECLARE_ROW_POINTERS(float, 1);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_F_3D(0);
- }
- }
- else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 4)) {
- DECLARE_ROW_POINTERS(half_float, 4);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_HF_3D(0);
- FILTER_HF_3D(1);
- FILTER_HF_3D(2);
- FILTER_HF_3D(3);
- }
- }
- else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 3)) {
- DECLARE_ROW_POINTERS(half_float, 4);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_HF_3D(0);
- FILTER_HF_3D(1);
- FILTER_HF_3D(2);
- }
- }
- else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 2)) {
- DECLARE_ROW_POINTERS(half_float, 4);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_HF_3D(0);
- FILTER_HF_3D(1);
- }
- }
- else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 1)) {
- DECLARE_ROW_POINTERS(half_float, 4);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- FILTER_HF_3D(0);
- }
- }
- else if ((datatype == DTYPE_UINT) && (comps == 1)) {
- const uint *rowA = (const uint *) srcRowA;
- const uint *rowB = (const uint *) srcRowB;
- const uint *rowC = (const uint *) srcRowC;
- const uint *rowD = (const uint *) srcRowD;
- float *dst = (float *) dstRow;
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const uint64_t tmp = (((uint64_t) rowA[j] + (uint64_t) rowA[k])
- + ((uint64_t) rowB[j] + (uint64_t) rowB[k])
- + ((uint64_t) rowC[j] + (uint64_t) rowC[k])
- + ((uint64_t) rowD[j] + (uint64_t) rowD[k]));
- dst[i] = (float)((double) tmp * 0.125);
- }
- }
- else if ((datatype == DTYPE_USHORT_5_6_5) && (comps == 3)) {
- DECLARE_ROW_POINTERS0(ushort);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0x1f;
- const int rowAr1 = rowA[k] & 0x1f;
- const int rowBr0 = rowB[j] & 0x1f;
- const int rowBr1 = rowB[k] & 0x1f;
- const int rowCr0 = rowC[j] & 0x1f;
- const int rowCr1 = rowC[k] & 0x1f;
- const int rowDr0 = rowD[j] & 0x1f;
- const int rowDr1 = rowD[k] & 0x1f;
- const int rowAg0 = (rowA[j] >> 5) & 0x3f;
- const int rowAg1 = (rowA[k] >> 5) & 0x3f;
- const int rowBg0 = (rowB[j] >> 5) & 0x3f;
- const int rowBg1 = (rowB[k] >> 5) & 0x3f;
- const int rowCg0 = (rowC[j] >> 5) & 0x3f;
- const int rowCg1 = (rowC[k] >> 5) & 0x3f;
- const int rowDg0 = (rowD[j] >> 5) & 0x3f;
- const int rowDg1 = (rowD[k] >> 5) & 0x3f;
- const int rowAb0 = (rowA[j] >> 11) & 0x1f;
- const int rowAb1 = (rowA[k] >> 11) & 0x1f;
- const int rowBb0 = (rowB[j] >> 11) & 0x1f;
- const int rowBb1 = (rowB[k] >> 11) & 0x1f;
- const int rowCb0 = (rowC[j] >> 11) & 0x1f;
- const int rowCb1 = (rowC[k] >> 11) & 0x1f;
- const int rowDb0 = (rowD[j] >> 11) & 0x1f;
- const int rowDb1 = (rowD[k] >> 11) & 0x1f;
- const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
- rowCr0, rowCr1, rowDr0, rowDr1);
- const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
- rowCg0, rowCg1, rowDg0, rowDg1);
- const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
- rowCb0, rowCb1, rowDb0, rowDb1);
- dst[i] = (b << 11) | (g << 5) | r;
- }
- }
- else if ((datatype == DTYPE_USHORT_4_4_4_4) && (comps == 4)) {
- DECLARE_ROW_POINTERS0(ushort);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0xf;
- const int rowAr1 = rowA[k] & 0xf;
- const int rowBr0 = rowB[j] & 0xf;
- const int rowBr1 = rowB[k] & 0xf;
- const int rowCr0 = rowC[j] & 0xf;
- const int rowCr1 = rowC[k] & 0xf;
- const int rowDr0 = rowD[j] & 0xf;
- const int rowDr1 = rowD[k] & 0xf;
- const int rowAg0 = (rowA[j] >> 4) & 0xf;
- const int rowAg1 = (rowA[k] >> 4) & 0xf;
- const int rowBg0 = (rowB[j] >> 4) & 0xf;
- const int rowBg1 = (rowB[k] >> 4) & 0xf;
- const int rowCg0 = (rowC[j] >> 4) & 0xf;
- const int rowCg1 = (rowC[k] >> 4) & 0xf;
- const int rowDg0 = (rowD[j] >> 4) & 0xf;
- const int rowDg1 = (rowD[k] >> 4) & 0xf;
- const int rowAb0 = (rowA[j] >> 8) & 0xf;
- const int rowAb1 = (rowA[k] >> 8) & 0xf;
- const int rowBb0 = (rowB[j] >> 8) & 0xf;
- const int rowBb1 = (rowB[k] >> 8) & 0xf;
- const int rowCb0 = (rowC[j] >> 8) & 0xf;
- const int rowCb1 = (rowC[k] >> 8) & 0xf;
- const int rowDb0 = (rowD[j] >> 8) & 0xf;
- const int rowDb1 = (rowD[k] >> 8) & 0xf;
- const int rowAa0 = (rowA[j] >> 12) & 0xf;
- const int rowAa1 = (rowA[k] >> 12) & 0xf;
- const int rowBa0 = (rowB[j] >> 12) & 0xf;
- const int rowBa1 = (rowB[k] >> 12) & 0xf;
- const int rowCa0 = (rowC[j] >> 12) & 0xf;
- const int rowCa1 = (rowC[k] >> 12) & 0xf;
- const int rowDa0 = (rowD[j] >> 12) & 0xf;
- const int rowDa1 = (rowD[k] >> 12) & 0xf;
- const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
- rowCr0, rowCr1, rowDr0, rowDr1);
- const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
- rowCg0, rowCg1, rowDg0, rowDg1);
- const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
- rowCb0, rowCb1, rowDb0, rowDb1);
- const int a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
- rowCa0, rowCa1, rowDa0, rowDa1);
-
- dst[i] = (a << 12) | (b << 8) | (g << 4) | r;
- }
- }
- else if ((datatype == DTYPE_USHORT_1_5_5_5_REV) && (comps == 4)) {
- DECLARE_ROW_POINTERS0(ushort);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0x1f;
- const int rowAr1 = rowA[k] & 0x1f;
- const int rowBr0 = rowB[j] & 0x1f;
- const int rowBr1 = rowB[k] & 0x1f;
- const int rowCr0 = rowC[j] & 0x1f;
- const int rowCr1 = rowC[k] & 0x1f;
- const int rowDr0 = rowD[j] & 0x1f;
- const int rowDr1 = rowD[k] & 0x1f;
- const int rowAg0 = (rowA[j] >> 5) & 0x1f;
- const int rowAg1 = (rowA[k] >> 5) & 0x1f;
- const int rowBg0 = (rowB[j] >> 5) & 0x1f;
- const int rowBg1 = (rowB[k] >> 5) & 0x1f;
- const int rowCg0 = (rowC[j] >> 5) & 0x1f;
- const int rowCg1 = (rowC[k] >> 5) & 0x1f;
- const int rowDg0 = (rowD[j] >> 5) & 0x1f;
- const int rowDg1 = (rowD[k] >> 5) & 0x1f;
- const int rowAb0 = (rowA[j] >> 10) & 0x1f;
- const int rowAb1 = (rowA[k] >> 10) & 0x1f;
- const int rowBb0 = (rowB[j] >> 10) & 0x1f;
- const int rowBb1 = (rowB[k] >> 10) & 0x1f;
- const int rowCb0 = (rowC[j] >> 10) & 0x1f;
- const int rowCb1 = (rowC[k] >> 10) & 0x1f;
- const int rowDb0 = (rowD[j] >> 10) & 0x1f;
- const int rowDb1 = (rowD[k] >> 10) & 0x1f;
- const int rowAa0 = (rowA[j] >> 15) & 0x1;
- const int rowAa1 = (rowA[k] >> 15) & 0x1;
- const int rowBa0 = (rowB[j] >> 15) & 0x1;
- const int rowBa1 = (rowB[k] >> 15) & 0x1;
- const int rowCa0 = (rowC[j] >> 15) & 0x1;
- const int rowCa1 = (rowC[k] >> 15) & 0x1;
- const int rowDa0 = (rowD[j] >> 15) & 0x1;
- const int rowDa1 = (rowD[k] >> 15) & 0x1;
- const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
- rowCr0, rowCr1, rowDr0, rowDr1);
- const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
- rowCg0, rowCg1, rowDg0, rowDg1);
- const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
- rowCb0, rowCb1, rowDb0, rowDb1);
- const int a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1,
- rowCa0, rowCa1, rowDa0, rowDa1);
-
- dst[i] = (a << 15) | (b << 10) | (g << 5) | r;
- }
- }
- else if ((datatype == DTYPE_UBYTE_3_3_2) && (comps == 3)) {
- DECLARE_ROW_POINTERS0(ushort);
-
- for (i = j = 0, k = k0; i < (uint) dstWidth;
- i++, j += colStride, k += colStride) {
- const int rowAr0 = rowA[j] & 0x3;
- const int rowAr1 = rowA[k] & 0x3;
- const int rowBr0 = rowB[j] & 0x3;
- const int rowBr1 = rowB[k] & 0x3;
- const int rowCr0 = rowC[j] & 0x3;
- const int rowCr1 = rowC[k] & 0x3;
- const int rowDr0 = rowD[j] & 0x3;
- const int rowDr1 = rowD[k] & 0x3;
- const int rowAg0 = (rowA[j] >> 2) & 0x7;
- const int rowAg1 = (rowA[k] >> 2) & 0x7;
- const int rowBg0 = (rowB[j] >> 2) & 0x7;
- const int rowBg1 = (rowB[k] >> 2) & 0x7;
- const int rowCg0 = (rowC[j] >> 2) & 0x7;
- const int rowCg1 = (rowC[k] >> 2) & 0x7;
- const int rowDg0 = (rowD[j] >> 2) & 0x7;
- const int rowDg1 = (rowD[k] >> 2) & 0x7;
- const int rowAb0 = (rowA[j] >> 5) & 0x7;
- const int rowAb1 = (rowA[k] >> 5) & 0x7;
- const int rowBb0 = (rowB[j] >> 5) & 0x7;
- const int rowBb1 = (rowB[k] >> 5) & 0x7;
- const int rowCb0 = (rowC[j] >> 5) & 0x7;
- const int rowCb1 = (rowC[k] >> 5) & 0x7;
- const int rowDb0 = (rowD[j] >> 5) & 0x7;
- const int rowDb1 = (rowD[k] >> 5) & 0x7;
- const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1,
- rowCr0, rowCr1, rowDr0, rowDr1);
- const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1,
- rowCg0, rowCg1, rowDg0, rowDg1);
- const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1,
- rowCb0, rowCb1, rowDb0, rowDb1);
- dst[i] = (b << 5) | (g << 2) | r;
- }
- }
- else {
- debug_printf("bad format in do_row_3D()");
- }
-}
-
-
-
-static void
-format_to_type_comps(enum pipe_format pformat,
- enum dtype *datatype, uint *comps)
-{
- /* XXX I think this could be implemented in terms of the pf_*() functions */
- switch (pformat) {
- case PIPE_FORMAT_B8G8R8A8_UNORM:
- case PIPE_FORMAT_B8G8R8X8_UNORM:
- case PIPE_FORMAT_A8R8G8B8_UNORM:
- case PIPE_FORMAT_X8R8G8B8_UNORM:
- case PIPE_FORMAT_A8B8G8R8_SRGB:
- case PIPE_FORMAT_X8B8G8R8_SRGB:
- case PIPE_FORMAT_B8G8R8A8_SRGB:
- case PIPE_FORMAT_B8G8R8X8_SRGB:
- case PIPE_FORMAT_A8R8G8B8_SRGB:
- case PIPE_FORMAT_X8R8G8B8_SRGB:
- case PIPE_FORMAT_R8G8B8_SRGB:
- *datatype = DTYPE_UBYTE;
- *comps = 4;
- return;
- case PIPE_FORMAT_B5G5R5X1_UNORM:
- case PIPE_FORMAT_B5G5R5A1_UNORM:
- *datatype = DTYPE_USHORT_1_5_5_5_REV;
- *comps = 4;
- return;
- case PIPE_FORMAT_B4G4R4A4_UNORM:
- *datatype = DTYPE_USHORT_4_4_4_4;
- *comps = 4;
- return;
- case PIPE_FORMAT_B5G6R5_UNORM:
- *datatype = DTYPE_USHORT_5_6_5;
- *comps = 3;
- return;
- case PIPE_FORMAT_L8_UNORM:
- case PIPE_FORMAT_L8_SRGB:
- case PIPE_FORMAT_A8_UNORM:
- case PIPE_FORMAT_I8_UNORM:
- *datatype = DTYPE_UBYTE;
- *comps = 1;
- return;
- case PIPE_FORMAT_L8A8_UNORM:
- case PIPE_FORMAT_L8A8_SRGB:
- *datatype = DTYPE_UBYTE;
- *comps = 2;
- return;
- default:
- assert(0);
- *datatype = DTYPE_UBYTE;
- *comps = 0;
- break;
- }
-}
-
-
-static void
-reduce_1d(enum pipe_format pformat,
- int srcWidth, const ubyte *srcPtr,
- int dstWidth, ubyte *dstPtr)
-{
- enum dtype datatype;
- uint comps;
-
- format_to_type_comps(pformat, &datatype, &comps);
-
- /* we just duplicate the input row, kind of hack, saves code */
- do_row(datatype, comps,
- srcWidth, srcPtr, srcPtr,
- dstWidth, dstPtr);
-}
-
-
-/**
- * Strides are in bytes. If zero, it'll be computed as width * bpp.
- */
-static void
-reduce_2d(enum pipe_format pformat,
- int srcWidth, int srcHeight,
- int srcRowStride, const ubyte *srcPtr,
- int dstWidth, int dstHeight,
- int dstRowStride, ubyte *dstPtr)
-{
- enum dtype datatype;
- uint comps;
- const int bpt = util_format_get_blocksize(pformat);
- const ubyte *srcA, *srcB;
- ubyte *dst;
- int row;
-
- format_to_type_comps(pformat, &datatype, &comps);
-
- if (!srcRowStride)
- srcRowStride = bpt * srcWidth;
-
- if (!dstRowStride)
- dstRowStride = bpt * dstWidth;
-
- /* Compute src and dst pointers */
- srcA = srcPtr;
- if (srcHeight > 1)
- srcB = srcA + srcRowStride;
- else
- srcB = srcA;
- dst = dstPtr;
-
- for (row = 0; row < dstHeight; row++) {
- do_row(datatype, comps,
- srcWidth, srcA, srcB,
- dstWidth, dst);
- srcA += 2 * srcRowStride;
- srcB += 2 * srcRowStride;
- dst += dstRowStride;
- }
-}
-
-
-static void
-reduce_3d(enum pipe_format pformat,
- int srcWidth, int srcHeight, int srcDepth,
- int srcRowStride, int srcImageStride, const ubyte *srcPtr,
- int dstWidth, int dstHeight, int dstDepth,
- int dstRowStride, int dstImageStride, ubyte *dstPtr)
-{
- const int bpt = util_format_get_blocksize(pformat);
- int img, row;
- int srcImageOffset, srcRowOffset;
- enum dtype datatype;
- uint comps;
-
- format_to_type_comps(pformat, &datatype, &comps);
-
- /* XXX I think we should rather assert those strides */
- if (!srcImageStride)
- srcImageStride = srcWidth * srcHeight * bpt;
- if (!dstImageStride)
- dstImageStride = dstWidth * dstHeight * bpt;
-
- if (!srcRowStride)
- srcRowStride = srcWidth * bpt;
- if (!dstRowStride)
- dstRowStride = dstWidth * bpt;
-
- /* Offset between adjacent src images to be averaged together */
- srcImageOffset = (srcDepth == dstDepth) ? 0 : srcImageStride;
-
- /* Offset between adjacent src rows to be averaged together */
- srcRowOffset = (srcHeight == dstHeight) ? 0 : srcRowStride;
-
- /*
- * Need to average together up to 8 src pixels for each dest pixel.
- * Break that down into 3 operations:
- * 1. take two rows from source image and average them together.
- * 2. take two rows from next source image and average them together.
- * 3. take the two averaged rows and average them for the final dst row.
- */
-
- /*
- printf("mip3d %d x %d x %d -> %d x %d x %d\n",
- srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth);
- */
-
- for (img = 0; img < dstDepth; img++) {
- /* first source image pointer */
- const ubyte *imgSrcA = srcPtr
- + img * (srcImageStride + srcImageOffset);
- /* second source image pointer */
- const ubyte *imgSrcB = imgSrcA + srcImageOffset;
- /* address of the dest image */
- ubyte *imgDst = dstPtr + img * dstImageStride;
-
- /* setup the four source row pointers and the dest row pointer */
- const ubyte *srcImgARowA = imgSrcA;
- const ubyte *srcImgARowB = imgSrcA + srcRowOffset;
- const ubyte *srcImgBRowA = imgSrcB;
- const ubyte *srcImgBRowB = imgSrcB + srcRowOffset;
- ubyte *dstImgRow = imgDst;
-
- for (row = 0; row < dstHeight; row++) {
- do_row_3D(datatype, comps, srcWidth,
- srcImgARowA, srcImgARowB,
- srcImgBRowA, srcImgBRowB,
- dstWidth, dstImgRow);
-
- /* advance to next rows */
- srcImgARowA += srcRowStride + srcRowOffset;
- srcImgARowB += srcRowStride + srcRowOffset;
- srcImgBRowA += srcRowStride + srcRowOffset;
- srcImgBRowB += srcRowStride + srcRowOffset;
- dstImgRow += dstImageStride;
- }
- }
-}
-
-
-
-
-static void
-make_1d_mipmap(struct gen_mipmap_state *ctx,
- struct pipe_resource *pt,
- uint layer, uint baseLevel, uint lastLevel)
-{
- struct pipe_context *pipe = ctx->pipe;
- uint dstLevel;
-
- for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
- const uint srcLevel = dstLevel - 1;
- struct pipe_transfer *srcTrans, *dstTrans;
- void *srcMap, *dstMap;
-
- srcTrans = pipe_get_transfer(pipe, pt, srcLevel, layer,
- PIPE_TRANSFER_READ, 0, 0,
- u_minify(pt->width0, srcLevel),
- u_minify(pt->height0, srcLevel));
- dstTrans = pipe_get_transfer(pipe, pt, dstLevel, layer,
- PIPE_TRANSFER_WRITE, 0, 0,
- u_minify(pt->width0, dstLevel),
- u_minify(pt->height0, dstLevel));
-
- srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans);
- dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans);
-
- reduce_1d(pt->format,
- srcTrans->box.width, srcMap,
- dstTrans->box.width, dstMap);
-
- pipe->transfer_unmap(pipe, srcTrans);
- pipe->transfer_unmap(pipe, dstTrans);
-
- pipe->transfer_destroy(pipe, srcTrans);
- pipe->transfer_destroy(pipe, dstTrans);
- }
-}
-
-
-static void
-make_2d_mipmap(struct gen_mipmap_state *ctx,
- struct pipe_resource *pt,
- uint layer, uint baseLevel, uint lastLevel)
-{
- struct pipe_context *pipe = ctx->pipe;
- uint dstLevel;
-
- assert(util_format_get_blockwidth(pt->format) == 1);
- assert(util_format_get_blockheight(pt->format) == 1);
-
- for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
- const uint srcLevel = dstLevel - 1;
- struct pipe_transfer *srcTrans, *dstTrans;
- ubyte *srcMap, *dstMap;
-
- srcTrans = pipe_get_transfer(pipe, pt, srcLevel, layer,
- PIPE_TRANSFER_READ, 0, 0,
- u_minify(pt->width0, srcLevel),
- u_minify(pt->height0, srcLevel));
- dstTrans = pipe_get_transfer(pipe, pt, dstLevel, layer,
- PIPE_TRANSFER_WRITE, 0, 0,
- u_minify(pt->width0, dstLevel),
- u_minify(pt->height0, dstLevel));
-
- srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans);
- dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans);
-
- reduce_2d(pt->format,
- srcTrans->box.width, srcTrans->box.height,
- srcTrans->stride, srcMap,
- dstTrans->box.width, dstTrans->box.height,
- dstTrans->stride, dstMap);
-
- pipe->transfer_unmap(pipe, srcTrans);
- pipe->transfer_unmap(pipe, dstTrans);
-
- pipe->transfer_destroy(pipe, srcTrans);
- pipe->transfer_destroy(pipe, dstTrans);
- }
-}
-
-
-/* XXX looks a bit more like it could work now but need to test */
-static void
-make_3d_mipmap(struct gen_mipmap_state *ctx,
- struct pipe_resource *pt,
- uint face, uint baseLevel, uint lastLevel)
-{
- struct pipe_context *pipe = ctx->pipe;
- uint dstLevel;
- struct pipe_box src_box, dst_box;
-
- assert(util_format_get_blockwidth(pt->format) == 1);
- assert(util_format_get_blockheight(pt->format) == 1);
-
- src_box.x = src_box.y = src_box.z = 0;
- dst_box.x = dst_box.y = dst_box.z = 0;
-
- for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
- const uint srcLevel = dstLevel - 1;
- struct pipe_transfer *srcTrans, *dstTrans;
- ubyte *srcMap, *dstMap;
- struct pipe_box src_box, dst_box;
- src_box.width = u_minify(pt->width0, srcLevel);
- src_box.height = u_minify(pt->height0, srcLevel);
- src_box.depth = u_minify(pt->depth0, srcLevel);
- dst_box.width = u_minify(pt->width0, dstLevel);
- dst_box.height = u_minify(pt->height0, dstLevel);
- dst_box.depth = u_minify(pt->depth0, dstLevel);
-
- srcTrans = pipe->get_transfer(pipe, pt, srcLevel,
- PIPE_TRANSFER_READ,
- &src_box);
- dstTrans = pipe->get_transfer(pipe, pt, dstLevel,
- PIPE_TRANSFER_WRITE,
- &dst_box);
-
- srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans);
- dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans);
-
- reduce_3d(pt->format,
- srcTrans->box.width, srcTrans->box.height, srcTrans->box.depth,
- srcTrans->stride, srcTrans->layer_stride, srcMap,
- dstTrans->box.width, dstTrans->box.height, dstTrans->box.depth,
- dstTrans->stride, dstTrans->layer_stride, dstMap);
-
- pipe->transfer_unmap(pipe, srcTrans);
- pipe->transfer_unmap(pipe, dstTrans);
-
- pipe->transfer_destroy(pipe, srcTrans);
- pipe->transfer_destroy(pipe, dstTrans);
- }
-}
-
-
-static void
-fallback_gen_mipmap(struct gen_mipmap_state *ctx,
- struct pipe_resource *pt,
- uint layer, uint baseLevel, uint lastLevel)
-{
- switch (pt->target) {
- case PIPE_TEXTURE_1D:
- make_1d_mipmap(ctx, pt, layer, baseLevel, lastLevel);
- break;
- case PIPE_TEXTURE_2D:
- case PIPE_TEXTURE_RECT:
- case PIPE_TEXTURE_CUBE:
- make_2d_mipmap(ctx, pt, layer, baseLevel, lastLevel);
- break;
- case PIPE_TEXTURE_3D:
- make_3d_mipmap(ctx, pt, layer, baseLevel, lastLevel);
- break;
- default:
- assert(0);
- }
-}
-
-
-/**
- * Create a mipmap generation context.
- * The idea is to create one of these and re-use it each time we need to
- * generate a mipmap.
- */
-struct gen_mipmap_state *
-util_create_gen_mipmap(struct pipe_context *pipe,
- struct cso_context *cso)
-{
- struct gen_mipmap_state *ctx;
- uint i;
-
- ctx = CALLOC_STRUCT(gen_mipmap_state);
- if (!ctx)
- return NULL;
-
- ctx->pipe = pipe;
- ctx->cso = cso;
-
- /* disabled blending/masking */
- memset(&ctx->blend, 0, sizeof(ctx->blend));
- ctx->blend.rt[0].colormask = PIPE_MASK_RGBA;
-
- /* no-op depth/stencil/alpha */
- memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil));
-
- /* rasterizer */
- memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer));
- ctx->rasterizer.cull_face = PIPE_FACE_NONE;
- ctx->rasterizer.gl_rasterization_rules = 1;
-
- /* sampler state */
- memset(&ctx->sampler, 0, sizeof(ctx->sampler));
- ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
- ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
- ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
- ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST;
- ctx->sampler.normalized_coords = 1;
-
- /* vertex elements state */
- memset(&ctx->velem[0], 0, sizeof(ctx->velem[0]) * 2);
- for (i = 0; i < 2; i++) {
- ctx->velem[i].src_offset = i * 4 * sizeof(float);
- ctx->velem[i].instance_divisor = 0;
- ctx->velem[i].vertex_buffer_index = 0;
- ctx->velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
- }
-
- /* vertex data that doesn't change */
- for (i = 0; i < 4; i++) {
- ctx->vertices[i][0][2] = 0.0f; /* z */
- ctx->vertices[i][0][3] = 1.0f; /* w */
- ctx->vertices[i][1][3] = 1.0f; /* q */
- }
-
- /* Note: the actual vertex buffer is allocated as needed below */
-
- return ctx;
-}
-
-
-/**
- * Helper function to set the fragment shaders.
- */
-static INLINE void
-set_fragment_shader(struct gen_mipmap_state *ctx, uint type)
-{
- if (!ctx->fs[type])
- ctx->fs[type] =
- util_make_fragment_tex_shader(ctx->pipe, type,
- TGSI_INTERPOLATE_LINEAR);
-
- cso_set_fragment_shader_handle(ctx->cso, ctx->fs[type]);
-}
-
-
-/**
- * Helper function to set the vertex shader.
- */
-static INLINE void
-set_vertex_shader(struct gen_mipmap_state *ctx)
-{
- /* vertex shader - still required to provide the linkage between
- * fragment shader input semantics and vertex_element/buffers.
- */
- if (!ctx->vs)
- {
- const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
- TGSI_SEMANTIC_GENERIC };
- const uint semantic_indexes[] = { 0, 0 };
- ctx->vs = util_make_vertex_passthrough_shader(ctx->pipe, 2,
- semantic_names,
- semantic_indexes);
- }
-
- cso_set_vertex_shader_handle(ctx->cso, ctx->vs);
-}
-
-
-/**
- * Get next "slot" of vertex space in the vertex buffer.
- * We're allocating one large vertex buffer and using it piece by piece.
- */
-static unsigned
-get_next_slot(struct gen_mipmap_state *ctx)
-{
- const unsigned max_slots = 4096 / sizeof ctx->vertices;
-
- if (ctx->vbuf_slot >= max_slots)
- util_gen_mipmap_flush( ctx );
-
- if (!ctx->vbuf) {
- ctx->vbuf = pipe_buffer_create(ctx->pipe->screen,
- PIPE_BIND_VERTEX_BUFFER,
- PIPE_USAGE_STREAM,
- max_slots * sizeof ctx->vertices);
- }
-
- return ctx->vbuf_slot++ * sizeof ctx->vertices;
-}
-
-
-static unsigned
-set_vertex_data(struct gen_mipmap_state *ctx,
- enum pipe_texture_target tex_target,
- uint layer, float r)
-{
- unsigned offset;
-
- /* vert[0].position */
- ctx->vertices[0][0][0] = -1.0f; /*x*/
- ctx->vertices[0][0][1] = -1.0f; /*y*/
-
- /* vert[1].position */
- ctx->vertices[1][0][0] = 1.0f;
- ctx->vertices[1][0][1] = -1.0f;
-
- /* vert[2].position */
- ctx->vertices[2][0][0] = 1.0f;
- ctx->vertices[2][0][1] = 1.0f;
-
- /* vert[3].position */
- ctx->vertices[3][0][0] = -1.0f;
- ctx->vertices[3][0][1] = 1.0f;
-
- /* Setup vertex texcoords. This is a little tricky for cube maps. */
- if (tex_target == PIPE_TEXTURE_CUBE) {
- static const float st[4][2] = {
- {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}
- };
-
- util_map_texcoords2d_onto_cubemap(layer, &st[0][0], 2,
- &ctx->vertices[0][1][0], 8);
- }
- else if (tex_target == PIPE_TEXTURE_1D_ARRAY) {
- /* 1D texture array */
- ctx->vertices[0][1][0] = 0.0f; /*s*/
- ctx->vertices[0][1][1] = r; /*t*/
- ctx->vertices[0][1][2] = 0.0f; /*r*/
-
- ctx->vertices[1][1][0] = 1.0f;
- ctx->vertices[1][1][1] = r;
- ctx->vertices[1][1][2] = 0.0f;
-
- ctx->vertices[2][1][0] = 1.0f;
- ctx->vertices[2][1][1] = r;
- ctx->vertices[2][1][2] = 0.0f;
-
- ctx->vertices[3][1][0] = 0.0f;
- ctx->vertices[3][1][1] = r;
- ctx->vertices[3][1][2] = 0.0f;
- } else {
- /* 1D/2D/3D/2D array */
- ctx->vertices[0][1][0] = 0.0f; /*s*/
- ctx->vertices[0][1][1] = 0.0f; /*t*/
- ctx->vertices[0][1][2] = r; /*r*/
-
- ctx->vertices[1][1][0] = 1.0f;
- ctx->vertices[1][1][1] = 0.0f;
- ctx->vertices[1][1][2] = r;
-
- ctx->vertices[2][1][0] = 1.0f;
- ctx->vertices[2][1][1] = 1.0f;
- ctx->vertices[2][1][2] = r;
-
- ctx->vertices[3][1][0] = 0.0f;
- ctx->vertices[3][1][1] = 1.0f;
- ctx->vertices[3][1][2] = r;
- }
-
- offset = get_next_slot( ctx );
-
- pipe_buffer_write_nooverlap(ctx->pipe, ctx->vbuf,
- offset, sizeof(ctx->vertices), ctx->vertices);
-
- return offset;
-}
-
-
-
-/**
- * Destroy a mipmap generation context
- */
-void
-util_destroy_gen_mipmap(struct gen_mipmap_state *ctx)
-{
- struct pipe_context *pipe = ctx->pipe;
- unsigned i;
-
- for (i = 0; i < Elements(ctx->fs); i++)
- if (ctx->fs[i])
- pipe->delete_fs_state(pipe, ctx->fs[i]);
-
- if (ctx->vs)
- pipe->delete_vs_state(pipe, ctx->vs);
-
- pipe_resource_reference(&ctx->vbuf, NULL);
-
- FREE(ctx);
-}
-
-
-
-/* Release vertex buffer at end of frame to avoid synchronous
- * rendering.
- */
-void util_gen_mipmap_flush( struct gen_mipmap_state *ctx )
-{
- pipe_resource_reference(&ctx->vbuf, NULL);
- ctx->vbuf_slot = 0;
-}
-
-
-/**
- * Generate mipmap images. It's assumed all needed texture memory is
- * already allocated.
- *
- * \param psv the sampler view to the texture to generate mipmap levels for
- * \param face which cube face to generate mipmaps for (0 for non-cube maps)
- * \param baseLevel the first mipmap level to use as a src
- * \param lastLevel the last mipmap level to generate
- * \param filter the minification filter used to generate mipmap levels with
- * \param filter one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST
- */
-void
-util_gen_mipmap(struct gen_mipmap_state *ctx,
- struct pipe_sampler_view *psv,
- uint face, uint baseLevel, uint lastLevel, uint filter)
-{
- struct pipe_context *pipe = ctx->pipe;
- struct pipe_screen *screen = pipe->screen;
- struct pipe_framebuffer_state fb;
- struct pipe_resource *pt = psv->texture;
- uint dstLevel;
- uint offset;
- uint type;
-
- /* The texture object should have room for the levels which we're
- * about to generate.
- */
- assert(lastLevel <= pt->last_level);
-
- /* If this fails, why are we here? */
- assert(lastLevel > baseLevel);
-
- assert(filter == PIPE_TEX_FILTER_LINEAR ||
- filter == PIPE_TEX_FILTER_NEAREST);
-
- switch (pt->target) {
- case PIPE_TEXTURE_1D:
- type = TGSI_TEXTURE_1D;
- break;
- case PIPE_TEXTURE_2D:
- type = TGSI_TEXTURE_2D;
- break;
- case PIPE_TEXTURE_3D:
- type = TGSI_TEXTURE_3D;
- break;
- case PIPE_TEXTURE_CUBE:
- type = TGSI_TEXTURE_CUBE;
- break;
- case PIPE_TEXTURE_1D_ARRAY:
- type = TGSI_TEXTURE_1D_ARRAY;
- break;
- case PIPE_TEXTURE_2D_ARRAY:
- type = TGSI_TEXTURE_2D_ARRAY;
- break;
- default:
- assert(0);
- type = TGSI_TEXTURE_2D;
- }
-
- /* check if we can render in the texture's format */
- if (!screen->is_format_supported(screen, psv->format, pt->target,
- pt->nr_samples, PIPE_BIND_RENDER_TARGET)) {
- fallback_gen_mipmap(ctx, pt, face, baseLevel, lastLevel);
- return;
- }
-
- /* save state (restored below) */
- cso_save_blend(ctx->cso);
- cso_save_depth_stencil_alpha(ctx->cso);
- cso_save_rasterizer(ctx->cso);
- cso_save_samplers(ctx->cso);
- cso_save_fragment_sampler_views(ctx->cso);
- cso_save_framebuffer(ctx->cso);
- cso_save_fragment_shader(ctx->cso);
- cso_save_vertex_shader(ctx->cso);
- cso_save_viewport(ctx->cso);
- cso_save_clip(ctx->cso);
- cso_save_vertex_elements(ctx->cso);
-
- /* bind our state */
- cso_set_blend(ctx->cso, &ctx->blend);
- cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil);
- cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
- cso_set_clip(ctx->cso, &ctx->clip);
- cso_set_vertex_elements(ctx->cso, 2, ctx->velem);
-
- set_fragment_shader(ctx, type);
- set_vertex_shader(ctx);
-
- /* init framebuffer state */
- memset(&fb, 0, sizeof(fb));
- fb.nr_cbufs = 1;
-
- /* set min/mag to same filter for faster sw speed */
- ctx->sampler.mag_img_filter = filter;
- ctx->sampler.min_img_filter = filter;
-
- /*
- * XXX for small mipmap levels, it may be faster to use the software
- * fallback path...
- */
- for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) {
- const uint srcLevel = dstLevel - 1;
- struct pipe_viewport_state vp;
- unsigned nr_layers, layer, i;
- float rcoord = 0.0f;
-
- if (pt->target == PIPE_TEXTURE_3D)
- nr_layers = u_minify(pt->depth0, dstLevel);
- else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY)
- nr_layers = pt->array_size;
- else
- nr_layers = 1;
-
- for (i = 0; i < nr_layers; i++) {
- struct pipe_surface *surf, surf_templ;
- if (pt->target == PIPE_TEXTURE_3D) {
- /* in theory with geom shaders and driver with full layer support
- could do that in one go. */
- layer = i;
- /* XXX hmm really? */
- rcoord = (float)layer / (float)nr_layers + 1.0f / (float)(nr_layers * 2);
- } else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY) {
- layer = i;
- rcoord = (float)layer;
- } else
- layer = face;
-
- memset(&surf_templ, 0, sizeof(surf_templ));
- u_surface_default_template(&surf_templ, pt, PIPE_BIND_RENDER_TARGET);
- surf_templ.u.tex.level = dstLevel;
- surf_templ.u.tex.first_layer = layer;
- surf_templ.u.tex.last_layer = layer;
- surf = pipe->create_surface(pipe, pt, &surf_templ);
-
- /*
- * Setup framebuffer / dest surface
- */
- fb.cbufs[0] = surf;
- fb.width = u_minify(pt->width0, dstLevel);
- fb.height = u_minify(pt->height0, dstLevel);
- cso_set_framebuffer(ctx->cso, &fb);
-
- /* viewport */
- vp.scale[0] = 0.5f * fb.width;
- vp.scale[1] = 0.5f * fb.height;
- vp.scale[2] = 1.0f;
- vp.scale[3] = 1.0f;
- vp.translate[0] = 0.5f * fb.width;
- vp.translate[1] = 0.5f * fb.height;
- vp.translate[2] = 0.0f;
- vp.translate[3] = 0.0f;
- cso_set_viewport(ctx->cso, &vp);
-
- /*
- * Setup sampler state
- * Note: we should only have to set the min/max LOD clamps to ensure
- * we grab texels from the right mipmap level. But some hardware
- * has trouble with min clamping so we also set the lod_bias to
- * try to work around that.
- */
- ctx->sampler.min_lod = ctx->sampler.max_lod = (float) srcLevel;
- ctx->sampler.lod_bias = (float) srcLevel;
- cso_single_sampler(ctx->cso, 0, &ctx->sampler);
- cso_single_sampler_done(ctx->cso);
-
- cso_set_fragment_sampler_views(ctx->cso, 1, &psv);
-
- /* quad coords in clip coords */
- offset = set_vertex_data(ctx,
- pt->target,
- face,
- rcoord);
-
- util_draw_vertex_buffer(ctx->pipe,
- ctx->cso,
- ctx->vbuf,
- offset,
- PIPE_PRIM_TRIANGLE_FAN,
- 4, /* verts */
- 2); /* attribs/vert */
-
- /* need to signal that the texture has changed _after_ rendering to it */
- pipe_surface_reference( &surf, NULL );
- }
- }
-
- /* restore state we changed */
- cso_restore_blend(ctx->cso);
- cso_restore_depth_stencil_alpha(ctx->cso);
- cso_restore_rasterizer(ctx->cso);
- cso_restore_samplers(ctx->cso);
- cso_restore_fragment_sampler_views(ctx->cso);
- cso_restore_framebuffer(ctx->cso);
- cso_restore_fragment_shader(ctx->cso);
- cso_restore_vertex_shader(ctx->cso);
- cso_restore_viewport(ctx->cso);
- cso_restore_clip(ctx->cso);
- cso_restore_vertex_elements(ctx->cso);
-}
+/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * Copyright 2008 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 TUNGSTEN GRAPHICS 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 + * Mipmap generation utility + * + * @author Brian Paul + */ + + +#include "pipe/p_context.h" +#include "util/u_debug.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" +#include "pipe/p_shader_tokens.h" +#include "pipe/p_state.h" + +#include "util/u_format.h" +#include "util/u_memory.h" +#include "util/u_draw_quad.h" +#include "util/u_gen_mipmap.h" +#include "util/u_simple_shaders.h" +#include "util/u_math.h" +#include "util/u_texture.h" +#include "util/u_half.h" +#include "util/u_surface.h" + +#include "cso_cache/cso_context.h" + + +struct gen_mipmap_state +{ + struct pipe_context *pipe; + struct cso_context *cso; + + struct pipe_blend_state blend; + struct pipe_depth_stencil_alpha_state depthstencil; + struct pipe_rasterizer_state rasterizer; + struct pipe_sampler_state sampler; + struct pipe_clip_state clip; + struct pipe_vertex_element velem[2]; + + void *vs; + void *fs[TGSI_TEXTURE_COUNT]; /**< Not all are used, but simplifies code */ + + struct pipe_resource *vbuf; /**< quad vertices */ + unsigned vbuf_slot; + + float vertices[4][2][4]; /**< vertex/texcoords for quad */ +}; + + + +enum dtype +{ + DTYPE_UBYTE, + DTYPE_UBYTE_3_3_2, + DTYPE_USHORT, + DTYPE_USHORT_4_4_4_4, + DTYPE_USHORT_5_6_5, + DTYPE_USHORT_1_5_5_5_REV, + DTYPE_UINT, + DTYPE_FLOAT, + DTYPE_HALF_FLOAT +}; + + +typedef uint16_t half_float; + + +/** + * \name Support macros for do_row and do_row_3d + * + * The macro madness is here for two reasons. First, it compacts the code + * slightly. Second, it makes it much easier to adjust the specifics of the + * filter to tune the rounding characteristics. + */ +/*@{*/ +#define DECLARE_ROW_POINTERS(t, e) \ + const t(*rowA)[e] = (const t(*)[e]) srcRowA; \ + const t(*rowB)[e] = (const t(*)[e]) srcRowB; \ + const t(*rowC)[e] = (const t(*)[e]) srcRowC; \ + const t(*rowD)[e] = (const t(*)[e]) srcRowD; \ + t(*dst)[e] = (t(*)[e]) dstRow + +#define DECLARE_ROW_POINTERS0(t) \ + const t *rowA = (const t *) srcRowA; \ + const t *rowB = (const t *) srcRowB; \ + const t *rowC = (const t *) srcRowC; \ + const t *rowD = (const t *) srcRowD; \ + t *dst = (t *) dstRow + +#define FILTER_SUM_3D(Aj, Ak, Bj, Bk, Cj, Ck, Dj, Dk) \ + ((unsigned) Aj + (unsigned) Ak \ + + (unsigned) Bj + (unsigned) Bk \ + + (unsigned) Cj + (unsigned) Ck \ + + (unsigned) Dj + (unsigned) Dk \ + + 4) >> 3 + +#define FILTER_3D(e) \ + do { \ + dst[i][e] = FILTER_SUM_3D(rowA[j][e], rowA[k][e], \ + rowB[j][e], rowB[k][e], \ + rowC[j][e], rowC[k][e], \ + rowD[j][e], rowD[k][e]); \ + } while(0) + +#define FILTER_F_3D(e) \ + do { \ + dst[i][e] = (rowA[j][e] + rowA[k][e] \ + + rowB[j][e] + rowB[k][e] \ + + rowC[j][e] + rowC[k][e] \ + + rowD[j][e] + rowD[k][e]) * 0.125F; \ + } while(0) + +#define FILTER_HF_3D(e) \ + do { \ + const float aj = util_half_to_float(rowA[j][e]); \ + const float ak = util_half_to_float(rowA[k][e]); \ + const float bj = util_half_to_float(rowB[j][e]); \ + const float bk = util_half_to_float(rowB[k][e]); \ + const float cj = util_half_to_float(rowC[j][e]); \ + const float ck = util_half_to_float(rowC[k][e]); \ + const float dj = util_half_to_float(rowD[j][e]); \ + const float dk = util_half_to_float(rowD[k][e]); \ + dst[i][e] = util_float_to_half((aj + ak + bj + bk + cj + ck + dj + dk) \ + * 0.125F); \ + } while(0) +/*@}*/ + + +/** + * Average together two rows of a source image to produce a single new + * row in the dest image. It's legal for the two source rows to point + * to the same data. The source width must be equal to either the + * dest width or two times the dest width. + * \param datatype GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_FLOAT, etc. + * \param comps number of components per pixel (1..4) + */ +static void +do_row(enum dtype datatype, uint comps, int srcWidth, + const void *srcRowA, const void *srcRowB, + int dstWidth, void *dstRow) +{ + const uint k0 = (srcWidth == dstWidth) ? 0 : 1; + const uint colStride = (srcWidth == dstWidth) ? 1 : 2; + + assert(comps >= 1); + assert(comps <= 4); + + /* This assertion is no longer valid with non-power-of-2 textures + assert(srcWidth == dstWidth || srcWidth == 2 * dstWidth); + */ + + if (datatype == DTYPE_UBYTE && comps == 4) { + uint i, j, k; + const ubyte(*rowA)[4] = (const ubyte(*)[4]) srcRowA; + const ubyte(*rowB)[4] = (const ubyte(*)[4]) srcRowB; + ubyte(*dst)[4] = (ubyte(*)[4]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; + dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; + dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; + dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4; + } + } + else if (datatype == DTYPE_UBYTE && comps == 3) { + uint i, j, k; + const ubyte(*rowA)[3] = (const ubyte(*)[3]) srcRowA; + const ubyte(*rowB)[3] = (const ubyte(*)[3]) srcRowB; + ubyte(*dst)[3] = (ubyte(*)[3]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; + dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; + dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; + } + } + else if (datatype == DTYPE_UBYTE && comps == 2) { + uint i, j, k; + const ubyte(*rowA)[2] = (const ubyte(*)[2]) srcRowA; + const ubyte(*rowB)[2] = (const ubyte(*)[2]) srcRowB; + ubyte(*dst)[2] = (ubyte(*)[2]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) >> 2; + dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) >> 2; + } + } + else if (datatype == DTYPE_UBYTE && comps == 1) { + uint i, j, k; + const ubyte *rowA = (const ubyte *) srcRowA; + const ubyte *rowB = (const ubyte *) srcRowB; + ubyte *dst = (ubyte *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) >> 2; + } + } + + else if (datatype == DTYPE_USHORT && comps == 4) { + uint i, j, k; + const ushort(*rowA)[4] = (const ushort(*)[4]) srcRowA; + const ushort(*rowB)[4] = (const ushort(*)[4]) srcRowB; + ushort(*dst)[4] = (ushort(*)[4]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; + dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; + dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; + dst[i][3] = (rowA[j][3] + rowA[k][3] + rowB[j][3] + rowB[k][3]) / 4; + } + } + else if (datatype == DTYPE_USHORT && comps == 3) { + uint i, j, k; + const ushort(*rowA)[3] = (const ushort(*)[3]) srcRowA; + const ushort(*rowB)[3] = (const ushort(*)[3]) srcRowB; + ushort(*dst)[3] = (ushort(*)[3]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; + dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; + dst[i][2] = (rowA[j][2] + rowA[k][2] + rowB[j][2] + rowB[k][2]) / 4; + } + } + else if (datatype == DTYPE_USHORT && comps == 2) { + uint i, j, k; + const ushort(*rowA)[2] = (const ushort(*)[2]) srcRowA; + const ushort(*rowB)[2] = (const ushort(*)[2]) srcRowB; + ushort(*dst)[2] = (ushort(*)[2]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + rowB[j][0] + rowB[k][0]) / 4; + dst[i][1] = (rowA[j][1] + rowA[k][1] + rowB[j][1] + rowB[k][1]) / 4; + } + } + else if (datatype == DTYPE_USHORT && comps == 1) { + uint i, j, k; + const ushort *rowA = (const ushort *) srcRowA; + const ushort *rowB = (const ushort *) srcRowB; + ushort *dst = (ushort *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) / 4; + } + } + + else if (datatype == DTYPE_FLOAT && comps == 4) { + uint i, j, k; + const float(*rowA)[4] = (const float(*)[4]) srcRowA; + const float(*rowB)[4] = (const float(*)[4]) srcRowB; + float(*dst)[4] = (float(*)[4]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + + rowB[j][0] + rowB[k][0]) * 0.25F; + dst[i][1] = (rowA[j][1] + rowA[k][1] + + rowB[j][1] + rowB[k][1]) * 0.25F; + dst[i][2] = (rowA[j][2] + rowA[k][2] + + rowB[j][2] + rowB[k][2]) * 0.25F; + dst[i][3] = (rowA[j][3] + rowA[k][3] + + rowB[j][3] + rowB[k][3]) * 0.25F; + } + } + else if (datatype == DTYPE_FLOAT && comps == 3) { + uint i, j, k; + const float(*rowA)[3] = (const float(*)[3]) srcRowA; + const float(*rowB)[3] = (const float(*)[3]) srcRowB; + float(*dst)[3] = (float(*)[3]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + + rowB[j][0] + rowB[k][0]) * 0.25F; + dst[i][1] = (rowA[j][1] + rowA[k][1] + + rowB[j][1] + rowB[k][1]) * 0.25F; + dst[i][2] = (rowA[j][2] + rowA[k][2] + + rowB[j][2] + rowB[k][2]) * 0.25F; + } + } + else if (datatype == DTYPE_FLOAT && comps == 2) { + uint i, j, k; + const float(*rowA)[2] = (const float(*)[2]) srcRowA; + const float(*rowB)[2] = (const float(*)[2]) srcRowB; + float(*dst)[2] = (float(*)[2]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i][0] = (rowA[j][0] + rowA[k][0] + + rowB[j][0] + rowB[k][0]) * 0.25F; + dst[i][1] = (rowA[j][1] + rowA[k][1] + + rowB[j][1] + rowB[k][1]) * 0.25F; + } + } + else if (datatype == DTYPE_FLOAT && comps == 1) { + uint i, j, k; + const float *rowA = (const float *) srcRowA; + const float *rowB = (const float *) srcRowB; + float *dst = (float *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i] = (rowA[j] + rowA[k] + rowB[j] + rowB[k]) * 0.25F; + } + } + + else if (datatype == DTYPE_HALF_FLOAT && comps == 4) { + uint i, j, k, comp; + const half_float(*rowA)[4] = (const half_float(*)[4]) srcRowA; + const half_float(*rowB)[4] = (const half_float(*)[4]) srcRowB; + half_float(*dst)[4] = (half_float(*)[4]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + for (comp = 0; comp < 4; comp++) { + float aj, ak, bj, bk; + aj = util_half_to_float(rowA[j][comp]); + ak = util_half_to_float(rowA[k][comp]); + bj = util_half_to_float(rowB[j][comp]); + bk = util_half_to_float(rowB[k][comp]); + dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + } + else if (datatype == DTYPE_HALF_FLOAT && comps == 3) { + uint i, j, k, comp; + const half_float(*rowA)[3] = (const half_float(*)[3]) srcRowA; + const half_float(*rowB)[3] = (const half_float(*)[3]) srcRowB; + half_float(*dst)[3] = (half_float(*)[3]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + for (comp = 0; comp < 3; comp++) { + float aj, ak, bj, bk; + aj = util_half_to_float(rowA[j][comp]); + ak = util_half_to_float(rowA[k][comp]); + bj = util_half_to_float(rowB[j][comp]); + bk = util_half_to_float(rowB[k][comp]); + dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + } + else if (datatype == DTYPE_HALF_FLOAT && comps == 2) { + uint i, j, k, comp; + const half_float(*rowA)[2] = (const half_float(*)[2]) srcRowA; + const half_float(*rowB)[2] = (const half_float(*)[2]) srcRowB; + half_float(*dst)[2] = (half_float(*)[2]) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + for (comp = 0; comp < 2; comp++) { + float aj, ak, bj, bk; + aj = util_half_to_float(rowA[j][comp]); + ak = util_half_to_float(rowA[k][comp]); + bj = util_half_to_float(rowB[j][comp]); + bk = util_half_to_float(rowB[k][comp]); + dst[i][comp] = util_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + } + else if (datatype == DTYPE_HALF_FLOAT && comps == 1) { + uint i, j, k; + const half_float *rowA = (const half_float *) srcRowA; + const half_float *rowB = (const half_float *) srcRowB; + half_float *dst = (half_float *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + float aj, ak, bj, bk; + aj = util_half_to_float(rowA[j]); + ak = util_half_to_float(rowA[k]); + bj = util_half_to_float(rowB[j]); + bk = util_half_to_float(rowB[k]); + dst[i] = util_float_to_half((aj + ak + bj + bk) * 0.25F); + } + } + + else if (datatype == DTYPE_UINT && comps == 1) { + uint i, j, k; + const uint *rowA = (const uint *) srcRowA; + const uint *rowB = (const uint *) srcRowB; + uint *dst = (uint *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + dst[i] = rowA[j] / 4 + rowA[k] / 4 + rowB[j] / 4 + rowB[k] / 4; + } + } + + else if (datatype == DTYPE_USHORT_5_6_5 && comps == 3) { + uint i, j, k; + const ushort *rowA = (const ushort *) srcRowA; + const ushort *rowB = (const ushort *) srcRowB; + ushort *dst = (ushort *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0x1f; + const int rowAr1 = rowA[k] & 0x1f; + const int rowBr0 = rowB[j] & 0x1f; + const int rowBr1 = rowB[k] & 0x1f; + const int rowAg0 = (rowA[j] >> 5) & 0x3f; + const int rowAg1 = (rowA[k] >> 5) & 0x3f; + const int rowBg0 = (rowB[j] >> 5) & 0x3f; + const int rowBg1 = (rowB[k] >> 5) & 0x3f; + const int rowAb0 = (rowA[j] >> 11) & 0x1f; + const int rowAb1 = (rowA[k] >> 11) & 0x1f; + const int rowBb0 = (rowB[j] >> 11) & 0x1f; + const int rowBb1 = (rowB[k] >> 11) & 0x1f; + const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; + const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; + const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; + dst[i] = (blue << 11) | (green << 5) | red; + } + } + else if (datatype == DTYPE_USHORT_4_4_4_4 && comps == 4) { + uint i, j, k; + const ushort *rowA = (const ushort *) srcRowA; + const ushort *rowB = (const ushort *) srcRowB; + ushort *dst = (ushort *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0xf; + const int rowAr1 = rowA[k] & 0xf; + const int rowBr0 = rowB[j] & 0xf; + const int rowBr1 = rowB[k] & 0xf; + const int rowAg0 = (rowA[j] >> 4) & 0xf; + const int rowAg1 = (rowA[k] >> 4) & 0xf; + const int rowBg0 = (rowB[j] >> 4) & 0xf; + const int rowBg1 = (rowB[k] >> 4) & 0xf; + const int rowAb0 = (rowA[j] >> 8) & 0xf; + const int rowAb1 = (rowA[k] >> 8) & 0xf; + const int rowBb0 = (rowB[j] >> 8) & 0xf; + const int rowBb1 = (rowB[k] >> 8) & 0xf; + const int rowAa0 = (rowA[j] >> 12) & 0xf; + const int rowAa1 = (rowA[k] >> 12) & 0xf; + const int rowBa0 = (rowB[j] >> 12) & 0xf; + const int rowBa1 = (rowB[k] >> 12) & 0xf; + const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; + const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; + const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; + const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2; + dst[i] = (alpha << 12) | (blue << 8) | (green << 4) | red; + } + } + else if (datatype == DTYPE_USHORT_1_5_5_5_REV && comps == 4) { + uint i, j, k; + const ushort *rowA = (const ushort *) srcRowA; + const ushort *rowB = (const ushort *) srcRowB; + ushort *dst = (ushort *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0x1f; + const int rowAr1 = rowA[k] & 0x1f; + const int rowBr0 = rowB[j] & 0x1f; + const int rowBr1 = rowB[k] & 0x1f; + const int rowAg0 = (rowA[j] >> 5) & 0x1f; + const int rowAg1 = (rowA[k] >> 5) & 0x1f; + const int rowBg0 = (rowB[j] >> 5) & 0x1f; + const int rowBg1 = (rowB[k] >> 5) & 0x1f; + const int rowAb0 = (rowA[j] >> 10) & 0x1f; + const int rowAb1 = (rowA[k] >> 10) & 0x1f; + const int rowBb0 = (rowB[j] >> 10) & 0x1f; + const int rowBb1 = (rowB[k] >> 10) & 0x1f; + const int rowAa0 = (rowA[j] >> 15) & 0x1; + const int rowAa1 = (rowA[k] >> 15) & 0x1; + const int rowBa0 = (rowB[j] >> 15) & 0x1; + const int rowBa1 = (rowB[k] >> 15) & 0x1; + const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; + const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; + const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; + const int alpha = (rowAa0 + rowAa1 + rowBa0 + rowBa1) >> 2; + dst[i] = (alpha << 15) | (blue << 10) | (green << 5) | red; + } + } + else if (datatype == DTYPE_UBYTE_3_3_2 && comps == 3) { + uint i, j, k; + const ubyte *rowA = (const ubyte *) srcRowA; + const ubyte *rowB = (const ubyte *) srcRowB; + ubyte *dst = (ubyte *) dstRow; + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0x3; + const int rowAr1 = rowA[k] & 0x3; + const int rowBr0 = rowB[j] & 0x3; + const int rowBr1 = rowB[k] & 0x3; + const int rowAg0 = (rowA[j] >> 2) & 0x7; + const int rowAg1 = (rowA[k] >> 2) & 0x7; + const int rowBg0 = (rowB[j] >> 2) & 0x7; + const int rowBg1 = (rowB[k] >> 2) & 0x7; + const int rowAb0 = (rowA[j] >> 5) & 0x7; + const int rowAb1 = (rowA[k] >> 5) & 0x7; + const int rowBb0 = (rowB[j] >> 5) & 0x7; + const int rowBb1 = (rowB[k] >> 5) & 0x7; + const int red = (rowAr0 + rowAr1 + rowBr0 + rowBr1) >> 2; + const int green = (rowAg0 + rowAg1 + rowBg0 + rowBg1) >> 2; + const int blue = (rowAb0 + rowAb1 + rowBb0 + rowBb1) >> 2; + dst[i] = (blue << 5) | (green << 2) | red; + } + } + else { + debug_printf("bad format in do_row()"); + } +} + + +/** + * Average together four rows of a source image to produce a single new + * row in the dest image. It's legal for the two source rows to point + * to the same data. The source width must be equal to either the + * dest width or two times the dest width. + * + * \param datatype GL pixel type \c GL_UNSIGNED_BYTE, \c GL_UNSIGNED_SHORT, + * \c GL_FLOAT, etc. + * \param comps number of components per pixel (1..4) + * \param srcWidth Width of a row in the source data + * \param srcRowA Pointer to one of the rows of source data + * \param srcRowB Pointer to one of the rows of source data + * \param srcRowC Pointer to one of the rows of source data + * \param srcRowD Pointer to one of the rows of source data + * \param dstWidth Width of a row in the destination data + * \param srcRowA Pointer to the row of destination data + */ +static void +do_row_3D(enum dtype datatype, uint comps, int srcWidth, + const void *srcRowA, const void *srcRowB, + const void *srcRowC, const void *srcRowD, + int dstWidth, void *dstRow) +{ + const uint k0 = (srcWidth == dstWidth) ? 0 : 1; + const uint colStride = (srcWidth == dstWidth) ? 1 : 2; + uint i, j, k; + + assert(comps >= 1); + assert(comps <= 4); + + if ((datatype == DTYPE_UBYTE) && (comps == 4)) { + DECLARE_ROW_POINTERS(ubyte, 4); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + FILTER_3D(1); + FILTER_3D(2); + FILTER_3D(3); + } + } + else if ((datatype == DTYPE_UBYTE) && (comps == 3)) { + DECLARE_ROW_POINTERS(ubyte, 3); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + FILTER_3D(1); + FILTER_3D(2); + } + } + else if ((datatype == DTYPE_UBYTE) && (comps == 2)) { + DECLARE_ROW_POINTERS(ubyte, 2); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + FILTER_3D(1); + } + } + else if ((datatype == DTYPE_UBYTE) && (comps == 1)) { + DECLARE_ROW_POINTERS(ubyte, 1); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + } + } + else if ((datatype == DTYPE_USHORT) && (comps == 4)) { + DECLARE_ROW_POINTERS(ushort, 4); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + FILTER_3D(1); + FILTER_3D(2); + FILTER_3D(3); + } + } + else if ((datatype == DTYPE_USHORT) && (comps == 3)) { + DECLARE_ROW_POINTERS(ushort, 3); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + FILTER_3D(1); + FILTER_3D(2); + } + } + else if ((datatype == DTYPE_USHORT) && (comps == 2)) { + DECLARE_ROW_POINTERS(ushort, 2); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + FILTER_3D(1); + } + } + else if ((datatype == DTYPE_USHORT) && (comps == 1)) { + DECLARE_ROW_POINTERS(ushort, 1); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_3D(0); + } + } + else if ((datatype == DTYPE_FLOAT) && (comps == 4)) { + DECLARE_ROW_POINTERS(float, 4); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_F_3D(0); + FILTER_F_3D(1); + FILTER_F_3D(2); + FILTER_F_3D(3); + } + } + else if ((datatype == DTYPE_FLOAT) && (comps == 3)) { + DECLARE_ROW_POINTERS(float, 3); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_F_3D(0); + FILTER_F_3D(1); + FILTER_F_3D(2); + } + } + else if ((datatype == DTYPE_FLOAT) && (comps == 2)) { + DECLARE_ROW_POINTERS(float, 2); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_F_3D(0); + FILTER_F_3D(1); + } + } + else if ((datatype == DTYPE_FLOAT) && (comps == 1)) { + DECLARE_ROW_POINTERS(float, 1); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_F_3D(0); + } + } + else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 4)) { + DECLARE_ROW_POINTERS(half_float, 4); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_HF_3D(0); + FILTER_HF_3D(1); + FILTER_HF_3D(2); + FILTER_HF_3D(3); + } + } + else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 3)) { + DECLARE_ROW_POINTERS(half_float, 4); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_HF_3D(0); + FILTER_HF_3D(1); + FILTER_HF_3D(2); + } + } + else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 2)) { + DECLARE_ROW_POINTERS(half_float, 4); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_HF_3D(0); + FILTER_HF_3D(1); + } + } + else if ((datatype == DTYPE_HALF_FLOAT) && (comps == 1)) { + DECLARE_ROW_POINTERS(half_float, 4); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + FILTER_HF_3D(0); + } + } + else if ((datatype == DTYPE_UINT) && (comps == 1)) { + const uint *rowA = (const uint *) srcRowA; + const uint *rowB = (const uint *) srcRowB; + const uint *rowC = (const uint *) srcRowC; + const uint *rowD = (const uint *) srcRowD; + float *dst = (float *) dstRow; + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const uint64_t tmp = (((uint64_t) rowA[j] + (uint64_t) rowA[k]) + + ((uint64_t) rowB[j] + (uint64_t) rowB[k]) + + ((uint64_t) rowC[j] + (uint64_t) rowC[k]) + + ((uint64_t) rowD[j] + (uint64_t) rowD[k])); + dst[i] = (float)((double) tmp * 0.125); + } + } + else if ((datatype == DTYPE_USHORT_5_6_5) && (comps == 3)) { + DECLARE_ROW_POINTERS0(ushort); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0x1f; + const int rowAr1 = rowA[k] & 0x1f; + const int rowBr0 = rowB[j] & 0x1f; + const int rowBr1 = rowB[k] & 0x1f; + const int rowCr0 = rowC[j] & 0x1f; + const int rowCr1 = rowC[k] & 0x1f; + const int rowDr0 = rowD[j] & 0x1f; + const int rowDr1 = rowD[k] & 0x1f; + const int rowAg0 = (rowA[j] >> 5) & 0x3f; + const int rowAg1 = (rowA[k] >> 5) & 0x3f; + const int rowBg0 = (rowB[j] >> 5) & 0x3f; + const int rowBg1 = (rowB[k] >> 5) & 0x3f; + const int rowCg0 = (rowC[j] >> 5) & 0x3f; + const int rowCg1 = (rowC[k] >> 5) & 0x3f; + const int rowDg0 = (rowD[j] >> 5) & 0x3f; + const int rowDg1 = (rowD[k] >> 5) & 0x3f; + const int rowAb0 = (rowA[j] >> 11) & 0x1f; + const int rowAb1 = (rowA[k] >> 11) & 0x1f; + const int rowBb0 = (rowB[j] >> 11) & 0x1f; + const int rowBb1 = (rowB[k] >> 11) & 0x1f; + const int rowCb0 = (rowC[j] >> 11) & 0x1f; + const int rowCb1 = (rowC[k] >> 11) & 0x1f; + const int rowDb0 = (rowD[j] >> 11) & 0x1f; + const int rowDb1 = (rowD[k] >> 11) & 0x1f; + const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1, + rowCr0, rowCr1, rowDr0, rowDr1); + const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1, + rowCg0, rowCg1, rowDg0, rowDg1); + const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1, + rowCb0, rowCb1, rowDb0, rowDb1); + dst[i] = (b << 11) | (g << 5) | r; + } + } + else if ((datatype == DTYPE_USHORT_4_4_4_4) && (comps == 4)) { + DECLARE_ROW_POINTERS0(ushort); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0xf; + const int rowAr1 = rowA[k] & 0xf; + const int rowBr0 = rowB[j] & 0xf; + const int rowBr1 = rowB[k] & 0xf; + const int rowCr0 = rowC[j] & 0xf; + const int rowCr1 = rowC[k] & 0xf; + const int rowDr0 = rowD[j] & 0xf; + const int rowDr1 = rowD[k] & 0xf; + const int rowAg0 = (rowA[j] >> 4) & 0xf; + const int rowAg1 = (rowA[k] >> 4) & 0xf; + const int rowBg0 = (rowB[j] >> 4) & 0xf; + const int rowBg1 = (rowB[k] >> 4) & 0xf; + const int rowCg0 = (rowC[j] >> 4) & 0xf; + const int rowCg1 = (rowC[k] >> 4) & 0xf; + const int rowDg0 = (rowD[j] >> 4) & 0xf; + const int rowDg1 = (rowD[k] >> 4) & 0xf; + const int rowAb0 = (rowA[j] >> 8) & 0xf; + const int rowAb1 = (rowA[k] >> 8) & 0xf; + const int rowBb0 = (rowB[j] >> 8) & 0xf; + const int rowBb1 = (rowB[k] >> 8) & 0xf; + const int rowCb0 = (rowC[j] >> 8) & 0xf; + const int rowCb1 = (rowC[k] >> 8) & 0xf; + const int rowDb0 = (rowD[j] >> 8) & 0xf; + const int rowDb1 = (rowD[k] >> 8) & 0xf; + const int rowAa0 = (rowA[j] >> 12) & 0xf; + const int rowAa1 = (rowA[k] >> 12) & 0xf; + const int rowBa0 = (rowB[j] >> 12) & 0xf; + const int rowBa1 = (rowB[k] >> 12) & 0xf; + const int rowCa0 = (rowC[j] >> 12) & 0xf; + const int rowCa1 = (rowC[k] >> 12) & 0xf; + const int rowDa0 = (rowD[j] >> 12) & 0xf; + const int rowDa1 = (rowD[k] >> 12) & 0xf; + const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1, + rowCr0, rowCr1, rowDr0, rowDr1); + const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1, + rowCg0, rowCg1, rowDg0, rowDg1); + const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1, + rowCb0, rowCb1, rowDb0, rowDb1); + const int a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1, + rowCa0, rowCa1, rowDa0, rowDa1); + + dst[i] = (a << 12) | (b << 8) | (g << 4) | r; + } + } + else if ((datatype == DTYPE_USHORT_1_5_5_5_REV) && (comps == 4)) { + DECLARE_ROW_POINTERS0(ushort); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0x1f; + const int rowAr1 = rowA[k] & 0x1f; + const int rowBr0 = rowB[j] & 0x1f; + const int rowBr1 = rowB[k] & 0x1f; + const int rowCr0 = rowC[j] & 0x1f; + const int rowCr1 = rowC[k] & 0x1f; + const int rowDr0 = rowD[j] & 0x1f; + const int rowDr1 = rowD[k] & 0x1f; + const int rowAg0 = (rowA[j] >> 5) & 0x1f; + const int rowAg1 = (rowA[k] >> 5) & 0x1f; + const int rowBg0 = (rowB[j] >> 5) & 0x1f; + const int rowBg1 = (rowB[k] >> 5) & 0x1f; + const int rowCg0 = (rowC[j] >> 5) & 0x1f; + const int rowCg1 = (rowC[k] >> 5) & 0x1f; + const int rowDg0 = (rowD[j] >> 5) & 0x1f; + const int rowDg1 = (rowD[k] >> 5) & 0x1f; + const int rowAb0 = (rowA[j] >> 10) & 0x1f; + const int rowAb1 = (rowA[k] >> 10) & 0x1f; + const int rowBb0 = (rowB[j] >> 10) & 0x1f; + const int rowBb1 = (rowB[k] >> 10) & 0x1f; + const int rowCb0 = (rowC[j] >> 10) & 0x1f; + const int rowCb1 = (rowC[k] >> 10) & 0x1f; + const int rowDb0 = (rowD[j] >> 10) & 0x1f; + const int rowDb1 = (rowD[k] >> 10) & 0x1f; + const int rowAa0 = (rowA[j] >> 15) & 0x1; + const int rowAa1 = (rowA[k] >> 15) & 0x1; + const int rowBa0 = (rowB[j] >> 15) & 0x1; + const int rowBa1 = (rowB[k] >> 15) & 0x1; + const int rowCa0 = (rowC[j] >> 15) & 0x1; + const int rowCa1 = (rowC[k] >> 15) & 0x1; + const int rowDa0 = (rowD[j] >> 15) & 0x1; + const int rowDa1 = (rowD[k] >> 15) & 0x1; + const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1, + rowCr0, rowCr1, rowDr0, rowDr1); + const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1, + rowCg0, rowCg1, rowDg0, rowDg1); + const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1, + rowCb0, rowCb1, rowDb0, rowDb1); + const int a = FILTER_SUM_3D(rowAa0, rowAa1, rowBa0, rowBa1, + rowCa0, rowCa1, rowDa0, rowDa1); + + dst[i] = (a << 15) | (b << 10) | (g << 5) | r; + } + } + else if ((datatype == DTYPE_UBYTE_3_3_2) && (comps == 3)) { + DECLARE_ROW_POINTERS0(ushort); + + for (i = j = 0, k = k0; i < (uint) dstWidth; + i++, j += colStride, k += colStride) { + const int rowAr0 = rowA[j] & 0x3; + const int rowAr1 = rowA[k] & 0x3; + const int rowBr0 = rowB[j] & 0x3; + const int rowBr1 = rowB[k] & 0x3; + const int rowCr0 = rowC[j] & 0x3; + const int rowCr1 = rowC[k] & 0x3; + const int rowDr0 = rowD[j] & 0x3; + const int rowDr1 = rowD[k] & 0x3; + const int rowAg0 = (rowA[j] >> 2) & 0x7; + const int rowAg1 = (rowA[k] >> 2) & 0x7; + const int rowBg0 = (rowB[j] >> 2) & 0x7; + const int rowBg1 = (rowB[k] >> 2) & 0x7; + const int rowCg0 = (rowC[j] >> 2) & 0x7; + const int rowCg1 = (rowC[k] >> 2) & 0x7; + const int rowDg0 = (rowD[j] >> 2) & 0x7; + const int rowDg1 = (rowD[k] >> 2) & 0x7; + const int rowAb0 = (rowA[j] >> 5) & 0x7; + const int rowAb1 = (rowA[k] >> 5) & 0x7; + const int rowBb0 = (rowB[j] >> 5) & 0x7; + const int rowBb1 = (rowB[k] >> 5) & 0x7; + const int rowCb0 = (rowC[j] >> 5) & 0x7; + const int rowCb1 = (rowC[k] >> 5) & 0x7; + const int rowDb0 = (rowD[j] >> 5) & 0x7; + const int rowDb1 = (rowD[k] >> 5) & 0x7; + const int r = FILTER_SUM_3D(rowAr0, rowAr1, rowBr0, rowBr1, + rowCr0, rowCr1, rowDr0, rowDr1); + const int g = FILTER_SUM_3D(rowAg0, rowAg1, rowBg0, rowBg1, + rowCg0, rowCg1, rowDg0, rowDg1); + const int b = FILTER_SUM_3D(rowAb0, rowAb1, rowBb0, rowBb1, + rowCb0, rowCb1, rowDb0, rowDb1); + dst[i] = (b << 5) | (g << 2) | r; + } + } + else { + debug_printf("bad format in do_row_3D()"); + } +} + + + +static void +format_to_type_comps(enum pipe_format pformat, + enum dtype *datatype, uint *comps) +{ + /* XXX I think this could be implemented in terms of the pf_*() functions */ + switch (pformat) { + case PIPE_FORMAT_B8G8R8A8_UNORM: + case PIPE_FORMAT_B8G8R8X8_UNORM: + case PIPE_FORMAT_A8R8G8B8_UNORM: + case PIPE_FORMAT_X8R8G8B8_UNORM: + case PIPE_FORMAT_A8B8G8R8_SRGB: + case PIPE_FORMAT_X8B8G8R8_SRGB: + case PIPE_FORMAT_B8G8R8A8_SRGB: + case PIPE_FORMAT_B8G8R8X8_SRGB: + case PIPE_FORMAT_A8R8G8B8_SRGB: + case PIPE_FORMAT_X8R8G8B8_SRGB: + case PIPE_FORMAT_R8G8B8_SRGB: + *datatype = DTYPE_UBYTE; + *comps = 4; + return; + case PIPE_FORMAT_B5G5R5X1_UNORM: + case PIPE_FORMAT_B5G5R5A1_UNORM: + *datatype = DTYPE_USHORT_1_5_5_5_REV; + *comps = 4; + return; + case PIPE_FORMAT_B4G4R4A4_UNORM: + *datatype = DTYPE_USHORT_4_4_4_4; + *comps = 4; + return; + case PIPE_FORMAT_B5G6R5_UNORM: + *datatype = DTYPE_USHORT_5_6_5; + *comps = 3; + return; + case PIPE_FORMAT_L8_UNORM: + case PIPE_FORMAT_L8_SRGB: + case PIPE_FORMAT_A8_UNORM: + case PIPE_FORMAT_I8_UNORM: + *datatype = DTYPE_UBYTE; + *comps = 1; + return; + case PIPE_FORMAT_L8A8_UNORM: + case PIPE_FORMAT_L8A8_SRGB: + *datatype = DTYPE_UBYTE; + *comps = 2; + return; + default: + assert(0); + *datatype = DTYPE_UBYTE; + *comps = 0; + break; + } +} + + +static void +reduce_1d(enum pipe_format pformat, + int srcWidth, const ubyte *srcPtr, + int dstWidth, ubyte *dstPtr) +{ + enum dtype datatype; + uint comps; + + format_to_type_comps(pformat, &datatype, &comps); + + /* we just duplicate the input row, kind of hack, saves code */ + do_row(datatype, comps, + srcWidth, srcPtr, srcPtr, + dstWidth, dstPtr); +} + + +/** + * Strides are in bytes. If zero, it'll be computed as width * bpp. + */ +static void +reduce_2d(enum pipe_format pformat, + int srcWidth, int srcHeight, + int srcRowStride, const ubyte *srcPtr, + int dstWidth, int dstHeight, + int dstRowStride, ubyte *dstPtr) +{ + enum dtype datatype; + uint comps; + const int bpt = util_format_get_blocksize(pformat); + const ubyte *srcA, *srcB; + ubyte *dst; + int row; + + format_to_type_comps(pformat, &datatype, &comps); + + if (!srcRowStride) + srcRowStride = bpt * srcWidth; + + if (!dstRowStride) + dstRowStride = bpt * dstWidth; + + /* Compute src and dst pointers */ + srcA = srcPtr; + if (srcHeight > 1) + srcB = srcA + srcRowStride; + else + srcB = srcA; + dst = dstPtr; + + for (row = 0; row < dstHeight; row++) { + do_row(datatype, comps, + srcWidth, srcA, srcB, + dstWidth, dst); + srcA += 2 * srcRowStride; + srcB += 2 * srcRowStride; + dst += dstRowStride; + } +} + + +static void +reduce_3d(enum pipe_format pformat, + int srcWidth, int srcHeight, int srcDepth, + int srcRowStride, int srcImageStride, const ubyte *srcPtr, + int dstWidth, int dstHeight, int dstDepth, + int dstRowStride, int dstImageStride, ubyte *dstPtr) +{ + const int bpt = util_format_get_blocksize(pformat); + int img, row; + int srcImageOffset, srcRowOffset; + enum dtype datatype; + uint comps; + + format_to_type_comps(pformat, &datatype, &comps); + + /* XXX I think we should rather assert those strides */ + if (!srcImageStride) + srcImageStride = srcWidth * srcHeight * bpt; + if (!dstImageStride) + dstImageStride = dstWidth * dstHeight * bpt; + + if (!srcRowStride) + srcRowStride = srcWidth * bpt; + if (!dstRowStride) + dstRowStride = dstWidth * bpt; + + /* Offset between adjacent src images to be averaged together */ + srcImageOffset = (srcDepth == dstDepth) ? 0 : srcImageStride; + + /* Offset between adjacent src rows to be averaged together */ + srcRowOffset = (srcHeight == dstHeight) ? 0 : srcRowStride; + + /* + * Need to average together up to 8 src pixels for each dest pixel. + * Break that down into 3 operations: + * 1. take two rows from source image and average them together. + * 2. take two rows from next source image and average them together. + * 3. take the two averaged rows and average them for the final dst row. + */ + + /* + printf("mip3d %d x %d x %d -> %d x %d x %d\n", + srcWidth, srcHeight, srcDepth, dstWidth, dstHeight, dstDepth); + */ + + for (img = 0; img < dstDepth; img++) { + /* first source image pointer */ + const ubyte *imgSrcA = srcPtr + + img * (srcImageStride + srcImageOffset); + /* second source image pointer */ + const ubyte *imgSrcB = imgSrcA + srcImageOffset; + /* address of the dest image */ + ubyte *imgDst = dstPtr + img * dstImageStride; + + /* setup the four source row pointers and the dest row pointer */ + const ubyte *srcImgARowA = imgSrcA; + const ubyte *srcImgARowB = imgSrcA + srcRowOffset; + const ubyte *srcImgBRowA = imgSrcB; + const ubyte *srcImgBRowB = imgSrcB + srcRowOffset; + ubyte *dstImgRow = imgDst; + + for (row = 0; row < dstHeight; row++) { + do_row_3D(datatype, comps, srcWidth, + srcImgARowA, srcImgARowB, + srcImgBRowA, srcImgBRowB, + dstWidth, dstImgRow); + + /* advance to next rows */ + srcImgARowA += srcRowStride + srcRowOffset; + srcImgARowB += srcRowStride + srcRowOffset; + srcImgBRowA += srcRowStride + srcRowOffset; + srcImgBRowB += srcRowStride + srcRowOffset; + dstImgRow += dstImageStride; + } + } +} + + + + +static void +make_1d_mipmap(struct gen_mipmap_state *ctx, + struct pipe_resource *pt, + uint layer, uint baseLevel, uint lastLevel) +{ + struct pipe_context *pipe = ctx->pipe; + uint dstLevel; + + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + struct pipe_transfer *srcTrans, *dstTrans; + void *srcMap, *dstMap; + + srcTrans = pipe_get_transfer(pipe, pt, srcLevel, layer, + PIPE_TRANSFER_READ, 0, 0, + u_minify(pt->width0, srcLevel), + u_minify(pt->height0, srcLevel)); + dstTrans = pipe_get_transfer(pipe, pt, dstLevel, layer, + PIPE_TRANSFER_WRITE, 0, 0, + u_minify(pt->width0, dstLevel), + u_minify(pt->height0, dstLevel)); + + srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans); + dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans); + + reduce_1d(pt->format, + srcTrans->box.width, srcMap, + dstTrans->box.width, dstMap); + + pipe->transfer_unmap(pipe, srcTrans); + pipe->transfer_unmap(pipe, dstTrans); + + pipe->transfer_destroy(pipe, srcTrans); + pipe->transfer_destroy(pipe, dstTrans); + } +} + + +static void +make_2d_mipmap(struct gen_mipmap_state *ctx, + struct pipe_resource *pt, + uint layer, uint baseLevel, uint lastLevel) +{ + struct pipe_context *pipe = ctx->pipe; + uint dstLevel; + + assert(util_format_get_blockwidth(pt->format) == 1); + assert(util_format_get_blockheight(pt->format) == 1); + + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + struct pipe_transfer *srcTrans, *dstTrans; + ubyte *srcMap, *dstMap; + + srcTrans = pipe_get_transfer(pipe, pt, srcLevel, layer, + PIPE_TRANSFER_READ, 0, 0, + u_minify(pt->width0, srcLevel), + u_minify(pt->height0, srcLevel)); + dstTrans = pipe_get_transfer(pipe, pt, dstLevel, layer, + PIPE_TRANSFER_WRITE, 0, 0, + u_minify(pt->width0, dstLevel), + u_minify(pt->height0, dstLevel)); + + srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans); + dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans); + + reduce_2d(pt->format, + srcTrans->box.width, srcTrans->box.height, + srcTrans->stride, srcMap, + dstTrans->box.width, dstTrans->box.height, + dstTrans->stride, dstMap); + + pipe->transfer_unmap(pipe, srcTrans); + pipe->transfer_unmap(pipe, dstTrans); + + pipe->transfer_destroy(pipe, srcTrans); + pipe->transfer_destroy(pipe, dstTrans); + } +} + + +/* XXX looks a bit more like it could work now but need to test */ +static void +make_3d_mipmap(struct gen_mipmap_state *ctx, + struct pipe_resource *pt, + uint face, uint baseLevel, uint lastLevel) +{ + struct pipe_context *pipe = ctx->pipe; + uint dstLevel; + struct pipe_box src_box, dst_box; + + assert(util_format_get_blockwidth(pt->format) == 1); + assert(util_format_get_blockheight(pt->format) == 1); + + src_box.x = src_box.y = src_box.z = 0; + dst_box.x = dst_box.y = dst_box.z = 0; + + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + struct pipe_transfer *srcTrans, *dstTrans; + ubyte *srcMap, *dstMap; + struct pipe_box src_box, dst_box; + src_box.width = u_minify(pt->width0, srcLevel); + src_box.height = u_minify(pt->height0, srcLevel); + src_box.depth = u_minify(pt->depth0, srcLevel); + dst_box.width = u_minify(pt->width0, dstLevel); + dst_box.height = u_minify(pt->height0, dstLevel); + dst_box.depth = u_minify(pt->depth0, dstLevel); + + srcTrans = pipe->get_transfer(pipe, pt, srcLevel, + PIPE_TRANSFER_READ, + &src_box); + dstTrans = pipe->get_transfer(pipe, pt, dstLevel, + PIPE_TRANSFER_WRITE, + &dst_box); + + srcMap = (ubyte *) pipe->transfer_map(pipe, srcTrans); + dstMap = (ubyte *) pipe->transfer_map(pipe, dstTrans); + + reduce_3d(pt->format, + srcTrans->box.width, srcTrans->box.height, srcTrans->box.depth, + srcTrans->stride, srcTrans->layer_stride, srcMap, + dstTrans->box.width, dstTrans->box.height, dstTrans->box.depth, + dstTrans->stride, dstTrans->layer_stride, dstMap); + + pipe->transfer_unmap(pipe, srcTrans); + pipe->transfer_unmap(pipe, dstTrans); + + pipe->transfer_destroy(pipe, srcTrans); + pipe->transfer_destroy(pipe, dstTrans); + } +} + + +static void +fallback_gen_mipmap(struct gen_mipmap_state *ctx, + struct pipe_resource *pt, + uint layer, uint baseLevel, uint lastLevel) +{ + switch (pt->target) { + case PIPE_TEXTURE_1D: + make_1d_mipmap(ctx, pt, layer, baseLevel, lastLevel); + break; + case PIPE_TEXTURE_2D: + case PIPE_TEXTURE_RECT: + case PIPE_TEXTURE_CUBE: + make_2d_mipmap(ctx, pt, layer, baseLevel, lastLevel); + break; + case PIPE_TEXTURE_3D: + make_3d_mipmap(ctx, pt, layer, baseLevel, lastLevel); + break; + default: + assert(0); + } +} + + +/** + * Create a mipmap generation context. + * The idea is to create one of these and re-use it each time we need to + * generate a mipmap. + */ +struct gen_mipmap_state * +util_create_gen_mipmap(struct pipe_context *pipe, + struct cso_context *cso) +{ + struct gen_mipmap_state *ctx; + uint i; + + ctx = CALLOC_STRUCT(gen_mipmap_state); + if (!ctx) + return NULL; + + ctx->pipe = pipe; + ctx->cso = cso; + + /* disabled blending/masking */ + memset(&ctx->blend, 0, sizeof(ctx->blend)); + ctx->blend.rt[0].colormask = PIPE_MASK_RGBA; + + /* no-op depth/stencil/alpha */ + memset(&ctx->depthstencil, 0, sizeof(ctx->depthstencil)); + + /* rasterizer */ + memset(&ctx->rasterizer, 0, sizeof(ctx->rasterizer)); + ctx->rasterizer.cull_face = PIPE_FACE_NONE; + ctx->rasterizer.gl_rasterization_rules = 1; + + /* sampler state */ + memset(&ctx->sampler, 0, sizeof(ctx->sampler)); + ctx->sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + ctx->sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + ctx->sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; + ctx->sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NEAREST; + ctx->sampler.normalized_coords = 1; + + /* vertex elements state */ + memset(&ctx->velem[0], 0, sizeof(ctx->velem[0]) * 2); + for (i = 0; i < 2; i++) { + ctx->velem[i].src_offset = i * 4 * sizeof(float); + ctx->velem[i].instance_divisor = 0; + ctx->velem[i].vertex_buffer_index = 0; + ctx->velem[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } + + /* vertex data that doesn't change */ + for (i = 0; i < 4; i++) { + ctx->vertices[i][0][2] = 0.0f; /* z */ + ctx->vertices[i][0][3] = 1.0f; /* w */ + ctx->vertices[i][1][3] = 1.0f; /* q */ + } + + /* Note: the actual vertex buffer is allocated as needed below */ + + return ctx; +} + + +/** + * Helper function to set the fragment shaders. + */ +static INLINE void +set_fragment_shader(struct gen_mipmap_state *ctx, uint type) +{ + if (!ctx->fs[type]) + ctx->fs[type] = + util_make_fragment_tex_shader(ctx->pipe, type, + TGSI_INTERPOLATE_LINEAR); + + cso_set_fragment_shader_handle(ctx->cso, ctx->fs[type]); +} + + +/** + * Helper function to set the vertex shader. + */ +static INLINE void +set_vertex_shader(struct gen_mipmap_state *ctx) +{ + /* vertex shader - still required to provide the linkage between + * fragment shader input semantics and vertex_element/buffers. + */ + if (!ctx->vs) + { + const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_GENERIC }; + const uint semantic_indexes[] = { 0, 0 }; + ctx->vs = util_make_vertex_passthrough_shader(ctx->pipe, 2, + semantic_names, + semantic_indexes); + } + + cso_set_vertex_shader_handle(ctx->cso, ctx->vs); +} + + +/** + * Get next "slot" of vertex space in the vertex buffer. + * We're allocating one large vertex buffer and using it piece by piece. + */ +static unsigned +get_next_slot(struct gen_mipmap_state *ctx) +{ + const unsigned max_slots = 4096 / sizeof ctx->vertices; + + if (ctx->vbuf_slot >= max_slots) + util_gen_mipmap_flush( ctx ); + + if (!ctx->vbuf) { + ctx->vbuf = pipe_buffer_create(ctx->pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, + max_slots * sizeof ctx->vertices); + } + + return ctx->vbuf_slot++ * sizeof ctx->vertices; +} + + +static unsigned +set_vertex_data(struct gen_mipmap_state *ctx, + enum pipe_texture_target tex_target, + uint layer, float r) +{ + unsigned offset; + + /* vert[0].position */ + ctx->vertices[0][0][0] = -1.0f; /*x*/ + ctx->vertices[0][0][1] = -1.0f; /*y*/ + + /* vert[1].position */ + ctx->vertices[1][0][0] = 1.0f; + ctx->vertices[1][0][1] = -1.0f; + + /* vert[2].position */ + ctx->vertices[2][0][0] = 1.0f; + ctx->vertices[2][0][1] = 1.0f; + + /* vert[3].position */ + ctx->vertices[3][0][0] = -1.0f; + ctx->vertices[3][0][1] = 1.0f; + + /* Setup vertex texcoords. This is a little tricky for cube maps. */ + if (tex_target == PIPE_TEXTURE_CUBE) { + static const float st[4][2] = { + {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f} + }; + + util_map_texcoords2d_onto_cubemap(layer, &st[0][0], 2, + &ctx->vertices[0][1][0], 8); + } + else if (tex_target == PIPE_TEXTURE_1D_ARRAY) { + /* 1D texture array */ + ctx->vertices[0][1][0] = 0.0f; /*s*/ + ctx->vertices[0][1][1] = r; /*t*/ + ctx->vertices[0][1][2] = 0.0f; /*r*/ + + ctx->vertices[1][1][0] = 1.0f; + ctx->vertices[1][1][1] = r; + ctx->vertices[1][1][2] = 0.0f; + + ctx->vertices[2][1][0] = 1.0f; + ctx->vertices[2][1][1] = r; + ctx->vertices[2][1][2] = 0.0f; + + ctx->vertices[3][1][0] = 0.0f; + ctx->vertices[3][1][1] = r; + ctx->vertices[3][1][2] = 0.0f; + } else { + /* 1D/2D/3D/2D array */ + ctx->vertices[0][1][0] = 0.0f; /*s*/ + ctx->vertices[0][1][1] = 0.0f; /*t*/ + ctx->vertices[0][1][2] = r; /*r*/ + + ctx->vertices[1][1][0] = 1.0f; + ctx->vertices[1][1][1] = 0.0f; + ctx->vertices[1][1][2] = r; + + ctx->vertices[2][1][0] = 1.0f; + ctx->vertices[2][1][1] = 1.0f; + ctx->vertices[2][1][2] = r; + + ctx->vertices[3][1][0] = 0.0f; + ctx->vertices[3][1][1] = 1.0f; + ctx->vertices[3][1][2] = r; + } + + offset = get_next_slot( ctx ); + + pipe_buffer_write_nooverlap(ctx->pipe, ctx->vbuf, + offset, sizeof(ctx->vertices), ctx->vertices); + + return offset; +} + + + +/** + * Destroy a mipmap generation context + */ +void +util_destroy_gen_mipmap(struct gen_mipmap_state *ctx) +{ + struct pipe_context *pipe = ctx->pipe; + unsigned i; + + for (i = 0; i < Elements(ctx->fs); i++) + if (ctx->fs[i]) + pipe->delete_fs_state(pipe, ctx->fs[i]); + + if (ctx->vs) + pipe->delete_vs_state(pipe, ctx->vs); + + pipe_resource_reference(&ctx->vbuf, NULL); + + FREE(ctx); +} + + + +/* Release vertex buffer at end of frame to avoid synchronous + * rendering. + */ +void util_gen_mipmap_flush( struct gen_mipmap_state *ctx ) +{ + pipe_resource_reference(&ctx->vbuf, NULL); + ctx->vbuf_slot = 0; +} + + +/** + * Generate mipmap images. It's assumed all needed texture memory is + * already allocated. + * + * \param psv the sampler view to the texture to generate mipmap levels for + * \param face which cube face to generate mipmaps for (0 for non-cube maps) + * \param baseLevel the first mipmap level to use as a src + * \param lastLevel the last mipmap level to generate + * \param filter the minification filter used to generate mipmap levels with + * \param filter one of PIPE_TEX_FILTER_LINEAR, PIPE_TEX_FILTER_NEAREST + */ +void +util_gen_mipmap(struct gen_mipmap_state *ctx, + struct pipe_sampler_view *psv, + uint face, uint baseLevel, uint lastLevel, uint filter) +{ + struct pipe_context *pipe = ctx->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_framebuffer_state fb; + struct pipe_resource *pt = psv->texture; + uint dstLevel; + uint offset; + uint type; + + /* The texture object should have room for the levels which we're + * about to generate. + */ + assert(lastLevel <= pt->last_level); + + /* If this fails, why are we here? */ + assert(lastLevel > baseLevel); + + assert(filter == PIPE_TEX_FILTER_LINEAR || + filter == PIPE_TEX_FILTER_NEAREST); + + switch (pt->target) { + case PIPE_TEXTURE_1D: + type = TGSI_TEXTURE_1D; + break; + case PIPE_TEXTURE_2D: + type = TGSI_TEXTURE_2D; + break; + case PIPE_TEXTURE_3D: + type = TGSI_TEXTURE_3D; + break; + case PIPE_TEXTURE_CUBE: + type = TGSI_TEXTURE_CUBE; + break; + case PIPE_TEXTURE_1D_ARRAY: + type = TGSI_TEXTURE_1D_ARRAY; + break; + case PIPE_TEXTURE_2D_ARRAY: + type = TGSI_TEXTURE_2D_ARRAY; + break; + default: + assert(0); + type = TGSI_TEXTURE_2D; + } + + /* check if we can render in the texture's format */ + if (!screen->is_format_supported(screen, psv->format, pt->target, + pt->nr_samples, PIPE_BIND_RENDER_TARGET)) { + fallback_gen_mipmap(ctx, pt, face, baseLevel, lastLevel); + return; + } + + /* save state (restored below) */ + cso_save_blend(ctx->cso); + cso_save_depth_stencil_alpha(ctx->cso); + cso_save_rasterizer(ctx->cso); + cso_save_samplers(ctx->cso); + cso_save_fragment_sampler_views(ctx->cso); + cso_save_framebuffer(ctx->cso); + cso_save_fragment_shader(ctx->cso); + cso_save_vertex_shader(ctx->cso); + cso_save_geometry_shader(ctx->cso); + cso_save_viewport(ctx->cso); + cso_save_clip(ctx->cso); + cso_save_vertex_elements(ctx->cso); + + /* bind our state */ + cso_set_blend(ctx->cso, &ctx->blend); + cso_set_depth_stencil_alpha(ctx->cso, &ctx->depthstencil); + cso_set_rasterizer(ctx->cso, &ctx->rasterizer); + cso_set_clip(ctx->cso, &ctx->clip); + cso_set_vertex_elements(ctx->cso, 2, ctx->velem); + + set_fragment_shader(ctx, type); + set_vertex_shader(ctx); + cso_set_geometry_shader_handle(ctx->cso, NULL); + + /* init framebuffer state */ + memset(&fb, 0, sizeof(fb)); + fb.nr_cbufs = 1; + + /* set min/mag to same filter for faster sw speed */ + ctx->sampler.mag_img_filter = filter; + ctx->sampler.min_img_filter = filter; + + /* + * XXX for small mipmap levels, it may be faster to use the software + * fallback path... + */ + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + struct pipe_viewport_state vp; + unsigned nr_layers, layer, i; + float rcoord = 0.0f; + + if (pt->target == PIPE_TEXTURE_3D) + nr_layers = u_minify(pt->depth0, dstLevel); + else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY) + nr_layers = pt->array_size; + else + nr_layers = 1; + + for (i = 0; i < nr_layers; i++) { + struct pipe_surface *surf, surf_templ; + if (pt->target == PIPE_TEXTURE_3D) { + /* in theory with geom shaders and driver with full layer support + could do that in one go. */ + layer = i; + /* XXX hmm really? */ + rcoord = (float)layer / (float)nr_layers + 1.0f / (float)(nr_layers * 2); + } else if (pt->target == PIPE_TEXTURE_2D_ARRAY || pt->target == PIPE_TEXTURE_1D_ARRAY) { + layer = i; + rcoord = (float)layer; + } else + layer = face; + + memset(&surf_templ, 0, sizeof(surf_templ)); + u_surface_default_template(&surf_templ, pt, PIPE_BIND_RENDER_TARGET); + surf_templ.u.tex.level = dstLevel; + surf_templ.u.tex.first_layer = layer; + surf_templ.u.tex.last_layer = layer; + surf = pipe->create_surface(pipe, pt, &surf_templ); + + /* + * Setup framebuffer / dest surface + */ + fb.cbufs[0] = surf; + fb.width = u_minify(pt->width0, dstLevel); + fb.height = u_minify(pt->height0, dstLevel); + cso_set_framebuffer(ctx->cso, &fb); + + /* viewport */ + vp.scale[0] = 0.5f * fb.width; + vp.scale[1] = 0.5f * fb.height; + vp.scale[2] = 1.0f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * fb.width; + vp.translate[1] = 0.5f * fb.height; + vp.translate[2] = 0.0f; + vp.translate[3] = 0.0f; + cso_set_viewport(ctx->cso, &vp); + + /* + * Setup sampler state + * Note: we should only have to set the min/max LOD clamps to ensure + * we grab texels from the right mipmap level. But some hardware + * has trouble with min clamping so we also set the lod_bias to + * try to work around that. + */ + ctx->sampler.min_lod = ctx->sampler.max_lod = (float) srcLevel; + ctx->sampler.lod_bias = (float) srcLevel; + cso_single_sampler(ctx->cso, 0, &ctx->sampler); + cso_single_sampler_done(ctx->cso); + + cso_set_fragment_sampler_views(ctx->cso, 1, &psv); + + /* quad coords in clip coords */ + offset = set_vertex_data(ctx, + pt->target, + face, + rcoord); + + util_draw_vertex_buffer(ctx->pipe, + ctx->cso, + ctx->vbuf, + offset, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + /* need to signal that the texture has changed _after_ rendering to it */ + pipe_surface_reference( &surf, NULL ); + } + } + + /* restore state we changed */ + cso_restore_blend(ctx->cso); + cso_restore_depth_stencil_alpha(ctx->cso); + cso_restore_rasterizer(ctx->cso); + cso_restore_samplers(ctx->cso); + cso_restore_fragment_sampler_views(ctx->cso); + cso_restore_framebuffer(ctx->cso); + cso_restore_fragment_shader(ctx->cso); + cso_restore_vertex_shader(ctx->cso); + cso_restore_geometry_shader(ctx->cso); + cso_restore_viewport(ctx->cso); + cso_restore_clip(ctx->cso); + cso_restore_vertex_elements(ctx->cso); +} diff --git a/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c b/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c index 6c2d1ed64..ca4f795f0 100644 --- a/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c +++ b/mesalib/src/gallium/auxiliary/util/u_vbuf_mgr.c @@ -471,7 +471,6 @@ void u_vbuf_set_vertex_buffers(struct u_vbuf_mgr *mgrb, const struct pipe_vertex_buffer *vb = &bufs[i]; pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, vb->buffer); - pipe_resource_reference(&mgr->b.real_vertex_buffer[i].buffer, NULL); mgr->b.real_vertex_buffer[i].buffer_offset = mgr->b.vertex_buffer[i].buffer_offset = vb->buffer_offset; @@ -480,10 +479,12 @@ void u_vbuf_set_vertex_buffers(struct u_vbuf_mgr *mgrb, mgr->b.vertex_buffer[i].stride = vb->stride; if (!vb->buffer) { + pipe_resource_reference(&mgr->b.real_vertex_buffer[i].buffer, NULL); continue; } if (u_vbuf_resource(vb->buffer)->user_ptr) { + pipe_resource_reference(&mgr->b.real_vertex_buffer[i].buffer, NULL); mgr->any_user_vbs = TRUE; continue; } diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c index da4e39f9c..1640c1448 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.c +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c @@ -15,12 +15,7 @@ */ -#include <assert.h> -#include <stdarg.h> -#include <stdio.h> - -#include "main/imports.h" - +#include <xf86drm.h> #include "dri_util.h" #include "utils.h" #include "xmlpool.h" @@ -35,18 +30,230 @@ PUBLIC const char __dri2ConfigOptions[] = static const uint __dri2NConfigOptions = 1; -#ifndef GLX_OML_sync_control -typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator); -#endif +/*****************************************************************/ +/** \name Screen handling functions */ +/*****************************************************************/ +/*@{*/ + +static void +setupLoaderExtensions(__DRIscreen *psp, + const __DRIextension **extensions) +{ + int i; + + for (i = 0; extensions[i]; i++) { + if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0) + psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0) + psp->dri2.image = (__DRIimageLookupExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0) + psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i]; + } +} + +static __DRIscreen * +dri2CreateNewScreen(int scrn, int fd, + const __DRIextension **extensions, + const __DRIconfig ***driver_configs, void *data) +{ + static const __DRIextension *emptyExtensionList[] = { NULL }; + __DRIscreen *psp; + drmVersionPtr version; + + psp = calloc(1, sizeof(*psp)); + if (!psp) + return NULL; + + setupLoaderExtensions(psp, extensions); + + version = drmGetVersion(fd); + if (version) { + psp->drm_version.major = version->version_major; + psp->drm_version.minor = version->version_minor; + psp->drm_version.patch = version->version_patchlevel; + drmFreeVersion(version); + } + + psp->loaderPrivate = data; + + psp->extensions = emptyExtensionList; + psp->fd = fd; + psp->myNum = scrn; + + psp->api_mask = (1 << __DRI_API_OPENGL); + + *driver_configs = driDriverAPI.InitScreen(psp); + if (*driver_configs == NULL) { + free(psp); + return NULL; + } + + driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, __dri2NConfigOptions); + driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, "dri2"); + + return psp; +} + +/** + * Destroy the per-screen private information. + * + * \internal + * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls + * drmClose(), and finally frees \p screenPrivate. + */ +static void driDestroyScreen(__DRIscreen *psp) +{ + if (psp) { + /* No interaction with the X-server is possible at this point. This + * routine is called after XCloseDisplay, so there is no protocol + * stream open to the X-server anymore. + */ + + _mesa_destroy_shader_compiler(); + + driDriverAPI.DestroyScreen(psp); + + driDestroyOptionCache(&psp->optionCache); + driDestroyOptionInfo(&psp->optionInfo); + + free(psp); + } +} + +static const __DRIextension **driGetExtensions(__DRIscreen *psp) +{ + return psp->extensions; +} + +/*@}*/ + + +/*****************************************************************/ +/** \name Context handling functions */ +/*****************************************************************/ +/*@{*/ + +static __DRIcontext * +dri2CreateNewContextForAPI(__DRIscreen *screen, int api, + const __DRIconfig *config, + __DRIcontext *shared, void *data) +{ + __DRIcontext *context; + const struct gl_config *modes = (config != NULL) ? &config->modes : NULL; + void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; + gl_api mesa_api; + + if (!(screen->api_mask & (1 << api))) + return NULL; + + switch (api) { + case __DRI_API_OPENGL: + mesa_api = API_OPENGL; + break; + case __DRI_API_GLES: + mesa_api = API_OPENGLES; + break; + case __DRI_API_GLES2: + mesa_api = API_OPENGLES2; + break; + default: + return NULL; + } + + context = malloc(sizeof *context); + if (!context) + return NULL; + + context->loaderPrivate = data; + + context->driScreenPriv = screen; + context->driDrawablePriv = NULL; + context->driReadablePriv = NULL; + + if (!driDriverAPI.CreateContext(mesa_api, modes, context, shareCtx) ) { + free(context); + return NULL; + } + + return context; +} + + +static __DRIcontext * +dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config, + __DRIcontext *shared, void *data) +{ + return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL, + config, shared, data); +} + +/** + * Destroy the per-context private information. + * + * \internal + * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls + * drmDestroyContext(), and finally frees \p contextPrivate. + */ +static void +driDestroyContext(__DRIcontext *pcp) +{ + if (pcp) { + driDriverAPI.DestroyContext(pcp); + free(pcp); + } +} + +static int +driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask) +{ + (void) dest; + (void) src; + (void) mask; + return GL_FALSE; +} + +/*@}*/ -static void dri_get_drawable(__DRIdrawable *pdp); -static void dri_put_drawable(__DRIdrawable *pdp); /*****************************************************************/ /** \name Context (un)binding functions */ /*****************************************************************/ /*@{*/ +static void dri_get_drawable(__DRIdrawable *pdp); +static void dri_put_drawable(__DRIdrawable *pdp); + +/** + * This function takes both a read buffer and a draw buffer. This is needed + * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent + * function. + */ +static int driBindContext(__DRIcontext *pcp, + __DRIdrawable *pdp, + __DRIdrawable *prp) +{ + /* + ** Assume error checking is done properly in glXMakeCurrent before + ** calling driUnbindContext. + */ + + if (!pcp) + return GL_FALSE; + + /* Bind the drawable to the context */ + pcp->driDrawablePriv = pdp; + pcp->driReadablePriv = prp; + if (pdp) { + pdp->driContextPriv = pcp; + dri_get_drawable(pdp); + } + if (prp && pdp != prp) { + dri_get_drawable(prp); + } + + return driDriverAPI.MakeCurrent(pcp, pdp, prp); +} + /** * Unbind context. * @@ -65,7 +272,6 @@ static void dri_put_drawable(__DRIdrawable *pdp); */ static int driUnbindContext(__DRIcontext *pcp) { - __DRIscreen *psp; __DRIdrawable *pdp; __DRIdrawable *prp; @@ -75,17 +281,16 @@ static int driUnbindContext(__DRIcontext *pcp) */ if (pcp == NULL) - return GL_FALSE; + return GL_FALSE; - psp = pcp->driScreenPriv; pdp = pcp->driDrawablePriv; prp = pcp->driReadablePriv; /* already unbound */ if (!pdp && !prp) - return GL_TRUE; - /* Let driver unbind drawable from context */ - (*psp->DriverAPI.UnbindContext)(pcp); + return GL_TRUE; + + driDriverAPI.UnbindContext(pcp); assert(pdp); if (pdp->refcount == 0) { @@ -96,63 +301,48 @@ static int driUnbindContext(__DRIcontext *pcp) dri_put_drawable(pdp); if (prp != pdp) { - if (prp->refcount == 0) { + if (prp->refcount == 0) { /* ERROR!!! */ return GL_FALSE; } - dri_put_drawable(prp); + dri_put_drawable(prp); } - /* XXX this is disabled so that if we call SwapBuffers on an unbound * window we can determine the last context bound to the window and * use that context's lock. (BrianP, 2-Dec-2000) */ - pcp->driDrawablePriv = pcp->driReadablePriv = NULL; + pcp->driDrawablePriv = NULL; + pcp->driReadablePriv = NULL; return GL_TRUE; } -/** - * This function takes both a read buffer and a draw buffer. This is needed - * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent - * function. - */ -static int driBindContext(__DRIcontext *pcp, - __DRIdrawable *pdp, - __DRIdrawable *prp) -{ - __DRIscreen *psp = NULL; +/*@}*/ - /* - ** Assume error checking is done properly in glXMakeCurrent before - ** calling driUnbindContext. - */ - if (!pcp) - return GL_FALSE; +static void dri_get_drawable(__DRIdrawable *pdp) +{ + pdp->refcount++; +} - /* Bind the drawable to the context */ - psp = pcp->driScreenPriv; - pcp->driDrawablePriv = pdp; - pcp->driReadablePriv = prp; +static void dri_put_drawable(__DRIdrawable *pdp) +{ if (pdp) { - pdp->driContextPriv = pcp; - dri_get_drawable(pdp); - } - if (prp && pdp != prp) { - dri_get_drawable(prp); - } + pdp->refcount--; + if (pdp->refcount) + return; - /* Call device-specific MakeCurrent */ - return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp); + driDriverAPI.DestroyBuffer(pdp); + free(pdp); + } } static __DRIdrawable * dri2CreateNewDrawable(__DRIscreen *screen, const __DRIconfig *config, - void *loaderPrivate) + void *data) { __DRIdrawable *pdraw; @@ -160,15 +350,18 @@ dri2CreateNewDrawable(__DRIscreen *screen, if (!pdraw) return NULL; + pdraw->loaderPrivate = data; + + pdraw->driScreenPriv = screen; pdraw->driContextPriv = NULL; - pdraw->loaderPrivate = loaderPrivate; - pdraw->refcount = 1; + pdraw->refcount = 0; pdraw->lastStamp = 0; pdraw->w = 0; pdraw->h = 0; - pdraw->driScreenPriv = screen; - if (!(*screen->DriverAPI.CreateBuffer)(screen, pdraw, &config->modes, 0)) { + dri_get_drawable(pdraw); + + if (!driDriverAPI.CreateBuffer(screen, pdraw, &config->modes, GL_FALSE)) { free(pdraw); return NULL; } @@ -178,19 +371,25 @@ dri2CreateNewDrawable(__DRIscreen *screen, return pdraw; } +static void +driDestroyDrawable(__DRIdrawable *pdp) +{ + dri_put_drawable(pdp); +} + static __DRIbuffer * dri2AllocateBuffer(__DRIscreen *screen, unsigned int attachment, unsigned int format, int width, int height) { - return (*screen->DriverAPI.AllocateBuffer)(screen, attachment, format, - width, height); + return driDriverAPI.AllocateBuffer(screen, attachment, format, + width, height); } static void dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer) { - (*screen->DriverAPI.ReleaseBuffer)(screen, buffer); + driDriverAPI.ReleaseBuffer(screen, buffer); } @@ -228,232 +427,12 @@ dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val) return 0; } - -static void dri_get_drawable(__DRIdrawable *pdp) -{ - pdp->refcount++; -} - -static void dri_put_drawable(__DRIdrawable *pdp) -{ - __DRIscreen *psp; - - if (pdp) { - pdp->refcount--; - if (pdp->refcount) - return; - - psp = pdp->driScreenPriv; - (*psp->DriverAPI.DestroyBuffer)(pdp); - free(pdp); - } -} - -static void -driDestroyDrawable(__DRIdrawable *pdp) -{ - dri_put_drawable(pdp); -} - -/*@}*/ - - -/*****************************************************************/ -/** \name Context handling functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Destroy the per-context private information. - * - * \internal - * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls - * drmDestroyContext(), and finally frees \p contextPrivate. - */ -static void -driDestroyContext(__DRIcontext *pcp) -{ - if (pcp) { - (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp); - free(pcp); - } -} - static unsigned int dri2GetAPIMask(__DRIscreen *screen) { return screen->api_mask; } -static __DRIcontext * -dri2CreateNewContextForAPI(__DRIscreen *screen, int api, - const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - __DRIcontext *context; - const struct gl_config *modes = (config != NULL) ? &config->modes : NULL; - void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; - gl_api mesa_api; - - if (!(screen->api_mask & (1 << api))) - return NULL; - - switch (api) { - case __DRI_API_OPENGL: - mesa_api = API_OPENGL; - break; - case __DRI_API_GLES: - mesa_api = API_OPENGLES; - break; - case __DRI_API_GLES2: - mesa_api = API_OPENGLES2; - break; - default: - return NULL; - } - - context = malloc(sizeof *context); - if (!context) - return NULL; - - context->driScreenPriv = screen; - context->driDrawablePriv = NULL; - context->loaderPrivate = data; - - if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes, - context, shareCtx) ) { - free(context); - return NULL; - } - - return context; -} - - -static __DRIcontext * -dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL, - config, shared, data); -} - -static int -driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask) -{ - (void) dest; - (void) src; - (void) mask; - return GL_FALSE; -} - -/*@}*/ - - -/*****************************************************************/ -/** \name Screen handling functions */ -/*****************************************************************/ -/*@{*/ - -/** - * Destroy the per-screen private information. - * - * \internal - * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls - * drmClose(), and finally frees \p screenPrivate. - */ -static void driDestroyScreen(__DRIscreen *psp) -{ - if (psp) { - /* No interaction with the X-server is possible at this point. This - * routine is called after XCloseDisplay, so there is no protocol - * stream open to the X-server anymore. - */ - - _mesa_destroy_shader_compiler(); - - if (psp->DriverAPI.DestroyScreen) - (*psp->DriverAPI.DestroyScreen)(psp); - - driDestroyOptionCache(&psp->optionCache); - driDestroyOptionInfo(&psp->optionInfo); - - free(psp); - } -} - -static void -setupLoaderExtensions(__DRIscreen *psp, - const __DRIextension **extensions) -{ - int i; - - for (i = 0; extensions[i]; i++) { - if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0) - psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0) - psp->dri2.image = (__DRIimageLookupExtension *) extensions[i]; - if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0) - psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i]; - } -} - -/** - * DRI2 - */ -static __DRIscreen * -dri2CreateNewScreen(int scrn, int fd, - const __DRIextension **extensions, - const __DRIconfig ***driver_configs, void *data) -{ - static const __DRIextension *emptyExtensionList[] = { NULL }; - __DRIscreen *psp; - drmVersionPtr version; - - if (driDriverAPI.InitScreen2 == NULL) - return NULL; - - psp = calloc(1, sizeof(*psp)); - if (!psp) - return NULL; - - setupLoaderExtensions(psp, extensions); - - version = drmGetVersion(fd); - if (version) { - psp->drm_version.major = version->version_major; - psp->drm_version.minor = version->version_minor; - psp->drm_version.patch = version->version_patchlevel; - drmFreeVersion(version); - } - - psp->extensions = emptyExtensionList; - psp->fd = fd; - psp->myNum = scrn; - - psp->DriverAPI = driDriverAPI; - psp->api_mask = (1 << __DRI_API_OPENGL); - *driver_configs = driDriverAPI.InitScreen2(psp); - if (*driver_configs == NULL) { - free(psp); - return NULL; - } - - psp->DriverAPI = driDriverAPI; - psp->loaderPrivate = data; - - driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, - __dri2NConfigOptions); - driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, - "dri2"); - - return psp; -} - -static const __DRIextension **driGetExtensions(__DRIscreen *psp) -{ - return psp->extensions; -} /** Core interface */ const __DRIcoreExtension driCoreExtension = { diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.h b/mesalib/src/mesa/drivers/dri/common/dri_util.h index 7a3b0a9b2..bebb021f6 100644 --- a/mesalib/src/mesa/drivers/dri/common/dri_util.h +++ b/mesalib/src/mesa/drivers/dri/common/dri_util.h @@ -44,24 +44,25 @@ * \author Brian Paul <brian@precisioninsight.com> */ +/** + * The following structs are shared between DRISW and DRI2, the DRISW structs + * are essentially base classes of the DRI2 structs. DRISW needs to compile on + * platforms without DRM, so keep the structs opaque to DRM. + */ + #ifndef _DRI_UTIL_H_ #define _DRI_UTIL_H_ #include <GL/gl.h> -#include <drm.h> -#include <drm_sarea.h> -#include <xf86drm.h> -#include "xmlconfig.h" -#include "main/glheader.h" +#include <GL/internal/dri_interface.h> #include "main/mtypes.h" -#include "GL/internal/dri_interface.h" - -#define GLX_BAD_CONTEXT 5 +#include "xmlconfig.h" /** * Extensions. */ extern const __DRIcoreExtension driCoreExtension; +extern const __DRIswrastExtension driSWRastExtension; extern const __DRIdri2Extension driDRI2Extension; extern const __DRI2configQueryExtension dri2ConfigQueryExtension; @@ -76,56 +77,37 @@ extern const __DRI2configQueryExtension dri2ConfigQueryExtension; * this structure. */ struct __DriverAPIRec { - /** - * Screen destruction callback - */ + const __DRIconfig **(*InitScreen) (__DRIscreen * priv); + void (*DestroyScreen)(__DRIscreen *driScrnPriv); - /** - * Context creation callback - */ GLboolean (*CreateContext)(gl_api api, - const struct gl_config *glVis, - __DRIcontext *driContextPriv, + const struct gl_config *glVis, + __DRIcontext *driContextPriv, void *sharedContextPrivate); - /** - * Context destruction callback - */ void (*DestroyContext)(__DRIcontext *driContextPriv); - /** - * Buffer (drawable) creation callback - */ GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv, __DRIdrawable *driDrawPriv, const struct gl_config *glVis, GLboolean pixmapBuffer); - - /** - * Buffer (drawable) destruction callback - */ + void (*DestroyBuffer)(__DRIdrawable *driDrawPriv); - /** - * Context activation callback - */ + void (*SwapBuffers)(__DRIdrawable *driDrawPriv); + GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv, __DRIdrawable *driDrawPriv, __DRIdrawable *driReadPriv); - /** - * Context unbinding callback - */ GLboolean (*UnbindContext)(__DRIcontext *driContextPriv); - /* DRI2 Entry point */ - const __DRIconfig **(*InitScreen2) (__DRIscreen * priv); - __DRIbuffer *(*AllocateBuffer) (__DRIscreen *screenPrivate, - unsigned int attachment, - unsigned int format, - int width, int height); + unsigned int attachment, + unsigned int format, + int width, int height); + void (*ReleaseBuffer) (__DRIscreen *screenPrivate, __DRIbuffer *buffer); }; @@ -133,59 +115,54 @@ extern const struct __DriverAPIRec driDriverAPI; /** - * Per-drawable private DRI driver information. + * Per-screen private driver information. */ -struct __DRIdrawableRec { +struct __DRIscreenRec { /** - * Driver's private drawable information. - * - * This structure is opaque. + * Current screen's number */ - void *driverPrivate; + int myNum; /** - * Private data from the loader. We just hold on to it and pass - * it back when calling into loader provided functions. + * File descriptor returned when the kernel device driver is opened. + * + * Used to: + * - authenticate client to kernel + * - map the frame buffer, SAREA, etc. + * - close the kernel device driver */ - void *loaderPrivate; + int fd; /** - * Reference count for number of context's currently bound to this - * drawable. - * - * Once it reaches zero, the drawable can be destroyed. - * - * \note This behavior will change with GLX 1.3. + * DRM (kernel module) version information. */ - int refcount; + __DRIversion drm_version; /** - * Last value of the stamp. - * - * If this differs from the value stored at __DRIdrawable::dri2.stamp, - * then the drawable information has been modified by the X server, and the - * drawable information (below) should be retrieved from the X server. + * Device-dependent private information (not stored in the SAREA). + * + * This pointer is never touched by the DRI layer. */ - unsigned int lastStamp; + void *driverPrivate; - int w, h; + void *loaderPrivate; - /** - * Pointer to context to which this drawable is currently bound. - */ - __DRIcontext *driContextPriv; + const __DRIextension **extensions; - /** - * Pointer to screen on which this drawable was created. - */ - __DRIscreen *driScreenPriv; + const __DRIswrastLoaderExtension *swrast_loader; - /** - * Drawable timestamp. Increased when the loader calls invalidate. - */ struct { - unsigned int stamp; + /* Flag to indicate that this is a DRI2 screen. Many of the above + * fields will not be valid or initializaed in that case. */ + __DRIdri2LoaderExtension *loader; + __DRIimageLookupExtension *image; + __DRIuseInvalidateExtension *useInvalidate; } dri2; + + driOptionCache optionInfo; + driOptionCache optionCache; + + unsigned int api_mask; }; /** @@ -198,6 +175,11 @@ struct __DRIcontextRec { void *driverPrivate; /** + * The loaders's private context data. This structure is opaque. + */ + void *loaderPrivate; + + /** * Pointer to drawable currently bound to this context for drawing. */ __DRIdrawable *driDrawablePriv; @@ -212,11 +194,6 @@ struct __DRIcontextRec { */ __DRIscreen *driScreenPriv; - /** - * The loaders's private context data. This structure is opaque. - */ - void *loaderPrivate; - struct { int draw_stamp; int read_stamp; @@ -224,59 +201,59 @@ struct __DRIcontextRec { }; /** - * Per-screen private driver information. + * Per-drawable private DRI driver information. */ -struct __DRIscreenRec { +struct __DRIdrawableRec { /** - * Current screen's number + * Driver's private drawable information. + * + * This structure is opaque. */ - int myNum; + void *driverPrivate; /** - * Callback functions into the hardware-specific DRI driver code. + * Private data from the loader. We just hold on to it and pass + * it back when calling into loader provided functions. */ - struct __DriverAPIRec DriverAPI; + void *loaderPrivate; - const __DRIextension **extensions; + /** + * Pointer to context to which this drawable is currently bound. + */ + __DRIcontext *driContextPriv; /** - * DRM (kernel module) version information. + * Pointer to screen on which this drawable was created. */ - __DRIversion drm_version; + __DRIscreen *driScreenPriv; /** - * File descriptor returned when the kernel device driver is opened. - * - * Used to: - * - authenticate client to kernel - * - map the frame buffer, SAREA, etc. - * - close the kernel device driver + * Reference count for number of context's currently bound to this + * drawable. + * + * Once it reaches zero, the drawable can be destroyed. + * + * \note This behavior will change with GLX 1.3. */ - int fd; + int refcount; /** - * Device-dependent private information (not stored in the SAREA). - * - * This pointer is never touched by the DRI layer. + * Last value of the stamp. + * + * If this differs from the value stored at __DRIdrawable::dri2.stamp, + * then the drawable information has been modified by the X server, and the + * drawable information (below) should be retrieved from the X server. */ -#ifdef __cplusplus - void *priv; -#else - void *private; -#endif + unsigned int lastStamp; + int w, h; + + /** + * Drawable timestamp. Increased when the loader calls invalidate. + */ struct { - /* Flag to indicate that this is a DRI2 screen. Many of the above - * fields will not be valid or initializaed in that case. */ - __DRIdri2LoaderExtension *loader; - __DRIimageLookupExtension *image; - __DRIuseInvalidateExtension *useInvalidate; + unsigned int stamp; } dri2; - - driOptionCache optionInfo; - driOptionCache optionCache; - unsigned int api_mask; - void *loaderPrivate; }; extern void diff --git a/mesalib/src/mesa/drivers/dri/common/drisw_util.c b/mesalib/src/mesa/drivers/dri/common/drisw_util.c index 1bdb6d893..614339eeb 100644 --- a/mesalib/src/mesa/drivers/dri/common/drisw_util.c +++ b/mesalib/src/mesa/drivers/dri/common/drisw_util.c @@ -27,7 +27,7 @@ * DRISW utility functions, i.e. dri_util.c stripped from drm-specific bits. */ -#include "drisw_util.h" +#include "dri_util.h" #include "utils.h" @@ -54,20 +54,19 @@ driCreateNewScreen(int scrn, const __DRIextension **extensions, static const __DRIextension *emptyExtensionList[] = { NULL }; __DRIscreen *psp; - (void) data; - psp = CALLOC_STRUCT(__DRIscreenRec); if (!psp) return NULL; setupLoaderExtensions(psp, extensions); + psp->loaderPrivate = data; + psp->extensions = emptyExtensionList; psp->fd = -1; psp->myNum = scrn; *driver_configs = driDriverAPI.InitScreen(psp); - if (*driver_configs == NULL) { FREE(psp); return NULL; @@ -80,7 +79,6 @@ static void driDestroyScreen(__DRIscreen *psp) { if (psp) { driDriverAPI.DestroyScreen(psp); - FREE(psp); } } @@ -96,37 +94,12 @@ static const __DRIextension **driGetExtensions(__DRIscreen *psp) */ static __DRIcontext * -driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config, - __DRIcontext *shared, void *data) -{ - __DRIcontext *pcp; - void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; - - pcp = CALLOC_STRUCT(__DRIcontextRec); - if (!pcp) - return NULL; - - pcp->loaderPrivate = data; - - pcp->driScreenPriv = psp; - pcp->driDrawablePriv = NULL; - pcp->driReadablePriv = NULL; - - if (!driDriverAPI.CreateContext(API_OPENGL, - &config->modes, pcp, shareCtx)) { - FREE(pcp); - return NULL; - } - - return pcp; -} - -static __DRIcontext * driCreateNewContextForAPI(__DRIscreen *psp, int api, const __DRIconfig *config, __DRIcontext *shared, void *data) { __DRIcontext *pcp; + const struct gl_config *modes = (config != NULL) ? &config->modes : NULL; void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL; gl_api mesa_api; @@ -154,8 +127,7 @@ driCreateNewContextForAPI(__DRIscreen *psp, int api, pcp->driDrawablePriv = NULL; pcp->driReadablePriv = NULL; - if (!driDriverAPI.CreateContext(mesa_api, - &config->modes, pcp, shareCtx)) { + if (!driDriverAPI.CreateContext(mesa_api, modes, pcp, shareCtx)) { FREE(pcp); return NULL; } @@ -163,6 +135,14 @@ driCreateNewContextForAPI(__DRIscreen *psp, int api, return pcp; } +static __DRIcontext * +driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config, + __DRIcontext *shared, void *data) +{ + return driCreateNewContextForAPI(psp, __DRI_API_OPENGL, + config, shared, data); +} + static void driDestroyContext(__DRIcontext *pcp) { @@ -193,7 +173,7 @@ static int driBindContext(__DRIcontext *pcp, pdp->driContextPriv = pcp; dri_get_drawable(pdp); } - if ( prp && pdp != prp ) { + if (prp && pdp != prp) { dri_get_drawable(prp); } } @@ -248,7 +228,6 @@ static void dri_put_drawable(__DRIdrawable *pdp) return; driDriverAPI.DestroyBuffer(pdp); - FREE(pdp); } } diff --git a/mesalib/src/mesa/drivers/dri/common/drisw_util.h b/mesalib/src/mesa/drivers/dri/common/drisw_util.h deleted file mode 100644 index cae47e1f6..000000000 --- a/mesalib/src/mesa/drivers/dri/common/drisw_util.h +++ /dev/null @@ -1,134 +0,0 @@ -/*
- * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
- *
- * 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, sublicense,
- * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL 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
- * Binding of the DRI interface (dri_interface.h) for DRISW.
- *
- * The DRISW structs are 'base classes' of the corresponding DRI1 / DRI2 (DRM)
- * structs. The bindings for SW and DRM can be unified by making the DRM structs
- * 'sub-classes' of the SW structs, either proper or with field re-ordering.
- *
- * The code can also be unified but that requires cluttering the common code
- * with ifdef's and guarding with (__DRIscreen::fd >= 0) for DRM.
- */
-
-#ifndef _DRISW_UTIL_H
-#define _DRISW_UTIL_H
-
-#include "main/mtypes.h"
-
-#include <GL/gl.h>
-#include <GL/internal/dri_interface.h>
-typedef struct _drmLock drmLock;
-
-
-/**
- * Extensions
- */
-extern const __DRIcoreExtension driCoreExtension;
-extern const __DRIswrastExtension driSWRastExtension;
-
-
-/**
- * Driver callback functions
- */
-struct __DriverAPIRec {
- const __DRIconfig **(*InitScreen) (__DRIscreen * priv);
-
- void (*DestroyScreen)(__DRIscreen *driScrnPriv);
-
- GLboolean (*CreateContext)(gl_api glapi,
- const struct gl_config *glVis,
- __DRIcontext *driContextPriv,
- void *sharedContextPrivate);
-
- void (*DestroyContext)(__DRIcontext *driContextPriv);
-
- GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv,
- __DRIdrawable *driDrawPriv,
- const struct gl_config *glVis,
- GLboolean pixmapBuffer);
-
- void (*DestroyBuffer)(__DRIdrawable *driDrawPriv);
-
- void (*SwapBuffers)(__DRIdrawable *driDrawPriv);
-
- GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv,
- __DRIdrawable *driDrawPriv,
- __DRIdrawable *driReadPriv);
-
- GLboolean (*UnbindContext)(__DRIcontext *driContextPriv);
-};
-
-extern const struct __DriverAPIRec driDriverAPI;
-
-
-/**
- * Data types
- */
-struct __DRIscreenRec {
- int myNum;
-
- int fd;
-
- void *private;
-
- const __DRIextension **extensions;
-
- const __DRIswrastLoaderExtension *swrast_loader;
-};
-
-struct __DRIcontextRec {
-
- void *driverPrivate;
-
- void *loaderPrivate;
-
- __DRIdrawable *driDrawablePriv;
-
- __DRIdrawable *driReadablePriv;
-
- __DRIscreen *driScreenPriv;
-};
-
-struct __DRIdrawableRec {
-
- void *driverPrivate;
-
- void *loaderPrivate;
-
- __DRIcontext *driContextPriv;
-
- __DRIscreen *driScreenPriv;
-
- int refcount;
-
- /* gallium */
- unsigned int lastStamp;
-
- int w;
- int h;
-};
-
-#endif /* _DRISW_UTIL_H */
diff --git a/mesalib/src/mesa/drivers/dri/common/utils.c b/mesalib/src/mesa/drivers/dri/common/utils.c index d8656a784..328f56b50 100644 --- a/mesalib/src/mesa/drivers/dri/common/utils.c +++ b/mesalib/src/mesa/drivers/dri/common/utils.c @@ -37,29 +37,6 @@ #include "utils.h" -/** - * Print message to \c stderr if the \c LIBGL_DEBUG environment variable - * is set. - * - * Is called from the drivers. - * - * \param f \c printf like format string. - */ -void -__driUtilMessage(const char *f, ...) -{ - va_list args; - - if (getenv("LIBGL_DEBUG")) { - fprintf(stderr, "libGL: "); - va_start(args, f); - vfprintf(stderr, f, args); - va_end(args); - fprintf(stderr, "\n"); - } -} - - unsigned driParseDebugString( const char * debug, const struct dri_debug_control * control ) diff --git a/mesalib/src/mesa/drivers/dri/common/utils.h b/mesalib/src/mesa/drivers/dri/common/utils.h index c2302de5d..9d6eb3037 100644 --- a/mesalib/src/mesa/drivers/dri/common/utils.h +++ b/mesalib/src/mesa/drivers/dri/common/utils.h @@ -32,16 +32,11 @@ #include <GL/internal/dri_interface.h> #include "main/context.h" -typedef struct __DRIutilversionRec2 __DRIutilversion2; - struct dri_debug_control { const char * string; unsigned flag; }; -extern void -__driUtilMessage(const char *f, ...); - extern unsigned driParseDebugString( const char * debug, const struct dri_debug_control * control ); diff --git a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c index 12dd31bb1..6d1d5ec61 100644 --- a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c +++ b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c @@ -420,6 +420,28 @@ static GLboolean checkValue (const driOptionValue *v, const driOptionInfo *info) return GL_FALSE; } +/** + * Print message to \c stderr if the \c LIBGL_DEBUG environment variable + * is set. + * + * Is called from the drivers. + * + * \param f \c printf like format string. + */ +static void +__driUtilMessage(const char *f, ...) +{ + va_list args; + + if (getenv("LIBGL_DEBUG")) { + fprintf(stderr, "libGL: "); + va_start(args, f); + vfprintf(stderr, f, args); + va_end(args); + fprintf(stderr, "\n"); + } +} + /** \brief Output a warning message. */ #define XML_WARNING1(msg) do {\ __driUtilMessage ("Warning in %s line %d, column %d: "msg, data->name, \ diff --git a/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h b/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h index 405bb0fd3..d08d42a81 100644 --- a/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h +++ b/mesalib/src/mesa/drivers/dri/swrast/swrast_priv.h @@ -30,7 +30,7 @@ #include <GL/gl.h> #include <GL/internal/dri_interface.h> #include "main/mtypes.h" -#include "drisw_util.h" +#include "dri_util.h" #ifdef _MSC_VER #ifdef PUBLIC diff --git a/mesalib/src/mesa/state_tracker/st_cb_bitmap.c b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c index beb5e7cab..1a8854b9b 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_bitmap.c +++ b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c @@ -480,6 +480,7 @@ draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, cso_save_viewport(cso); cso_save_fragment_shader(cso); cso_save_vertex_shader(cso); + cso_save_geometry_shader(cso); cso_save_vertex_elements(cso); cso_save_vertex_buffers(cso); @@ -493,6 +494,9 @@ draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, /* vertex shader state: position + texcoord pass-through */ cso_set_vertex_shader_handle(cso, st->bitmap.vs); + /* geometry shader state: disabled */ + cso_set_geometry_shader_handle(cso, NULL); + /* user samplers, plus our bitmap sampler */ { struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; @@ -556,6 +560,7 @@ draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, cso_restore_viewport(cso); cso_restore_fragment_shader(cso); cso_restore_vertex_shader(cso); + cso_restore_geometry_shader(cso); cso_restore_vertex_elements(cso); cso_restore_vertex_buffers(cso); } diff --git a/mesalib/src/mesa/state_tracker/st_cb_clear.c b/mesalib/src/mesa/state_tracker/st_cb_clear.c index 83802a5ea..19a87aae2 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_clear.c +++ b/mesalib/src/mesa/state_tracker/st_cb_clear.c @@ -246,6 +246,7 @@ clear_with_quad(struct gl_context *ctx, cso_save_clip(st->cso_context); cso_save_fragment_shader(st->cso_context); cso_save_vertex_shader(st->cso_context); + cso_save_geometry_shader(st->cso_context); cso_save_vertex_elements(st->cso_context); cso_save_vertex_buffers(st->cso_context); @@ -321,6 +322,7 @@ clear_with_quad(struct gl_context *ctx, cso_set_clip(st->cso_context, &st->clear.clip); set_fragment_shader(st); set_vertex_shader(st); + cso_set_geometry_shader_handle(st->cso_context, NULL); if (ctx->DrawBuffer->_ColorDrawBuffers[0]) { st_translate_color(ctx->Color.ClearColor.f, @@ -340,6 +342,7 @@ clear_with_quad(struct gl_context *ctx, cso_restore_clip(st->cso_context); cso_restore_fragment_shader(st->cso_context); cso_restore_vertex_shader(st->cso_context); + cso_restore_geometry_shader(st->cso_context); cso_restore_vertex_elements(st->cso_context); cso_restore_vertex_buffers(st->cso_context); } diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c index 89e0a73f1..1c44d0d87 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c @@ -671,6 +671,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, cso_save_fragment_sampler_views(cso); cso_save_fragment_shader(cso); cso_save_vertex_shader(cso); + cso_save_geometry_shader(cso); cso_save_vertex_elements(cso); cso_save_vertex_buffers(cso); if (write_stencil) { @@ -720,6 +721,8 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, /* vertex shader state: position + texcoord pass-through */ cso_set_vertex_shader_handle(cso, driver_vp); + /* geometry shader state: disabled */ + cso_set_geometry_shader_handle(cso, NULL); /* texture sampling state: */ { @@ -789,6 +792,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, cso_restore_fragment_sampler_views(cso); cso_restore_fragment_shader(cso); cso_restore_vertex_shader(cso); + cso_restore_geometry_shader(cso); cso_restore_vertex_elements(cso); cso_restore_vertex_buffers(cso); if (write_stencil) { diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawtex.c b/mesalib/src/mesa/state_tracker/st_cb_drawtex.c index 86ceb9d78..eff195068 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawtex.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawtex.c @@ -230,6 +230,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, cso_save_viewport(cso); cso_save_vertex_shader(cso); + cso_save_geometry_shader(cso); cso_save_vertex_elements(cso); cso_save_vertex_buffers(cso); @@ -238,6 +239,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, semantic_names, semantic_indexes); cso_set_vertex_shader_handle(cso, vs); } + cso_set_geometry_shader_handle(cso, NULL); for (i = 0; i < numAttribs; i++) { velements[i].src_offset = i * 4 * sizeof(float); @@ -278,6 +280,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, /* restore state */ cso_restore_viewport(cso); cso_restore_vertex_shader(cso); + cso_restore_geometry_shader(cso); cso_restore_vertex_elements(cso); cso_restore_vertex_buffers(cso); } diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c index af8cc0476..3563e1d9b 100644 --- a/mesalib/src/mesa/state_tracker/st_extensions.c +++ b/mesalib/src/mesa/state_tracker/st_extensions.c @@ -555,7 +555,8 @@ void st_init_extensions(struct st_context *st) ctx->Extensions.ARB_vertex_type_2_10_10_10_rev = GL_TRUE; } - if (screen->get_shader_param(screen, PIPE_SHADER_GEOMETRY, PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) { + if (screen->get_shader_param(screen, PIPE_SHADER_GEOMETRY, + PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) { #if 0 /* XXX re-enable when GLSL compiler again supports geometry shaders */ ctx->Extensions.ARB_geometry_shader4 = GL_TRUE; #endif diff --git a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp index 6b841f1e9..529f5f64a 100644 --- a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -79,6 +79,12 @@ extern "C" { (1 << PROGRAM_CONSTANT) | \ (1 << PROGRAM_UNIFORM)) +/** + * Maximum number of temporary registers. + * + * It is too big for stack allocated arrays -- it will cause stack overflow on + * Windows and likely Mac OS X. + */ #define MAX_TEMPS 4096 /* will be 4 for GLSL 4.00 */ @@ -3004,9 +3010,13 @@ glsl_to_tgsi_visitor::remove_output_reads(gl_register_file type) GLint outputMap[VERT_RESULT_MAX]; GLint outputTypes[VERT_RESULT_MAX]; GLuint numVaryingReads = 0; - GLboolean usedTemps[MAX_TEMPS]; + GLboolean *usedTemps; GLuint firstTemp = 0; + usedTemps = new GLboolean[MAX_TEMPS]; + if (!usedTemps) { + return; + } _mesa_find_used_registers(prog, PROGRAM_TEMPORARY, usedTemps, MAX_TEMPS); @@ -3039,6 +3049,8 @@ glsl_to_tgsi_visitor::remove_output_reads(gl_register_file type) } } + delete [] usedTemps; + if (numVaryingReads == 0) return; /* nothing to be done */ @@ -3110,9 +3122,13 @@ get_src_arg_mask(st_dst_reg dst, st_src_reg src) void glsl_to_tgsi_visitor::simplify_cmp(void) { - unsigned tempWrites[MAX_TEMPS]; + unsigned *tempWrites; unsigned outputWrites[MAX_PROGRAM_OUTPUTS]; + tempWrites = new unsigned[MAX_TEMPS]; + if (!tempWrites) { + return; + } memset(tempWrites, 0, sizeof(tempWrites)); memset(outputWrites, 0, sizeof(outputWrites)); @@ -3128,7 +3144,7 @@ glsl_to_tgsi_visitor::simplify_cmp(void) inst->op == TGSI_OPCODE_END || inst->op == TGSI_OPCODE_ENDSUB || inst->op == TGSI_OPCODE_RET) { - return; + break; } if (inst->dst.file == PROGRAM_OUTPUT) { @@ -3153,6 +3169,8 @@ glsl_to_tgsi_visitor::simplify_cmp(void) inst->src[0] = inst->src[1]; } } + + delete [] tempWrites; } /* Replaces all references to a temporary register index with another index. */ @@ -4580,14 +4598,19 @@ st_translate_program( const ubyte outputSemanticIndex[], boolean passthrough_edgeflags) { - struct st_translate translate, *t; + struct st_translate *t; unsigned i; enum pipe_error ret = PIPE_OK; assert(numInputs <= Elements(t->inputs)); assert(numOutputs <= Elements(t->outputs)); - t = &translate; + t = CALLOC_STRUCT(st_translate); + if (!t) { + ret = PIPE_ERROR_OUT_OF_MEMORY; + goto out; + } + memset(t, 0, sizeof *t); t->procType = procType; @@ -4642,7 +4665,8 @@ st_translate_program( break; default: assert(!"fragment shader outputs must be POSITION/STENCIL/COLOR"); - return PIPE_ERROR_BAD_INPUT; + ret = PIPE_ERROR_BAD_INPUT; + goto out; } } } @@ -4823,13 +4847,17 @@ st_translate_program( } out: - FREE(t->insn); - FREE(t->labels); - FREE(t->constants); - FREE(t->immediates); + if (t) { + FREE(t->insn); + FREE(t->labels); + FREE(t->constants); + FREE(t->immediates); + + if (t->error) { + debug_printf("%s: translate error flag set\n", __FUNCTION__); + } - if (t->error) { - debug_printf("%s: translate error flag set\n", __FUNCTION__); + FREE(t); } return ret; diff --git a/mesalib/src/mesa/swrast/s_readpix.c b/mesalib/src/mesa/swrast/s_readpix.c index 6246c092b..4438b9a20 100644 --- a/mesalib/src/mesa/swrast/s_readpix.c +++ b/mesalib/src/mesa/swrast/s_readpix.c @@ -305,7 +305,7 @@ static GLboolean fast_read_depth_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, - GLvoid *dst, int dstStride) + GLubyte *dst, int dstStride) { struct gl_framebuffer *fb = ctx->ReadBuffer; struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer; |