diff options
author | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
commit | dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0 (patch) | |
tree | bdf833cc6a4fc9035411779e10dd9e8478201885 /mesalib/src/mesa/state_tracker | |
parent | 0b40f5f4b54453a77f4b09c431f8efc6875da61f (diff) | |
download | vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.gz vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.bz2 vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.zip |
Synchronised line endinge with release branch
Diffstat (limited to 'mesalib/src/mesa/state_tracker')
21 files changed, 13506 insertions, 13506 deletions
diff --git a/mesalib/src/mesa/state_tracker/st_atom_blend.c b/mesalib/src/mesa/state_tracker/st_atom_blend.c index c02ea3ffa..4c9a2b95a 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_blend.c +++ b/mesalib/src/mesa/state_tracker/st_atom_blend.c @@ -1,303 +1,303 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
- /*
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Brian Paul
- */
-
-
-#include "st_context.h"
-#include "st_atom.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "cso_cache/cso_context.h"
-
-#include "main/macros.h"
-
-/**
- * Convert GLenum blend tokens to pipe tokens.
- * Both blend factors and blend funcs are accepted.
- */
-static GLuint
-translate_blend(GLenum blend)
-{
- switch (blend) {
- /* blend functions */
- case GL_FUNC_ADD:
- return PIPE_BLEND_ADD;
- case GL_FUNC_SUBTRACT:
- return PIPE_BLEND_SUBTRACT;
- case GL_FUNC_REVERSE_SUBTRACT:
- return PIPE_BLEND_REVERSE_SUBTRACT;
- case GL_MIN:
- return PIPE_BLEND_MIN;
- case GL_MAX:
- return PIPE_BLEND_MAX;
-
- /* blend factors */
- case GL_ONE:
- return PIPE_BLENDFACTOR_ONE;
- case GL_SRC_COLOR:
- return PIPE_BLENDFACTOR_SRC_COLOR;
- case GL_SRC_ALPHA:
- return PIPE_BLENDFACTOR_SRC_ALPHA;
- case GL_DST_ALPHA:
- return PIPE_BLENDFACTOR_DST_ALPHA;
- case GL_DST_COLOR:
- return PIPE_BLENDFACTOR_DST_COLOR;
- case GL_SRC_ALPHA_SATURATE:
- return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
- case GL_CONSTANT_COLOR:
- return PIPE_BLENDFACTOR_CONST_COLOR;
- case GL_CONSTANT_ALPHA:
- return PIPE_BLENDFACTOR_CONST_ALPHA;
- /*
- return PIPE_BLENDFACTOR_SRC1_COLOR;
- return PIPE_BLENDFACTOR_SRC1_ALPHA;
- */
- case GL_ZERO:
- return PIPE_BLENDFACTOR_ZERO;
- case GL_ONE_MINUS_SRC_COLOR:
- return PIPE_BLENDFACTOR_INV_SRC_COLOR;
- case GL_ONE_MINUS_SRC_ALPHA:
- return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
- case GL_ONE_MINUS_DST_COLOR:
- return PIPE_BLENDFACTOR_INV_DST_COLOR;
- case GL_ONE_MINUS_DST_ALPHA:
- return PIPE_BLENDFACTOR_INV_DST_ALPHA;
- case GL_ONE_MINUS_CONSTANT_COLOR:
- return PIPE_BLENDFACTOR_INV_CONST_COLOR;
- case GL_ONE_MINUS_CONSTANT_ALPHA:
- return PIPE_BLENDFACTOR_INV_CONST_ALPHA;
- /*
- return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
- return PIPE_BLENDFACTOR_INV_SRC1_ALPHA;
- */
- default:
- assert("invalid GL token in translate_blend()" == NULL);
- return 0;
- }
-}
-
-
-/**
- * Convert GLenum logicop tokens to pipe tokens.
- */
-static GLuint
-translate_logicop(GLenum logicop)
-{
- switch (logicop) {
- case GL_CLEAR:
- return PIPE_LOGICOP_CLEAR;
- case GL_NOR:
- return PIPE_LOGICOP_NOR;
- case GL_AND_INVERTED:
- return PIPE_LOGICOP_AND_INVERTED;
- case GL_COPY_INVERTED:
- return PIPE_LOGICOP_COPY_INVERTED;
- case GL_AND_REVERSE:
- return PIPE_LOGICOP_AND_REVERSE;
- case GL_INVERT:
- return PIPE_LOGICOP_INVERT;
- case GL_XOR:
- return PIPE_LOGICOP_XOR;
- case GL_NAND:
- return PIPE_LOGICOP_NAND;
- case GL_AND:
- return PIPE_LOGICOP_AND;
- case GL_EQUIV:
- return PIPE_LOGICOP_EQUIV;
- case GL_NOOP:
- return PIPE_LOGICOP_NOOP;
- case GL_OR_INVERTED:
- return PIPE_LOGICOP_OR_INVERTED;
- case GL_COPY:
- return PIPE_LOGICOP_COPY;
- case GL_OR_REVERSE:
- return PIPE_LOGICOP_OR_REVERSE;
- case GL_OR:
- return PIPE_LOGICOP_OR;
- case GL_SET:
- return PIPE_LOGICOP_SET;
- default:
- assert("invalid GL token in translate_logicop()" == NULL);
- return 0;
- }
-}
-
-/**
- * Figure out if colormasks are different per rt.
- */
-static GLboolean
-colormask_per_rt(const struct gl_context *ctx)
-{
- /* a bit suboptimal have to compare lots of values */
- unsigned i;
- for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) {
- if (memcmp(ctx->Color.ColorMask[0], ctx->Color.ColorMask[i], 4)) {
- return GL_TRUE;
- }
- }
- return GL_FALSE;
-}
-
-/**
- * Figure out if blend enables/state are different per rt.
- */
-static GLboolean
-blend_per_rt(const struct gl_context *ctx)
-{
- if (ctx->Color.BlendEnabled &&
- (ctx->Color.BlendEnabled != ((1 << ctx->Const.MaxDrawBuffers) - 1))) {
- /* This can only happen if GL_EXT_draw_buffers2 is enabled */
- return GL_TRUE;
- }
- if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) {
- /* this can only happen if GL_ARB_draw_buffers_blend is enabled */
- return GL_TRUE;
- }
- return GL_FALSE;
-}
-
-static void
-update_blend( struct st_context *st )
-{
- struct pipe_blend_state *blend = &st->state.blend;
- const struct gl_context *ctx = st->ctx;
- unsigned num_state = 1;
- unsigned i, j;
-
- memset(blend, 0, sizeof(*blend));
-
- if (blend_per_rt(ctx) || colormask_per_rt(ctx)) {
- num_state = ctx->Const.MaxDrawBuffers;
- blend->independent_blend_enable = 1;
- }
- /* Note it is impossible to correctly deal with EXT_blend_logic_op and
- EXT_draw_buffers2/EXT_blend_equation_separate at the same time.
- These combinations would require support for per-rt logicop enables
- and separate alpha/rgb logicop/blend support respectively. Neither
- possible in gallium nor most hardware. Assume these combinations
- don't happen. */
- if (ctx->Color.ColorLogicOpEnabled ||
- (ctx->Color.BlendEnabled &&
- ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) {
- /* logicop enabled */
- blend->logicop_enable = 1;
- blend->logicop_func = translate_logicop(ctx->Color.LogicOp);
- }
- else if (ctx->Color.BlendEnabled) {
- /* blending enabled */
- for (i = 0, j = 0; i < num_state; i++) {
-
- blend->rt[i].blend_enable = (ctx->Color.BlendEnabled >> i) & 0x1;
-
- if (ctx->Extensions.ARB_draw_buffers_blend)
- j = i;
-
- blend->rt[i].rgb_func =
- translate_blend(ctx->Color.Blend[j].EquationRGB);
-
- if (ctx->Color.Blend[i].EquationRGB == GL_MIN ||
- ctx->Color.Blend[i].EquationRGB == GL_MAX) {
- /* Min/max are special */
- blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
- blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE;
- }
- else {
- blend->rt[i].rgb_src_factor =
- translate_blend(ctx->Color.Blend[j].SrcRGB);
- blend->rt[i].rgb_dst_factor =
- translate_blend(ctx->Color.Blend[j].DstRGB);
- }
-
- blend->rt[i].alpha_func =
- translate_blend(ctx->Color.Blend[j].EquationA);
-
- if (ctx->Color.Blend[i].EquationA == GL_MIN ||
- ctx->Color.Blend[i].EquationA == GL_MAX) {
- /* Min/max are special */
- blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
- blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE;
- }
- else {
- blend->rt[i].alpha_src_factor =
- translate_blend(ctx->Color.Blend[j].SrcA);
- blend->rt[i].alpha_dst_factor =
- translate_blend(ctx->Color.Blend[j].DstA);
- }
- }
- }
- else {
- /* no blending / logicop */
- }
-
- /* Colormask - maybe reverse these bits? */
- for (i = 0; i < num_state; i++) {
- if (ctx->Color.ColorMask[i][0])
- blend->rt[i].colormask |= PIPE_MASK_R;
- if (ctx->Color.ColorMask[i][1])
- blend->rt[i].colormask |= PIPE_MASK_G;
- if (ctx->Color.ColorMask[i][2])
- blend->rt[i].colormask |= PIPE_MASK_B;
- if (ctx->Color.ColorMask[i][3])
- blend->rt[i].colormask |= PIPE_MASK_A;
- }
-
- if (ctx->Color.DitherFlag)
- blend->dither = 1;
-
- if (ctx->Multisample.Enabled) {
- /* unlike in gallium/d3d10 these operations are only performed
- if msaa is enabled */
- if (ctx->Multisample.SampleAlphaToCoverage)
- blend->alpha_to_coverage = 1;
- if (ctx->Multisample.SampleAlphaToOne)
- blend->alpha_to_one = 1;
- }
-
- cso_set_blend(st->cso_context, blend);
-
- {
- struct pipe_blend_color bc;
- COPY_4FV(bc.color, ctx->Color.BlendColorUnclamped);
- cso_set_blend_color(st->cso_context, &bc);
- }
-}
-
-
-const struct st_tracked_state st_update_blend = {
- "st_update_blend", /* name */
- { /* dirty */
- (_NEW_COLOR | _NEW_MULTISAMPLE), /* XXX _NEW_BLEND someday? */ /* mesa */
- 0, /* st */
- },
- update_blend, /* update */
-};
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + + +#include "st_context.h" +#include "st_atom.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "cso_cache/cso_context.h" + +#include "main/macros.h" + +/** + * Convert GLenum blend tokens to pipe tokens. + * Both blend factors and blend funcs are accepted. + */ +static GLuint +translate_blend(GLenum blend) +{ + switch (blend) { + /* blend functions */ + case GL_FUNC_ADD: + return PIPE_BLEND_ADD; + case GL_FUNC_SUBTRACT: + return PIPE_BLEND_SUBTRACT; + case GL_FUNC_REVERSE_SUBTRACT: + return PIPE_BLEND_REVERSE_SUBTRACT; + case GL_MIN: + return PIPE_BLEND_MIN; + case GL_MAX: + return PIPE_BLEND_MAX; + + /* blend factors */ + case GL_ONE: + return PIPE_BLENDFACTOR_ONE; + case GL_SRC_COLOR: + return PIPE_BLENDFACTOR_SRC_COLOR; + case GL_SRC_ALPHA: + return PIPE_BLENDFACTOR_SRC_ALPHA; + case GL_DST_ALPHA: + return PIPE_BLENDFACTOR_DST_ALPHA; + case GL_DST_COLOR: + return PIPE_BLENDFACTOR_DST_COLOR; + case GL_SRC_ALPHA_SATURATE: + return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE; + case GL_CONSTANT_COLOR: + return PIPE_BLENDFACTOR_CONST_COLOR; + case GL_CONSTANT_ALPHA: + return PIPE_BLENDFACTOR_CONST_ALPHA; + /* + return PIPE_BLENDFACTOR_SRC1_COLOR; + return PIPE_BLENDFACTOR_SRC1_ALPHA; + */ + case GL_ZERO: + return PIPE_BLENDFACTOR_ZERO; + case GL_ONE_MINUS_SRC_COLOR: + return PIPE_BLENDFACTOR_INV_SRC_COLOR; + case GL_ONE_MINUS_SRC_ALPHA: + return PIPE_BLENDFACTOR_INV_SRC_ALPHA; + case GL_ONE_MINUS_DST_COLOR: + return PIPE_BLENDFACTOR_INV_DST_COLOR; + case GL_ONE_MINUS_DST_ALPHA: + return PIPE_BLENDFACTOR_INV_DST_ALPHA; + case GL_ONE_MINUS_CONSTANT_COLOR: + return PIPE_BLENDFACTOR_INV_CONST_COLOR; + case GL_ONE_MINUS_CONSTANT_ALPHA: + return PIPE_BLENDFACTOR_INV_CONST_ALPHA; + /* + return PIPE_BLENDFACTOR_INV_SRC1_COLOR; + return PIPE_BLENDFACTOR_INV_SRC1_ALPHA; + */ + default: + assert("invalid GL token in translate_blend()" == NULL); + return 0; + } +} + + +/** + * Convert GLenum logicop tokens to pipe tokens. + */ +static GLuint +translate_logicop(GLenum logicop) +{ + switch (logicop) { + case GL_CLEAR: + return PIPE_LOGICOP_CLEAR; + case GL_NOR: + return PIPE_LOGICOP_NOR; + case GL_AND_INVERTED: + return PIPE_LOGICOP_AND_INVERTED; + case GL_COPY_INVERTED: + return PIPE_LOGICOP_COPY_INVERTED; + case GL_AND_REVERSE: + return PIPE_LOGICOP_AND_REVERSE; + case GL_INVERT: + return PIPE_LOGICOP_INVERT; + case GL_XOR: + return PIPE_LOGICOP_XOR; + case GL_NAND: + return PIPE_LOGICOP_NAND; + case GL_AND: + return PIPE_LOGICOP_AND; + case GL_EQUIV: + return PIPE_LOGICOP_EQUIV; + case GL_NOOP: + return PIPE_LOGICOP_NOOP; + case GL_OR_INVERTED: + return PIPE_LOGICOP_OR_INVERTED; + case GL_COPY: + return PIPE_LOGICOP_COPY; + case GL_OR_REVERSE: + return PIPE_LOGICOP_OR_REVERSE; + case GL_OR: + return PIPE_LOGICOP_OR; + case GL_SET: + return PIPE_LOGICOP_SET; + default: + assert("invalid GL token in translate_logicop()" == NULL); + return 0; + } +} + +/** + * Figure out if colormasks are different per rt. + */ +static GLboolean +colormask_per_rt(const struct gl_context *ctx) +{ + /* a bit suboptimal have to compare lots of values */ + unsigned i; + for (i = 1; i < ctx->Const.MaxDrawBuffers; i++) { + if (memcmp(ctx->Color.ColorMask[0], ctx->Color.ColorMask[i], 4)) { + return GL_TRUE; + } + } + return GL_FALSE; +} + +/** + * Figure out if blend enables/state are different per rt. + */ +static GLboolean +blend_per_rt(const struct gl_context *ctx) +{ + if (ctx->Color.BlendEnabled && + (ctx->Color.BlendEnabled != ((1 << ctx->Const.MaxDrawBuffers) - 1))) { + /* This can only happen if GL_EXT_draw_buffers2 is enabled */ + return GL_TRUE; + } + if (ctx->Color._BlendFuncPerBuffer || ctx->Color._BlendEquationPerBuffer) { + /* this can only happen if GL_ARB_draw_buffers_blend is enabled */ + return GL_TRUE; + } + return GL_FALSE; +} + +static void +update_blend( struct st_context *st ) +{ + struct pipe_blend_state *blend = &st->state.blend; + const struct gl_context *ctx = st->ctx; + unsigned num_state = 1; + unsigned i, j; + + memset(blend, 0, sizeof(*blend)); + + if (blend_per_rt(ctx) || colormask_per_rt(ctx)) { + num_state = ctx->Const.MaxDrawBuffers; + blend->independent_blend_enable = 1; + } + /* Note it is impossible to correctly deal with EXT_blend_logic_op and + EXT_draw_buffers2/EXT_blend_equation_separate at the same time. + These combinations would require support for per-rt logicop enables + and separate alpha/rgb logicop/blend support respectively. Neither + possible in gallium nor most hardware. Assume these combinations + don't happen. */ + if (ctx->Color.ColorLogicOpEnabled || + (ctx->Color.BlendEnabled && + ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) { + /* logicop enabled */ + blend->logicop_enable = 1; + blend->logicop_func = translate_logicop(ctx->Color.LogicOp); + } + else if (ctx->Color.BlendEnabled) { + /* blending enabled */ + for (i = 0, j = 0; i < num_state; i++) { + + blend->rt[i].blend_enable = (ctx->Color.BlendEnabled >> i) & 0x1; + + if (ctx->Extensions.ARB_draw_buffers_blend) + j = i; + + blend->rt[i].rgb_func = + translate_blend(ctx->Color.Blend[j].EquationRGB); + + if (ctx->Color.Blend[i].EquationRGB == GL_MIN || + ctx->Color.Blend[i].EquationRGB == GL_MAX) { + /* Min/max are special */ + blend->rt[i].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rt[i].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; + } + else { + blend->rt[i].rgb_src_factor = + translate_blend(ctx->Color.Blend[j].SrcRGB); + blend->rt[i].rgb_dst_factor = + translate_blend(ctx->Color.Blend[j].DstRGB); + } + + blend->rt[i].alpha_func = + translate_blend(ctx->Color.Blend[j].EquationA); + + if (ctx->Color.Blend[i].EquationA == GL_MIN || + ctx->Color.Blend[i].EquationA == GL_MAX) { + /* Min/max are special */ + blend->rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend->rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; + } + else { + blend->rt[i].alpha_src_factor = + translate_blend(ctx->Color.Blend[j].SrcA); + blend->rt[i].alpha_dst_factor = + translate_blend(ctx->Color.Blend[j].DstA); + } + } + } + else { + /* no blending / logicop */ + } + + /* Colormask - maybe reverse these bits? */ + for (i = 0; i < num_state; i++) { + if (ctx->Color.ColorMask[i][0]) + blend->rt[i].colormask |= PIPE_MASK_R; + if (ctx->Color.ColorMask[i][1]) + blend->rt[i].colormask |= PIPE_MASK_G; + if (ctx->Color.ColorMask[i][2]) + blend->rt[i].colormask |= PIPE_MASK_B; + if (ctx->Color.ColorMask[i][3]) + blend->rt[i].colormask |= PIPE_MASK_A; + } + + if (ctx->Color.DitherFlag) + blend->dither = 1; + + if (ctx->Multisample.Enabled) { + /* unlike in gallium/d3d10 these operations are only performed + if msaa is enabled */ + if (ctx->Multisample.SampleAlphaToCoverage) + blend->alpha_to_coverage = 1; + if (ctx->Multisample.SampleAlphaToOne) + blend->alpha_to_one = 1; + } + + cso_set_blend(st->cso_context, blend); + + { + struct pipe_blend_color bc; + COPY_4FV(bc.color, ctx->Color.BlendColorUnclamped); + cso_set_blend_color(st->cso_context, &bc); + } +} + + +const struct st_tracked_state st_update_blend = { + "st_update_blend", /* name */ + { /* dirty */ + (_NEW_COLOR | _NEW_MULTISAMPLE), /* XXX _NEW_BLEND someday? */ /* mesa */ + 0, /* st */ + }, + update_blend, /* update */ +}; diff --git a/mesalib/src/mesa/state_tracker/st_atom_depth.c b/mesalib/src/mesa/state_tracker/st_atom_depth.c index 524f8986f..6c51b1ac1 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_depth.c +++ b/mesalib/src/mesa/state_tracker/st_atom_depth.c @@ -1,160 +1,160 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
- /*
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Brian Paul
- * Zack Rusin
- */
-
-
-#include <assert.h>
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "cso_cache/cso_context.h"
-
-
-/**
- * Convert an OpenGL compare mode to a pipe tokens.
- */
-GLuint
-st_compare_func_to_pipe(GLenum func)
-{
- /* Same values, just biased */
- assert(PIPE_FUNC_NEVER == GL_NEVER - GL_NEVER);
- assert(PIPE_FUNC_LESS == GL_LESS - GL_NEVER);
- assert(PIPE_FUNC_EQUAL == GL_EQUAL - GL_NEVER);
- assert(PIPE_FUNC_LEQUAL == GL_LEQUAL - GL_NEVER);
- assert(PIPE_FUNC_GREATER == GL_GREATER - GL_NEVER);
- assert(PIPE_FUNC_NOTEQUAL == GL_NOTEQUAL - GL_NEVER);
- assert(PIPE_FUNC_GEQUAL == GL_GEQUAL - GL_NEVER);
- assert(PIPE_FUNC_ALWAYS == GL_ALWAYS - GL_NEVER);
- assert(func >= GL_NEVER);
- assert(func <= GL_ALWAYS);
- return func - GL_NEVER;
-}
-
-
-/**
- * Convert GLenum stencil op tokens to pipe tokens.
- */
-static GLuint
-gl_stencil_op_to_pipe(GLenum func)
-{
- switch (func) {
- case GL_KEEP:
- return PIPE_STENCIL_OP_KEEP;
- case GL_ZERO:
- return PIPE_STENCIL_OP_ZERO;
- case GL_REPLACE:
- return PIPE_STENCIL_OP_REPLACE;
- case GL_INCR:
- return PIPE_STENCIL_OP_INCR;
- case GL_DECR:
- return PIPE_STENCIL_OP_DECR;
- case GL_INCR_WRAP:
- return PIPE_STENCIL_OP_INCR_WRAP;
- case GL_DECR_WRAP:
- return PIPE_STENCIL_OP_DECR_WRAP;
- case GL_INVERT:
- return PIPE_STENCIL_OP_INVERT;
- default:
- assert("invalid GL token in gl_stencil_op_to_pipe()" == NULL);
- return 0;
- }
-}
-
-static void
-update_depth_stencil_alpha(struct st_context *st)
-{
- struct pipe_depth_stencil_alpha_state *dsa = &st->state.depth_stencil;
- struct pipe_stencil_ref sr;
- struct gl_context *ctx = st->ctx;
-
- memset(dsa, 0, sizeof(*dsa));
- memset(&sr, 0, sizeof(sr));
-
- if (ctx->Depth.Test && ctx->DrawBuffer->Visual.depthBits > 0) {
- dsa->depth.enabled = 1;
- dsa->depth.writemask = ctx->Depth.Mask;
- dsa->depth.func = st_compare_func_to_pipe(ctx->Depth.Func);
- }
-
- if (ctx->Stencil.Enabled && ctx->DrawBuffer->Visual.stencilBits > 0) {
- dsa->stencil[0].enabled = 1;
- dsa->stencil[0].func = st_compare_func_to_pipe(ctx->Stencil.Function[0]);
- dsa->stencil[0].fail_op = gl_stencil_op_to_pipe(ctx->Stencil.FailFunc[0]);
- dsa->stencil[0].zfail_op = gl_stencil_op_to_pipe(ctx->Stencil.ZFailFunc[0]);
- dsa->stencil[0].zpass_op = gl_stencil_op_to_pipe(ctx->Stencil.ZPassFunc[0]);
- dsa->stencil[0].valuemask = ctx->Stencil.ValueMask[0] & 0xff;
- dsa->stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
- sr.ref_value[0] = ctx->Stencil.Ref[0] & 0xff;
-
- if (ctx->Stencil._TestTwoSide) {
- const GLuint back = ctx->Stencil._BackFace;
- dsa->stencil[1].enabled = 1;
- dsa->stencil[1].func = st_compare_func_to_pipe(ctx->Stencil.Function[back]);
- dsa->stencil[1].fail_op = gl_stencil_op_to_pipe(ctx->Stencil.FailFunc[back]);
- dsa->stencil[1].zfail_op = gl_stencil_op_to_pipe(ctx->Stencil.ZFailFunc[back]);
- dsa->stencil[1].zpass_op = gl_stencil_op_to_pipe(ctx->Stencil.ZPassFunc[back]);
- dsa->stencil[1].valuemask = ctx->Stencil.ValueMask[back] & 0xff;
- dsa->stencil[1].writemask = ctx->Stencil.WriteMask[back] & 0xff;
- sr.ref_value[1] = ctx->Stencil.Ref[back] & 0xff;
- }
- else {
- /* This should be unnecessary. Drivers must not expect this to
- * contain valid data, except the enabled bit
- */
- dsa->stencil[1] = dsa->stencil[0];
- dsa->stencil[1].enabled = 0;
- sr.ref_value[1] = sr.ref_value[0];
- }
- }
-
- if (ctx->Color.AlphaEnabled) {
- dsa->alpha.enabled = 1;
- dsa->alpha.func = st_compare_func_to_pipe(ctx->Color.AlphaFunc);
- dsa->alpha.ref_value = ctx->Color.AlphaRefUnclamped;
- }
-
- cso_set_depth_stencil_alpha(st->cso_context, dsa);
- cso_set_stencil_ref(st->cso_context, &sr);
-}
-
-
-const struct st_tracked_state st_update_depth_stencil_alpha = {
- "st_update_depth_stencil", /* name */
- { /* dirty */
- (_NEW_DEPTH|_NEW_STENCIL|_NEW_COLOR), /* mesa */
- 0, /* st */
- },
- update_depth_stencil_alpha /* update */
-};
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + * Zack Rusin + */ + + +#include <assert.h> + +#include "st_context.h" +#include "st_atom.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "cso_cache/cso_context.h" + + +/** + * Convert an OpenGL compare mode to a pipe tokens. + */ +GLuint +st_compare_func_to_pipe(GLenum func) +{ + /* Same values, just biased */ + assert(PIPE_FUNC_NEVER == GL_NEVER - GL_NEVER); + assert(PIPE_FUNC_LESS == GL_LESS - GL_NEVER); + assert(PIPE_FUNC_EQUAL == GL_EQUAL - GL_NEVER); + assert(PIPE_FUNC_LEQUAL == GL_LEQUAL - GL_NEVER); + assert(PIPE_FUNC_GREATER == GL_GREATER - GL_NEVER); + assert(PIPE_FUNC_NOTEQUAL == GL_NOTEQUAL - GL_NEVER); + assert(PIPE_FUNC_GEQUAL == GL_GEQUAL - GL_NEVER); + assert(PIPE_FUNC_ALWAYS == GL_ALWAYS - GL_NEVER); + assert(func >= GL_NEVER); + assert(func <= GL_ALWAYS); + return func - GL_NEVER; +} + + +/** + * Convert GLenum stencil op tokens to pipe tokens. + */ +static GLuint +gl_stencil_op_to_pipe(GLenum func) +{ + switch (func) { + case GL_KEEP: + return PIPE_STENCIL_OP_KEEP; + case GL_ZERO: + return PIPE_STENCIL_OP_ZERO; + case GL_REPLACE: + return PIPE_STENCIL_OP_REPLACE; + case GL_INCR: + return PIPE_STENCIL_OP_INCR; + case GL_DECR: + return PIPE_STENCIL_OP_DECR; + case GL_INCR_WRAP: + return PIPE_STENCIL_OP_INCR_WRAP; + case GL_DECR_WRAP: + return PIPE_STENCIL_OP_DECR_WRAP; + case GL_INVERT: + return PIPE_STENCIL_OP_INVERT; + default: + assert("invalid GL token in gl_stencil_op_to_pipe()" == NULL); + return 0; + } +} + +static void +update_depth_stencil_alpha(struct st_context *st) +{ + struct pipe_depth_stencil_alpha_state *dsa = &st->state.depth_stencil; + struct pipe_stencil_ref sr; + struct gl_context *ctx = st->ctx; + + memset(dsa, 0, sizeof(*dsa)); + memset(&sr, 0, sizeof(sr)); + + if (ctx->Depth.Test && ctx->DrawBuffer->Visual.depthBits > 0) { + dsa->depth.enabled = 1; + dsa->depth.writemask = ctx->Depth.Mask; + dsa->depth.func = st_compare_func_to_pipe(ctx->Depth.Func); + } + + if (ctx->Stencil.Enabled && ctx->DrawBuffer->Visual.stencilBits > 0) { + dsa->stencil[0].enabled = 1; + dsa->stencil[0].func = st_compare_func_to_pipe(ctx->Stencil.Function[0]); + dsa->stencil[0].fail_op = gl_stencil_op_to_pipe(ctx->Stencil.FailFunc[0]); + dsa->stencil[0].zfail_op = gl_stencil_op_to_pipe(ctx->Stencil.ZFailFunc[0]); + dsa->stencil[0].zpass_op = gl_stencil_op_to_pipe(ctx->Stencil.ZPassFunc[0]); + dsa->stencil[0].valuemask = ctx->Stencil.ValueMask[0] & 0xff; + dsa->stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; + sr.ref_value[0] = ctx->Stencil.Ref[0] & 0xff; + + if (ctx->Stencil._TestTwoSide) { + const GLuint back = ctx->Stencil._BackFace; + dsa->stencil[1].enabled = 1; + dsa->stencil[1].func = st_compare_func_to_pipe(ctx->Stencil.Function[back]); + dsa->stencil[1].fail_op = gl_stencil_op_to_pipe(ctx->Stencil.FailFunc[back]); + dsa->stencil[1].zfail_op = gl_stencil_op_to_pipe(ctx->Stencil.ZFailFunc[back]); + dsa->stencil[1].zpass_op = gl_stencil_op_to_pipe(ctx->Stencil.ZPassFunc[back]); + dsa->stencil[1].valuemask = ctx->Stencil.ValueMask[back] & 0xff; + dsa->stencil[1].writemask = ctx->Stencil.WriteMask[back] & 0xff; + sr.ref_value[1] = ctx->Stencil.Ref[back] & 0xff; + } + else { + /* This should be unnecessary. Drivers must not expect this to + * contain valid data, except the enabled bit + */ + dsa->stencil[1] = dsa->stencil[0]; + dsa->stencil[1].enabled = 0; + sr.ref_value[1] = sr.ref_value[0]; + } + } + + if (ctx->Color.AlphaEnabled) { + dsa->alpha.enabled = 1; + dsa->alpha.func = st_compare_func_to_pipe(ctx->Color.AlphaFunc); + dsa->alpha.ref_value = ctx->Color.AlphaRefUnclamped; + } + + cso_set_depth_stencil_alpha(st->cso_context, dsa); + cso_set_stencil_ref(st->cso_context, &sr); +} + + +const struct st_tracked_state st_update_depth_stencil_alpha = { + "st_update_depth_stencil", /* name */ + { /* dirty */ + (_NEW_DEPTH|_NEW_STENCIL|_NEW_COLOR), /* mesa */ + 0, /* st */ + }, + update_depth_stencil_alpha /* update */ +}; diff --git a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c index 678a270c7..76386fe01 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c +++ b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c @@ -1,182 +1,182 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
- /*
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Brian Paul
- */
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_fbo.h"
-#include "st_texture.h"
-#include "pipe/p_context.h"
-#include "cso_cache/cso_context.h"
-#include "util/u_math.h"
-#include "util/u_inlines.h"
-#include "util/u_format.h"
-
-
-/**
- * When doing GL render to texture, we have to be sure that finalize_texture()
- * didn't yank out the pipe_resource that we earlier created a surface for.
- * Check for that here and create a new surface if needed.
- */
-static void
-update_renderbuffer_surface(struct st_context *st,
- struct st_renderbuffer *strb)
-{
- struct pipe_context *pipe = st->pipe;
- struct pipe_resource *resource = strb->rtt->pt;
- int rtt_width = strb->Base.Width;
- int rtt_height = strb->Base.Height;
- enum pipe_format format = st->ctx->Color.sRGBEnabled ? resource->format : util_format_linear(resource->format);
-
- if (!strb->surface ||
- strb->surface->format != format ||
- strb->surface->texture != resource ||
- strb->surface->width != rtt_width ||
- strb->surface->height != rtt_height) {
- GLuint level;
- /* find matching mipmap level size */
- for (level = 0; level <= resource->last_level; level++) {
- if (u_minify(resource->width0, level) == rtt_width &&
- u_minify(resource->height0, level) == rtt_height) {
- struct pipe_surface surf_tmpl;
- memset(&surf_tmpl, 0, sizeof(surf_tmpl));
- surf_tmpl.format = format;
- surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
- surf_tmpl.u.tex.level = level;
- surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
- surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
-
- pipe_surface_reference(&strb->surface, NULL);
-
- strb->surface = pipe->create_surface(pipe,
- resource,
- &surf_tmpl);
-#if 0
- printf("-- alloc new surface %d x %d into tex %p\n",
- strb->surface->width, strb->surface->height,
- texture);
-#endif
- break;
- }
- }
- }
-}
-
-
-/**
- * Update framebuffer state (color, depth, stencil, etc. buffers)
- */
-static void
-update_framebuffer_state( struct st_context *st )
-{
- struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer;
- struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- struct st_renderbuffer *strb;
- GLuint i;
-
- framebuffer->width = fb->Width;
- framebuffer->height = fb->Height;
-
- /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/
-
- /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
- * to determine which surfaces to draw to
- */
- framebuffer->nr_cbufs = 0;
- for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
- strb = st_renderbuffer(fb->_ColorDrawBuffers[i]);
-
- if (strb) {
- /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/
- if (strb->rtt) {
- /* rendering to a GL texture, may have to update surface */
- update_renderbuffer_surface(st, strb);
- }
-
- if (strb->surface) {
- pipe_surface_reference(&framebuffer->cbufs[framebuffer->nr_cbufs],
- strb->surface);
- framebuffer->nr_cbufs++;
- }
- strb->defined = GL_TRUE; /* we'll be drawing something */
- }
- }
- for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) {
- pipe_surface_reference(&framebuffer->cbufs[i], NULL);
- }
-
- /*
- * Depth/Stencil renderbuffer/surface.
- */
- strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer);
- if (strb) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- if (strb->rtt) {
- /* rendering to a GL texture, may have to update surface */
- update_renderbuffer_surface(st, strb);
- }
- pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
- }
- else {
- strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer);
- if (strb) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- assert(strb->surface);
- pipe_surface_reference(&framebuffer->zsbuf, strb->surface);
- }
- else
- pipe_surface_reference(&framebuffer->zsbuf, NULL);
- }
-
-#ifdef DEBUG
- /* Make sure the resource binding flags were set properly */
- for (i = 0; i < framebuffer->nr_cbufs; i++) {
- assert(framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
- }
- if (framebuffer->zsbuf) {
- assert(framebuffer->zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL);
- }
-#endif
-
- cso_set_framebuffer(st->cso_context, framebuffer);
-}
-
-
-const struct st_tracked_state st_update_framebuffer = {
- "st_update_framebuffer", /* name */
- { /* dirty */
- _NEW_BUFFERS, /* mesa */
- ST_NEW_FRAMEBUFFER, /* st */
- },
- update_framebuffer_state /* update */
-};
-
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_fbo.h" +#include "st_texture.h" +#include "pipe/p_context.h" +#include "cso_cache/cso_context.h" +#include "util/u_math.h" +#include "util/u_inlines.h" +#include "util/u_format.h" + + +/** + * When doing GL render to texture, we have to be sure that finalize_texture() + * didn't yank out the pipe_resource that we earlier created a surface for. + * Check for that here and create a new surface if needed. + */ +static void +update_renderbuffer_surface(struct st_context *st, + struct st_renderbuffer *strb) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_resource *resource = strb->rtt->pt; + int rtt_width = strb->Base.Width; + int rtt_height = strb->Base.Height; + enum pipe_format format = st->ctx->Color.sRGBEnabled ? resource->format : util_format_linear(resource->format); + + if (!strb->surface || + strb->surface->format != format || + strb->surface->texture != resource || + strb->surface->width != rtt_width || + strb->surface->height != rtt_height) { + GLuint level; + /* find matching mipmap level size */ + for (level = 0; level <= resource->last_level; level++) { + if (u_minify(resource->width0, level) == rtt_width && + u_minify(resource->height0, level) == rtt_height) { + struct pipe_surface surf_tmpl; + memset(&surf_tmpl, 0, sizeof(surf_tmpl)); + surf_tmpl.format = format; + surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; + surf_tmpl.u.tex.level = level; + surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice; + surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice; + + pipe_surface_reference(&strb->surface, NULL); + + strb->surface = pipe->create_surface(pipe, + resource, + &surf_tmpl); +#if 0 + printf("-- alloc new surface %d x %d into tex %p\n", + strb->surface->width, strb->surface->height, + texture); +#endif + break; + } + } + } +} + + +/** + * Update framebuffer state (color, depth, stencil, etc. buffers) + */ +static void +update_framebuffer_state( struct st_context *st ) +{ + struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer; + struct gl_framebuffer *fb = st->ctx->DrawBuffer; + struct st_renderbuffer *strb; + GLuint i; + + framebuffer->width = fb->Width; + framebuffer->height = fb->Height; + + /*printf("------ fb size %d x %d\n", fb->Width, fb->Height);*/ + + /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state + * to determine which surfaces to draw to + */ + framebuffer->nr_cbufs = 0; + for (i = 0; i < fb->_NumColorDrawBuffers; i++) { + strb = st_renderbuffer(fb->_ColorDrawBuffers[i]); + + if (strb) { + /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/ + if (strb->rtt) { + /* rendering to a GL texture, may have to update surface */ + update_renderbuffer_surface(st, strb); + } + + if (strb->surface) { + pipe_surface_reference(&framebuffer->cbufs[framebuffer->nr_cbufs], + strb->surface); + framebuffer->nr_cbufs++; + } + strb->defined = GL_TRUE; /* we'll be drawing something */ + } + } + for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) { + pipe_surface_reference(&framebuffer->cbufs[i], NULL); + } + + /* + * Depth/Stencil renderbuffer/surface. + */ + strb = st_renderbuffer(fb->Attachment[BUFFER_DEPTH].Renderbuffer); + if (strb) { + strb = st_renderbuffer(strb->Base.Wrapped); + if (strb->rtt) { + /* rendering to a GL texture, may have to update surface */ + update_renderbuffer_surface(st, strb); + } + pipe_surface_reference(&framebuffer->zsbuf, strb->surface); + } + else { + strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer); + if (strb) { + strb = st_renderbuffer(strb->Base.Wrapped); + assert(strb->surface); + pipe_surface_reference(&framebuffer->zsbuf, strb->surface); + } + else + pipe_surface_reference(&framebuffer->zsbuf, NULL); + } + +#ifdef DEBUG + /* Make sure the resource binding flags were set properly */ + for (i = 0; i < framebuffer->nr_cbufs; i++) { + assert(framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET); + } + if (framebuffer->zsbuf) { + assert(framebuffer->zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL); + } +#endif + + cso_set_framebuffer(st->cso_context, framebuffer); +} + + +const struct st_tracked_state st_update_framebuffer = { + "st_update_framebuffer", /* name */ + { /* dirty */ + _NEW_BUFFERS, /* mesa */ + ST_NEW_FRAMEBUFFER, /* st */ + }, + update_framebuffer_state /* update */ +}; + diff --git a/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c b/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c index 420e6c1b0..12b5bc5ba 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c +++ b/mesalib/src/mesa/state_tracker/st_atom_pixeltransfer.c @@ -1,324 +1,324 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-/*
- * Generate fragment programs to implement pixel transfer ops, such as
- * scale/bias, colortable, convolution...
- *
- * Authors:
- * Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "program/program.h"
-#include "program/prog_cache.h"
-#include "program/prog_instruction.h"
-#include "program/prog_parameter.h"
-#include "program/prog_print.h"
-
-#include "st_context.h"
-#include "st_format.h"
-#include "st_texture.h"
-
-#include "pipe/p_screen.h"
-#include "pipe/p_context.h"
-#include "util/u_inlines.h"
-#include "util/u_pack_color.h"
-
-
-struct state_key
-{
- GLuint scaleAndBias:1;
- GLuint pixelMaps:1;
-
-#if 0
- GLfloat Maps[3][256][4];
- int NumMaps;
- GLint NumStages;
- pipeline_stage Stages[STAGE_MAX];
- GLboolean StagesUsed[STAGE_MAX];
- GLfloat Scale1[4], Bias1[4];
- GLfloat Scale2[4], Bias2[4];
-#endif
-};
-
-static void
-make_state_key(struct gl_context *ctx, struct state_key *key)
-{
- memset(key, 0, sizeof(*key));
-
- if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 ||
- ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 ||
- ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 ||
- ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) {
- key->scaleAndBias = 1;
- }
-
- key->pixelMaps = ctx->Pixel.MapColorFlag;
-}
-
-
-/**
- * Update the pixelmap texture with the contents of the R/G/B/A pixel maps.
- */
-static void
-load_color_map_texture(struct gl_context *ctx, struct pipe_resource *pt)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_transfer *transfer;
- const GLuint rSize = ctx->PixelMaps.RtoR.Size;
- const GLuint gSize = ctx->PixelMaps.GtoG.Size;
- const GLuint bSize = ctx->PixelMaps.BtoB.Size;
- const GLuint aSize = ctx->PixelMaps.AtoA.Size;
- const uint texSize = pt->width0;
- uint *dest;
- uint i, j;
-
- transfer = pipe_get_transfer(pipe,
- pt, 0, 0, PIPE_TRANSFER_WRITE,
- 0, 0, texSize, texSize);
- dest = (uint *) pipe_transfer_map(pipe, transfer);
-
- /* Pack four 1D maps into a 2D texture:
- * R map is placed horizontally, indexed by S, in channel 0
- * G map is placed vertically, indexed by T, in channel 1
- * B map is placed horizontally, indexed by S, in channel 2
- * A map is placed vertically, indexed by T, in channel 3
- */
- for (i = 0; i < texSize; i++) {
- for (j = 0; j < texSize; j++) {
- union util_color uc;
- int k = (i * texSize + j);
- ubyte r = ctx->PixelMaps.RtoR.Map8[j * rSize / texSize];
- ubyte g = ctx->PixelMaps.GtoG.Map8[i * gSize / texSize];
- ubyte b = ctx->PixelMaps.BtoB.Map8[j * bSize / texSize];
- ubyte a = ctx->PixelMaps.AtoA.Map8[i * aSize / texSize];
- util_pack_color_ub(r, g, b, a, pt->format, &uc);
- *(dest + k) = uc.ui;
- }
- }
-
- pipe_transfer_unmap(pipe, transfer);
- pipe->transfer_destroy(pipe, transfer);
-}
-
-
-
-#define MAX_INST 100
-
-/**
- * Returns a fragment program which implements the current pixel transfer ops.
- */
-static struct gl_fragment_program *
-get_pixel_transfer_program(struct gl_context *ctx, const struct state_key *key)
-{
- struct st_context *st = st_context(ctx);
- struct prog_instruction inst[MAX_INST];
- struct gl_program_parameter_list *params;
- struct gl_fragment_program *fp;
- GLuint ic = 0;
- const GLuint colorTemp = 0;
-
- fp = (struct gl_fragment_program *)
- ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
- if (!fp)
- return NULL;
-
- params = _mesa_new_parameter_list();
-
- /*
- * Get initial pixel color from the texture.
- * TEX colorTemp, fragment.texcoord[0], texture[0], 2D;
- */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_TEX;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = colorTemp;
- inst[ic].SrcReg[0].File = PROGRAM_INPUT;
- inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
- inst[ic].TexSrcUnit = 0;
- inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
- fp->Base.InputsRead = (1 << FRAG_ATTRIB_TEX0);
- fp->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
- fp->Base.SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */
-
- if (key->scaleAndBias) {
- static const gl_state_index scale_state[STATE_LENGTH] =
- { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 };
- static const gl_state_index bias_state[STATE_LENGTH] =
- { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 };
- GLint scale_p, bias_p;
-
- scale_p = _mesa_add_state_reference(params, scale_state);
- bias_p = _mesa_add_state_reference(params, bias_state);
-
- /* MAD colorTemp, colorTemp, scale, bias; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_MAD;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = colorTemp;
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = colorTemp;
- inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR;
- inst[ic].SrcReg[1].Index = scale_p;
- inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR;
- inst[ic].SrcReg[2].Index = bias_p;
- ic++;
- }
-
- if (key->pixelMaps) {
- const GLuint temp = 1;
-
- /* create the colormap/texture now if not already done */
- if (!st->pixel_xfer.pixelmap_texture) {
- st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx);
- st->pixel_xfer.pixelmap_sampler_view =
- st_create_texture_sampler_view(st->pipe,
- st->pixel_xfer.pixelmap_texture);
- }
-
- /* with a little effort, we can do four pixel map look-ups with
- * two TEX instructions:
- */
-
- /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_TEX;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = temp;
- inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = colorTemp;
- inst[ic].TexSrcUnit = 1;
- inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
-
- /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_TEX;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = temp;
- inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = colorTemp;
- inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W,
- SWIZZLE_Z, SWIZZLE_W);
- inst[ic].TexSrcUnit = 1;
- inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
-
- /* MOV colorTemp, temp; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_MOV;
- inst[ic].DstReg.File = PROGRAM_TEMPORARY;
- inst[ic].DstReg.Index = colorTemp;
- inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
- inst[ic].SrcReg[0].Index = temp;
- ic++;
-
- fp->Base.SamplersUsed |= (1 << 1); /* sampler 1 is used */
- }
-
- /* Modify last instruction's dst reg to write to result.color */
- {
- struct prog_instruction *last = &inst[ic - 1];
- last->DstReg.File = PROGRAM_OUTPUT;
- last->DstReg.Index = FRAG_RESULT_COLOR;
- }
-
- /* END; */
- _mesa_init_instructions(inst + ic, 1);
- inst[ic].Opcode = OPCODE_END;
- ic++;
-
- assert(ic <= MAX_INST);
-
-
- fp->Base.Instructions = _mesa_alloc_instructions(ic);
- if (!fp->Base.Instructions) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY,
- "generating pixel transfer program");
- return NULL;
- }
-
- _mesa_copy_instructions(fp->Base.Instructions, inst, ic);
- fp->Base.NumInstructions = ic;
- fp->Base.Parameters = params;
-
-#if 0
- printf("========= pixel transfer prog\n");
- _mesa_print_program(&fp->Base);
- _mesa_print_parameter_list(fp->Base.Parameters);
-#endif
-
- return fp;
-}
-
-
-
-/**
- * Update st->pixel_xfer.program in response to new pixel-transfer state.
- */
-static void
-update_pixel_transfer(struct st_context *st)
-{
- struct gl_context *ctx = st->ctx;
- struct state_key key;
- struct gl_fragment_program *fp;
-
- make_state_key(st->ctx, &key);
-
- fp = (struct gl_fragment_program *)
- _mesa_search_program_cache(st->pixel_xfer.cache, &key, sizeof(key));
- if (!fp) {
- fp = get_pixel_transfer_program(st->ctx, &key);
- _mesa_program_cache_insert(st->ctx, st->pixel_xfer.cache,
- &key, sizeof(key), &fp->Base);
- }
-
- if (ctx->Pixel.MapColorFlag) {
- load_color_map_texture(ctx, st->pixel_xfer.pixelmap_texture);
- }
- st->pixel_xfer.pixelmap_enabled = ctx->Pixel.MapColorFlag;
-
- st->pixel_xfer.program = (struct st_fragment_program *) fp;
-}
-
-
-
-const struct st_tracked_state st_update_pixel_transfer = {
- "st_update_pixel_transfer", /* name */
- { /* dirty */
- _NEW_PIXEL, /* mesa */
- 0, /* st */
- },
- update_pixel_transfer /* update */
-};
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + +/* + * Generate fragment programs to implement pixel transfer ops, such as + * scale/bias, colortable, convolution... + * + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "program/program.h" +#include "program/prog_cache.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" + +#include "st_context.h" +#include "st_format.h" +#include "st_texture.h" + +#include "pipe/p_screen.h" +#include "pipe/p_context.h" +#include "util/u_inlines.h" +#include "util/u_pack_color.h" + + +struct state_key +{ + GLuint scaleAndBias:1; + GLuint pixelMaps:1; + +#if 0 + GLfloat Maps[3][256][4]; + int NumMaps; + GLint NumStages; + pipeline_stage Stages[STAGE_MAX]; + GLboolean StagesUsed[STAGE_MAX]; + GLfloat Scale1[4], Bias1[4]; + GLfloat Scale2[4], Bias2[4]; +#endif +}; + +static void +make_state_key(struct gl_context *ctx, struct state_key *key) +{ + memset(key, 0, sizeof(*key)); + + if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 || + ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 || + ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 || + ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) { + key->scaleAndBias = 1; + } + + key->pixelMaps = ctx->Pixel.MapColorFlag; +} + + +/** + * Update the pixelmap texture with the contents of the R/G/B/A pixel maps. + */ +static void +load_color_map_texture(struct gl_context *ctx, struct pipe_resource *pt) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_transfer *transfer; + const GLuint rSize = ctx->PixelMaps.RtoR.Size; + const GLuint gSize = ctx->PixelMaps.GtoG.Size; + const GLuint bSize = ctx->PixelMaps.BtoB.Size; + const GLuint aSize = ctx->PixelMaps.AtoA.Size; + const uint texSize = pt->width0; + uint *dest; + uint i, j; + + transfer = pipe_get_transfer(pipe, + pt, 0, 0, PIPE_TRANSFER_WRITE, + 0, 0, texSize, texSize); + dest = (uint *) pipe_transfer_map(pipe, transfer); + + /* Pack four 1D maps into a 2D texture: + * R map is placed horizontally, indexed by S, in channel 0 + * G map is placed vertically, indexed by T, in channel 1 + * B map is placed horizontally, indexed by S, in channel 2 + * A map is placed vertically, indexed by T, in channel 3 + */ + for (i = 0; i < texSize; i++) { + for (j = 0; j < texSize; j++) { + union util_color uc; + int k = (i * texSize + j); + ubyte r = ctx->PixelMaps.RtoR.Map8[j * rSize / texSize]; + ubyte g = ctx->PixelMaps.GtoG.Map8[i * gSize / texSize]; + ubyte b = ctx->PixelMaps.BtoB.Map8[j * bSize / texSize]; + ubyte a = ctx->PixelMaps.AtoA.Map8[i * aSize / texSize]; + util_pack_color_ub(r, g, b, a, pt->format, &uc); + *(dest + k) = uc.ui; + } + } + + pipe_transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); +} + + + +#define MAX_INST 100 + +/** + * Returns a fragment program which implements the current pixel transfer ops. + */ +static struct gl_fragment_program * +get_pixel_transfer_program(struct gl_context *ctx, const struct state_key *key) +{ + struct st_context *st = st_context(ctx); + struct prog_instruction inst[MAX_INST]; + struct gl_program_parameter_list *params; + struct gl_fragment_program *fp; + GLuint ic = 0; + const GLuint colorTemp = 0; + + fp = (struct gl_fragment_program *) + ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!fp) + return NULL; + + params = _mesa_new_parameter_list(); + + /* + * Get initial pixel color from the texture. + * TEX colorTemp, fragment.texcoord[0], texture[0], 2D; + */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_TEX; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_INPUT; + inst[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + inst[ic].TexSrcUnit = 0; + inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + fp->Base.InputsRead = (1 << FRAG_ATTRIB_TEX0); + fp->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR); + fp->Base.SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + + if (key->scaleAndBias) { + static const gl_state_index scale_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 }; + static const gl_state_index bias_state[STATE_LENGTH] = + { STATE_INTERNAL, STATE_PT_BIAS, 0, 0, 0 }; + GLint scale_p, bias_p; + + scale_p = _mesa_add_state_reference(params, scale_state); + bias_p = _mesa_add_state_reference(params, bias_state); + + /* MAD colorTemp, colorTemp, scale, bias; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_MAD; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[1].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[1].Index = scale_p; + inst[ic].SrcReg[2].File = PROGRAM_STATE_VAR; + inst[ic].SrcReg[2].Index = bias_p; + ic++; + } + + if (key->pixelMaps) { + const GLuint temp = 1; + + /* create the colormap/texture now if not already done */ + if (!st->pixel_xfer.pixelmap_texture) { + st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx); + st->pixel_xfer.pixelmap_sampler_view = + st_create_texture_sampler_view(st->pipe, + st->pixel_xfer.pixelmap_texture); + } + + /* with a little effort, we can do four pixel map look-ups with + * two TEX instructions: + */ + + /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_TEX; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */ + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].TexSrcUnit = 1; + inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + + /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_TEX; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = temp; + inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */ + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = colorTemp; + inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, + SWIZZLE_Z, SWIZZLE_W); + inst[ic].TexSrcUnit = 1; + inst[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + + /* MOV colorTemp, temp; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_MOV; + inst[ic].DstReg.File = PROGRAM_TEMPORARY; + inst[ic].DstReg.Index = colorTemp; + inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + inst[ic].SrcReg[0].Index = temp; + ic++; + + fp->Base.SamplersUsed |= (1 << 1); /* sampler 1 is used */ + } + + /* Modify last instruction's dst reg to write to result.color */ + { + struct prog_instruction *last = &inst[ic - 1]; + last->DstReg.File = PROGRAM_OUTPUT; + last->DstReg.Index = FRAG_RESULT_COLOR; + } + + /* END; */ + _mesa_init_instructions(inst + ic, 1); + inst[ic].Opcode = OPCODE_END; + ic++; + + assert(ic <= MAX_INST); + + + fp->Base.Instructions = _mesa_alloc_instructions(ic); + if (!fp->Base.Instructions) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, + "generating pixel transfer program"); + return NULL; + } + + _mesa_copy_instructions(fp->Base.Instructions, inst, ic); + fp->Base.NumInstructions = ic; + fp->Base.Parameters = params; + +#if 0 + printf("========= pixel transfer prog\n"); + _mesa_print_program(&fp->Base); + _mesa_print_parameter_list(fp->Base.Parameters); +#endif + + return fp; +} + + + +/** + * Update st->pixel_xfer.program in response to new pixel-transfer state. + */ +static void +update_pixel_transfer(struct st_context *st) +{ + struct gl_context *ctx = st->ctx; + struct state_key key; + struct gl_fragment_program *fp; + + make_state_key(st->ctx, &key); + + fp = (struct gl_fragment_program *) + _mesa_search_program_cache(st->pixel_xfer.cache, &key, sizeof(key)); + if (!fp) { + fp = get_pixel_transfer_program(st->ctx, &key); + _mesa_program_cache_insert(st->ctx, st->pixel_xfer.cache, + &key, sizeof(key), &fp->Base); + } + + if (ctx->Pixel.MapColorFlag) { + load_color_map_texture(ctx, st->pixel_xfer.pixelmap_texture); + } + st->pixel_xfer.pixelmap_enabled = ctx->Pixel.MapColorFlag; + + st->pixel_xfer.program = (struct st_fragment_program *) fp; +} + + + +const struct st_tracked_state st_update_pixel_transfer = { + "st_update_pixel_transfer", /* name */ + { /* dirty */ + _NEW_PIXEL, /* mesa */ + 0, /* st */ + }, + update_pixel_transfer /* update */ +}; diff --git a/mesalib/src/mesa/state_tracker/st_atom_rasterizer.c b/mesalib/src/mesa/state_tracker/st_atom_rasterizer.c index 89ee4ebca..250cbb226 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_rasterizer.c +++ b/mesalib/src/mesa/state_tracker/st_atom_rasterizer.c @@ -1,280 +1,280 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
- /*
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-#include "main/macros.h"
-#include "st_context.h"
-#include "st_atom.h"
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "cso_cache/cso_context.h"
-
-
-static GLuint translate_fill( GLenum mode )
-{
- switch (mode) {
- case GL_POINT:
- return PIPE_POLYGON_MODE_POINT;
- case GL_LINE:
- return PIPE_POLYGON_MODE_LINE;
- case GL_FILL:
- return PIPE_POLYGON_MODE_FILL;
- default:
- assert(0);
- return 0;
- }
-}
-
-
-
-static void update_raster_state( struct st_context *st )
-{
- struct gl_context *ctx = st->ctx;
- struct pipe_rasterizer_state *raster = &st->state.rasterizer;
- const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current;
- const struct gl_fragment_program *fragProg = ctx->FragmentProgram._Current;
- uint i;
-
- memset(raster, 0, sizeof(*raster));
-
- /* _NEW_POLYGON, _NEW_BUFFERS
- */
- {
- raster->front_ccw = (ctx->Polygon.FrontFace == GL_CCW);
-
- /*
- * Gallium's surfaces are Y=0=TOP orientation. OpenGL is the
- * opposite. Window system surfaces are Y=0=TOP. Mesa's FBOs
- * must match OpenGL conventions so FBOs use Y=0=BOTTOM. In that
- * case, we must invert Y and flip the notion of front vs. back.
- */
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) {
- /* Drawing to an FBO. The viewport will be inverted. */
- raster->front_ccw ^= 1;
- }
- }
-
- /* _NEW_LIGHT
- */
- if (ctx->Light.ShadeModel == GL_FLAT)
- raster->flatshade = 1;
-
- if (ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT)
- raster->flatshade_first = 1;
-
- /* _NEW_LIGHT | _NEW_PROGRAM
- *
- * Back-face colors can come from traditional lighting (when
- * GL_LIGHT_MODEL_TWO_SIDE is set) or from vertex programs/shaders (when
- * GL_VERTEX_PROGRAM_TWO_SIDE is set). Note the logic here.
- */
- if (ctx->VertexProgram._Current) {
- if (ctx->VertexProgram._Enabled ||
- (ctx->Shader.CurrentVertexProgram &&
- ctx->Shader.CurrentVertexProgram->LinkStatus)) {
- /* user-defined vertex program or shader */
- raster->light_twoside = ctx->VertexProgram.TwoSideEnabled;
- }
- else {
- /* TNL-generated program */
- raster->light_twoside = ctx->Light.Enabled && ctx->Light.Model.TwoSide;
- }
- }
- else if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) {
- raster->light_twoside = 1;
- }
-
- raster->clamp_vertex_color = ctx->Light._ClampVertexColor;
-
- /* _NEW_POLYGON
- */
- if (ctx->Polygon.CullFlag) {
- switch (ctx->Polygon.CullFaceMode) {
- case GL_FRONT:
- raster->cull_face = PIPE_FACE_FRONT;
- break;
- case GL_BACK:
- raster->cull_face = PIPE_FACE_BACK;
- break;
- case GL_FRONT_AND_BACK:
- raster->cull_face = PIPE_FACE_FRONT_AND_BACK;
- break;
- }
- }
- else {
- raster->cull_face = PIPE_FACE_NONE;
- }
-
- /* _NEW_POLYGON
- */
- {
- raster->fill_front = translate_fill( ctx->Polygon.FrontMode );
- raster->fill_back = translate_fill( ctx->Polygon.BackMode );
-
- /* Simplify when culling is active:
- */
- if (raster->cull_face & PIPE_FACE_FRONT) {
- raster->fill_front = raster->fill_back;
- }
-
- if (raster->cull_face & PIPE_FACE_BACK) {
- raster->fill_back = raster->fill_front;
- }
- }
-
- /* _NEW_POLYGON
- */
- if (ctx->Polygon.OffsetUnits != 0.0 ||
- ctx->Polygon.OffsetFactor != 0.0) {
- raster->offset_point = ctx->Polygon.OffsetPoint;
- raster->offset_line = ctx->Polygon.OffsetLine;
- raster->offset_tri = ctx->Polygon.OffsetFill;
- }
-
- if (ctx->Polygon.OffsetPoint ||
- ctx->Polygon.OffsetLine ||
- ctx->Polygon.OffsetFill) {
- raster->offset_units = ctx->Polygon.OffsetUnits;
- raster->offset_scale = ctx->Polygon.OffsetFactor;
- }
-
- if (ctx->Polygon.SmoothFlag)
- raster->poly_smooth = 1;
-
- if (ctx->Polygon.StippleFlag)
- raster->poly_stipple_enable = 1;
-
- /* _NEW_POINT
- */
- raster->point_size = ctx->Point.Size;
-
- if (!ctx->Point.PointSprite && ctx->Point.SmoothFlag)
- raster->point_smooth = 1;
-
- /* _NEW_POINT | _NEW_PROGRAM
- */
- if (ctx->Point.PointSprite) {
- /* origin */
- if ((ctx->Point.SpriteOrigin == GL_UPPER_LEFT) ^
- (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM))
- raster->sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT;
- else
- raster->sprite_coord_mode = PIPE_SPRITE_COORD_LOWER_LEFT;
-
- /* Coord replacement flags. If bit 'k' is set that means
- * that we need to replace GENERIC[k] attrib with an automatically
- * computed texture coord.
- */
- for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
- if (ctx->Point.CoordReplace[i]) {
- raster->sprite_coord_enable |= 1 << i;
- }
- }
- if (fragProg->Base.InputsRead & FRAG_BIT_PNTC) {
- raster->sprite_coord_enable |=
- 1 << (FRAG_ATTRIB_PNTC - FRAG_ATTRIB_TEX0);
- }
-
- raster->point_quad_rasterization = 1;
- }
-
- /* ST_NEW_VERTEX_PROGRAM
- */
- if (vertProg) {
- if (vertProg->Base.Id == 0) {
- if (vertProg->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
- /* generated program which emits point size */
- raster->point_size_per_vertex = TRUE;
- }
- }
- else if (ctx->VertexProgram.PointSizeEnabled) {
- /* user-defined program and GL_VERTEX_PROGRAM_POINT_SIZE set */
- raster->point_size_per_vertex = ctx->VertexProgram.PointSizeEnabled;
- }
- }
- if (!raster->point_size_per_vertex) {
- /* clamp size now */
- raster->point_size = CLAMP(ctx->Point.Size,
- ctx->Point.MinSize,
- ctx->Point.MaxSize);
- }
-
- /* _NEW_LINE
- */
- raster->line_smooth = ctx->Line.SmoothFlag;
- if (ctx->Line.SmoothFlag) {
- raster->line_width = CLAMP(ctx->Line.Width,
- ctx->Const.MinLineWidthAA,
- ctx->Const.MaxLineWidthAA);
- }
- else {
- raster->line_width = CLAMP(ctx->Line.Width,
- ctx->Const.MinLineWidth,
- ctx->Const.MaxLineWidth);
- }
-
- raster->line_stipple_enable = ctx->Line.StippleFlag;
- raster->line_stipple_pattern = ctx->Line.StipplePattern;
- /* GL stipple factor is in [1,256], remap to [0, 255] here */
- raster->line_stipple_factor = ctx->Line.StippleFactor - 1;
-
- /* _NEW_MULTISAMPLE */
- if (ctx->Multisample._Enabled || st->force_msaa)
- raster->multisample = 1;
-
- /* _NEW_SCISSOR */
- if (ctx->Scissor.Enabled)
- raster->scissor = 1;
-
- /* _NEW_FRAG_CLAMP */
- raster->clamp_fragment_color = ctx->Color._ClampFragmentColor;
-
- raster->gl_rasterization_rules = 1;
-
- cso_set_rasterizer(st->cso_context, raster);
-}
-
-const struct st_tracked_state st_update_rasterizer = {
- "st_update_rasterizer", /* name */
- {
- (_NEW_BUFFERS |
- _NEW_LIGHT |
- _NEW_LINE |
- _NEW_MULTISAMPLE |
- _NEW_POINT |
- _NEW_POLYGON |
- _NEW_PROGRAM |
- _NEW_SCISSOR |
- _NEW_FRAG_CLAMP), /* mesa state dependencies*/
- ST_NEW_VERTEX_PROGRAM, /* state tracker dependencies */
- },
- update_raster_state /* update function */
-};
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "main/macros.h" +#include "st_context.h" +#include "st_atom.h" +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "cso_cache/cso_context.h" + + +static GLuint translate_fill( GLenum mode ) +{ + switch (mode) { + case GL_POINT: + return PIPE_POLYGON_MODE_POINT; + case GL_LINE: + return PIPE_POLYGON_MODE_LINE; + case GL_FILL: + return PIPE_POLYGON_MODE_FILL; + default: + assert(0); + return 0; + } +} + + + +static void update_raster_state( struct st_context *st ) +{ + struct gl_context *ctx = st->ctx; + struct pipe_rasterizer_state *raster = &st->state.rasterizer; + const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current; + const struct gl_fragment_program *fragProg = ctx->FragmentProgram._Current; + uint i; + + memset(raster, 0, sizeof(*raster)); + + /* _NEW_POLYGON, _NEW_BUFFERS + */ + { + raster->front_ccw = (ctx->Polygon.FrontFace == GL_CCW); + + /* + * Gallium's surfaces are Y=0=TOP orientation. OpenGL is the + * opposite. Window system surfaces are Y=0=TOP. Mesa's FBOs + * must match OpenGL conventions so FBOs use Y=0=BOTTOM. In that + * case, we must invert Y and flip the notion of front vs. back. + */ + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { + /* Drawing to an FBO. The viewport will be inverted. */ + raster->front_ccw ^= 1; + } + } + + /* _NEW_LIGHT + */ + if (ctx->Light.ShadeModel == GL_FLAT) + raster->flatshade = 1; + + if (ctx->Light.ProvokingVertex == GL_FIRST_VERTEX_CONVENTION_EXT) + raster->flatshade_first = 1; + + /* _NEW_LIGHT | _NEW_PROGRAM + * + * Back-face colors can come from traditional lighting (when + * GL_LIGHT_MODEL_TWO_SIDE is set) or from vertex programs/shaders (when + * GL_VERTEX_PROGRAM_TWO_SIDE is set). Note the logic here. + */ + if (ctx->VertexProgram._Current) { + if (ctx->VertexProgram._Enabled || + (ctx->Shader.CurrentVertexProgram && + ctx->Shader.CurrentVertexProgram->LinkStatus)) { + /* user-defined vertex program or shader */ + raster->light_twoside = ctx->VertexProgram.TwoSideEnabled; + } + else { + /* TNL-generated program */ + raster->light_twoside = ctx->Light.Enabled && ctx->Light.Model.TwoSide; + } + } + else if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) { + raster->light_twoside = 1; + } + + raster->clamp_vertex_color = ctx->Light._ClampVertexColor; + + /* _NEW_POLYGON + */ + if (ctx->Polygon.CullFlag) { + switch (ctx->Polygon.CullFaceMode) { + case GL_FRONT: + raster->cull_face = PIPE_FACE_FRONT; + break; + case GL_BACK: + raster->cull_face = PIPE_FACE_BACK; + break; + case GL_FRONT_AND_BACK: + raster->cull_face = PIPE_FACE_FRONT_AND_BACK; + break; + } + } + else { + raster->cull_face = PIPE_FACE_NONE; + } + + /* _NEW_POLYGON + */ + { + raster->fill_front = translate_fill( ctx->Polygon.FrontMode ); + raster->fill_back = translate_fill( ctx->Polygon.BackMode ); + + /* Simplify when culling is active: + */ + if (raster->cull_face & PIPE_FACE_FRONT) { + raster->fill_front = raster->fill_back; + } + + if (raster->cull_face & PIPE_FACE_BACK) { + raster->fill_back = raster->fill_front; + } + } + + /* _NEW_POLYGON + */ + if (ctx->Polygon.OffsetUnits != 0.0 || + ctx->Polygon.OffsetFactor != 0.0) { + raster->offset_point = ctx->Polygon.OffsetPoint; + raster->offset_line = ctx->Polygon.OffsetLine; + raster->offset_tri = ctx->Polygon.OffsetFill; + } + + if (ctx->Polygon.OffsetPoint || + ctx->Polygon.OffsetLine || + ctx->Polygon.OffsetFill) { + raster->offset_units = ctx->Polygon.OffsetUnits; + raster->offset_scale = ctx->Polygon.OffsetFactor; + } + + if (ctx->Polygon.SmoothFlag) + raster->poly_smooth = 1; + + if (ctx->Polygon.StippleFlag) + raster->poly_stipple_enable = 1; + + /* _NEW_POINT + */ + raster->point_size = ctx->Point.Size; + + if (!ctx->Point.PointSprite && ctx->Point.SmoothFlag) + raster->point_smooth = 1; + + /* _NEW_POINT | _NEW_PROGRAM + */ + if (ctx->Point.PointSprite) { + /* origin */ + if ((ctx->Point.SpriteOrigin == GL_UPPER_LEFT) ^ + (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM)) + raster->sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; + else + raster->sprite_coord_mode = PIPE_SPRITE_COORD_LOWER_LEFT; + + /* Coord replacement flags. If bit 'k' is set that means + * that we need to replace GENERIC[k] attrib with an automatically + * computed texture coord. + */ + for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { + if (ctx->Point.CoordReplace[i]) { + raster->sprite_coord_enable |= 1 << i; + } + } + if (fragProg->Base.InputsRead & FRAG_BIT_PNTC) { + raster->sprite_coord_enable |= + 1 << (FRAG_ATTRIB_PNTC - FRAG_ATTRIB_TEX0); + } + + raster->point_quad_rasterization = 1; + } + + /* ST_NEW_VERTEX_PROGRAM + */ + if (vertProg) { + if (vertProg->Base.Id == 0) { + if (vertProg->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_PSIZ)) { + /* generated program which emits point size */ + raster->point_size_per_vertex = TRUE; + } + } + else if (ctx->VertexProgram.PointSizeEnabled) { + /* user-defined program and GL_VERTEX_PROGRAM_POINT_SIZE set */ + raster->point_size_per_vertex = ctx->VertexProgram.PointSizeEnabled; + } + } + if (!raster->point_size_per_vertex) { + /* clamp size now */ + raster->point_size = CLAMP(ctx->Point.Size, + ctx->Point.MinSize, + ctx->Point.MaxSize); + } + + /* _NEW_LINE + */ + raster->line_smooth = ctx->Line.SmoothFlag; + if (ctx->Line.SmoothFlag) { + raster->line_width = CLAMP(ctx->Line.Width, + ctx->Const.MinLineWidthAA, + ctx->Const.MaxLineWidthAA); + } + else { + raster->line_width = CLAMP(ctx->Line.Width, + ctx->Const.MinLineWidth, + ctx->Const.MaxLineWidth); + } + + raster->line_stipple_enable = ctx->Line.StippleFlag; + raster->line_stipple_pattern = ctx->Line.StipplePattern; + /* GL stipple factor is in [1,256], remap to [0, 255] here */ + raster->line_stipple_factor = ctx->Line.StippleFactor - 1; + + /* _NEW_MULTISAMPLE */ + if (ctx->Multisample._Enabled || st->force_msaa) + raster->multisample = 1; + + /* _NEW_SCISSOR */ + if (ctx->Scissor.Enabled) + raster->scissor = 1; + + /* _NEW_FRAG_CLAMP */ + raster->clamp_fragment_color = ctx->Color._ClampFragmentColor; + + raster->gl_rasterization_rules = 1; + + cso_set_rasterizer(st->cso_context, raster); +} + +const struct st_tracked_state st_update_rasterizer = { + "st_update_rasterizer", /* name */ + { + (_NEW_BUFFERS | + _NEW_LIGHT | + _NEW_LINE | + _NEW_MULTISAMPLE | + _NEW_POINT | + _NEW_POLYGON | + _NEW_PROGRAM | + _NEW_SCISSOR | + _NEW_FRAG_CLAMP), /* mesa state dependencies*/ + ST_NEW_VERTEX_PROGRAM, /* state tracker dependencies */ + }, + update_raster_state /* update function */ +}; diff --git a/mesalib/src/mesa/state_tracker/st_cb_blit.c b/mesalib/src/mesa/state_tracker/st_cb_blit.c index a890afe74..750f541b5 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_blit.c +++ b/mesalib/src/mesa/state_tracker/st_cb_blit.c @@ -1,332 +1,332 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
- /*
- * Authors:
- * Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-
-#include "st_context.h"
-#include "st_texture.h"
-#include "st_cb_blit.h"
-#include "st_cb_fbo.h"
-#include "st_atom.h"
-
-#include "util/u_blit.h"
-
-
-void
-st_init_blit(struct st_context *st)
-{
- st->blit = util_create_blit(st->pipe, st->cso_context);
-}
-
-
-void
-st_destroy_blit(struct st_context *st)
-{
- util_destroy_blit(st->blit);
- st->blit = NULL;
-}
-
-
-#if FEATURE_EXT_framebuffer_blit
-
-static void
-st_BlitFramebuffer_resolve(struct gl_context *ctx,
- GLbitfield mask,
- struct pipe_resolve_info *info)
-{
- const GLbitfield depthStencil = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
-
- struct st_context *st = st_context(ctx);
-
- struct st_renderbuffer *srcRb, *dstRb;
-
- if (mask & GL_COLOR_BUFFER_BIT) {
- srcRb = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
- dstRb = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
-
- info->mask = PIPE_MASK_RGBA;
-
- info->src.res = srcRb->texture;
- info->src.layer = srcRb->surface->u.tex.first_layer;
- info->dst.res = dstRb->texture;
- info->dst.level = dstRb->surface->u.tex.level;
- info->dst.layer = dstRb->surface->u.tex.first_layer;
-
- st->pipe->resource_resolve(st->pipe, info);
- }
-
- if (mask & depthStencil) {
- struct gl_renderbuffer_attachment *srcDepth, *srcStencil;
- struct gl_renderbuffer_attachment *dstDepth, *dstStencil;
- boolean combined;
-
- srcDepth = &ctx->ReadBuffer->Attachment[BUFFER_DEPTH];
- dstDepth = &ctx->DrawBuffer->Attachment[BUFFER_DEPTH];
- srcStencil = &ctx->ReadBuffer->Attachment[BUFFER_STENCIL];
- dstStencil = &ctx->DrawBuffer->Attachment[BUFFER_STENCIL];
-
- combined =
- st_is_depth_stencil_combined(srcDepth, srcStencil) &&
- st_is_depth_stencil_combined(dstDepth, dstStencil);
-
- if ((mask & GL_DEPTH_BUFFER_BIT) || combined) {
- /* resolve depth and, if combined and requested, stencil as well */
- srcRb = st_renderbuffer(srcDepth->Renderbuffer);
- dstRb = st_renderbuffer(dstDepth->Renderbuffer);
-
- info->mask = (mask & GL_DEPTH_BUFFER_BIT) ? PIPE_MASK_Z : 0;
- if (combined && (mask & GL_STENCIL_BUFFER_BIT)) {
- mask &= ~GL_STENCIL_BUFFER_BIT;
- info->mask |= PIPE_MASK_S;
- }
-
- info->src.res = srcRb->texture;
- info->src.layer = srcRb->surface->u.tex.first_layer;
- info->dst.res = dstRb->texture;
- info->dst.level = dstRb->surface->u.tex.level;
- info->dst.layer = dstRb->surface->u.tex.first_layer;
-
- st->pipe->resource_resolve(st->pipe, info);
- }
-
- if (mask & GL_STENCIL_BUFFER_BIT) {
- /* resolve separate stencil buffer */
- srcRb = st_renderbuffer(srcStencil->Renderbuffer);
- dstRb = st_renderbuffer(dstStencil->Renderbuffer);
-
- info->mask = PIPE_MASK_S;
-
- info->src.res = srcRb->texture;
- info->src.layer = srcRb->surface->u.tex.first_layer;
- info->dst.res = dstRb->texture;
- info->dst.level = dstRb->surface->u.tex.level;
- info->dst.layer = dstRb->surface->u.tex.first_layer;
-
- st->pipe->resource_resolve(st->pipe, info);
- }
- }
-}
-
-static void
-st_BlitFramebuffer(struct gl_context *ctx,
- GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
- GLbitfield mask, GLenum filter)
-{
- const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT |
- GL_STENCIL_BUFFER_BIT);
- struct st_context *st = st_context(ctx);
- const uint pFilter = ((filter == GL_NEAREST)
- ? PIPE_TEX_MIPFILTER_NEAREST
- : PIPE_TEX_MIPFILTER_LINEAR);
- struct gl_framebuffer *readFB = ctx->ReadBuffer;
- struct gl_framebuffer *drawFB = ctx->DrawBuffer;
-
- st_validate_state(st);
-
- if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1,
- &dstX0, &dstY0, &dstX1, &dstY1)) {
- return; /* nothing to draw/blit */
- }
-
- if (st_fb_orientation(drawFB) == Y_0_TOP) {
- /* invert Y for dest */
- dstY0 = drawFB->Height - dstY0;
- dstY1 = drawFB->Height - dstY1;
- }
-
- if (st_fb_orientation(readFB) == Y_0_TOP) {
- /* invert Y for src */
- srcY0 = readFB->Height - srcY0;
- srcY1 = readFB->Height - srcY1;
- }
-
- /* Disable conditional rendering. */
- if (st->render_condition) {
- st->pipe->render_condition(st->pipe, NULL, 0);
- }
-
- if (readFB->Visual.sampleBuffers > drawFB->Visual.sampleBuffers) {
- struct pipe_resolve_info info;
-
- if (dstX0 < dstX1) {
- info.dst.x0 = dstX0;
- info.dst.x1 = dstX1;
- info.src.x0 = srcX0;
- info.src.x1 = srcX1;
- } else {
- info.dst.x0 = dstX1;
- info.dst.x1 = dstX0;
- info.src.x0 = srcX1;
- info.src.x1 = srcX0;
- }
- if (dstY0 < dstY1) {
- info.dst.y0 = dstY0;
- info.dst.y1 = dstY1;
- info.src.y0 = srcY0;
- info.src.y1 = srcY1;
- } else {
- info.dst.y0 = dstY1;
- info.dst.y1 = dstY0;
- info.src.y0 = srcY1;
- info.src.y1 = srcY0;
- }
-
- st_BlitFramebuffer_resolve(ctx, mask, &info); /* filter doesn't apply */
-
- goto done;
- }
-
- if (srcY0 > srcY1 && dstY0 > dstY1) {
- /* Both src and dst are upside down. Swap Y to make it
- * right-side up to increase odds of using a fast path.
- * Recall that all Gallium raster coords have Y=0=top.
- */
- GLint tmp;
- tmp = srcY0;
- srcY0 = srcY1;
- srcY1 = tmp;
- tmp = dstY0;
- dstY0 = dstY1;
- dstY1 = tmp;
- }
-
- if (mask & GL_COLOR_BUFFER_BIT) {
- struct gl_renderbuffer_attachment *srcAtt =
- &readFB->Attachment[readFB->_ColorReadBufferIndex];
-
- if(srcAtt->Type == GL_TEXTURE) {
- struct st_texture_object *srcObj =
- st_texture_object(srcAtt->Texture);
- struct st_renderbuffer *dstRb =
- st_renderbuffer(drawFB->_ColorDrawBuffers[0]);
- struct pipe_surface *dstSurf = dstRb->surface;
-
- if (!srcObj->pt)
- goto done;
-
- util_blit_pixels(st->blit, srcObj->pt, srcAtt->TextureLevel,
- srcX0, srcY0, srcX1, srcY1,
- srcAtt->Zoffset + srcAtt->CubeMapFace,
- dstSurf, dstX0, dstY0, dstX1, dstY1,
- 0.0, pFilter);
- }
- else {
- struct st_renderbuffer *srcRb =
- st_renderbuffer(readFB->_ColorReadBuffer);
- struct st_renderbuffer *dstRb =
- st_renderbuffer(drawFB->_ColorDrawBuffers[0]);
- struct pipe_surface *srcSurf = srcRb->surface;
- struct pipe_surface *dstSurf = dstRb->surface;
-
- util_blit_pixels(st->blit,
- srcRb->texture, srcSurf->u.tex.level,
- srcX0, srcY0, srcX1, srcY1,
- srcSurf->u.tex.first_layer,
- dstSurf, dstX0, dstY0, dstX1, dstY1,
- 0.0, pFilter);
- }
- }
-
- if (mask & depthStencil) {
- /* depth and/or stencil blit */
-
- /* get src/dst depth surfaces */
- struct gl_renderbuffer_attachment *srcDepth =
- &readFB->Attachment[BUFFER_DEPTH];
- struct gl_renderbuffer_attachment *dstDepth =
- &drawFB->Attachment[BUFFER_DEPTH];
- struct gl_renderbuffer_attachment *srcStencil =
- &readFB->Attachment[BUFFER_STENCIL];
- struct gl_renderbuffer_attachment *dstStencil =
- &drawFB->Attachment[BUFFER_STENCIL];
-
- struct st_renderbuffer *srcDepthRb =
- st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer);
- struct st_renderbuffer *dstDepthRb =
- st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer);
- struct pipe_surface *dstDepthSurf =
- dstDepthRb ? dstDepthRb->surface : NULL;
-
- if ((mask & depthStencil) == depthStencil &&
- st_is_depth_stencil_combined(srcDepth, srcStencil) &&
- st_is_depth_stencil_combined(dstDepth, dstStencil)) {
-
- /* Blitting depth and stencil values between combined
- * depth/stencil buffers. This is the ideal case for such buffers.
- */
- util_blit_pixels(st->blit,
- srcDepthRb->texture,
- srcDepthRb->surface->u.tex.level,
- srcX0, srcY0, srcX1, srcY1,
- srcDepthRb->surface->u.tex.first_layer,
- dstDepthSurf, dstX0, dstY0, dstX1, dstY1,
- 0.0, pFilter);
- }
- else {
- /* blitting depth and stencil separately */
-
- if (mask & GL_DEPTH_BUFFER_BIT) {
- util_blit_pixels(st->blit, srcDepthRb->texture,
- srcDepthRb->surface->u.tex.level,
- srcX0, srcY0, srcX1, srcY1,
- srcDepthRb->surface->u.tex.first_layer,
- dstDepthSurf, dstX0, dstY0, dstX1, dstY1,
- 0.0, pFilter);
- }
-
- if (mask & GL_STENCIL_BUFFER_BIT) {
- /* blit stencil only */
- _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) not completed");
- }
- }
- }
-
-done:
- /* Restore conditional rendering state. */
- if (st->render_condition) {
- st->pipe->render_condition(st->pipe, st->render_condition,
- st->condition_mode);
- }
-}
-
-
-void
-st_init_blit_functions(struct dd_function_table *functions)
-{
- functions->BlitFramebuffer = st_BlitFramebuffer;
-}
-
-#endif /* FEATURE_EXT_framebuffer_blit */
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/mfeatures.h" + +#include "st_context.h" +#include "st_texture.h" +#include "st_cb_blit.h" +#include "st_cb_fbo.h" +#include "st_atom.h" + +#include "util/u_blit.h" + + +void +st_init_blit(struct st_context *st) +{ + st->blit = util_create_blit(st->pipe, st->cso_context); +} + + +void +st_destroy_blit(struct st_context *st) +{ + util_destroy_blit(st->blit); + st->blit = NULL; +} + + +#if FEATURE_EXT_framebuffer_blit + +static void +st_BlitFramebuffer_resolve(struct gl_context *ctx, + GLbitfield mask, + struct pipe_resolve_info *info) +{ + const GLbitfield depthStencil = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + + struct st_context *st = st_context(ctx); + + struct st_renderbuffer *srcRb, *dstRb; + + if (mask & GL_COLOR_BUFFER_BIT) { + srcRb = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); + dstRb = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); + + info->mask = PIPE_MASK_RGBA; + + info->src.res = srcRb->texture; + info->src.layer = srcRb->surface->u.tex.first_layer; + info->dst.res = dstRb->texture; + info->dst.level = dstRb->surface->u.tex.level; + info->dst.layer = dstRb->surface->u.tex.first_layer; + + st->pipe->resource_resolve(st->pipe, info); + } + + if (mask & depthStencil) { + struct gl_renderbuffer_attachment *srcDepth, *srcStencil; + struct gl_renderbuffer_attachment *dstDepth, *dstStencil; + boolean combined; + + srcDepth = &ctx->ReadBuffer->Attachment[BUFFER_DEPTH]; + dstDepth = &ctx->DrawBuffer->Attachment[BUFFER_DEPTH]; + srcStencil = &ctx->ReadBuffer->Attachment[BUFFER_STENCIL]; + dstStencil = &ctx->DrawBuffer->Attachment[BUFFER_STENCIL]; + + combined = + st_is_depth_stencil_combined(srcDepth, srcStencil) && + st_is_depth_stencil_combined(dstDepth, dstStencil); + + if ((mask & GL_DEPTH_BUFFER_BIT) || combined) { + /* resolve depth and, if combined and requested, stencil as well */ + srcRb = st_renderbuffer(srcDepth->Renderbuffer); + dstRb = st_renderbuffer(dstDepth->Renderbuffer); + + info->mask = (mask & GL_DEPTH_BUFFER_BIT) ? PIPE_MASK_Z : 0; + if (combined && (mask & GL_STENCIL_BUFFER_BIT)) { + mask &= ~GL_STENCIL_BUFFER_BIT; + info->mask |= PIPE_MASK_S; + } + + info->src.res = srcRb->texture; + info->src.layer = srcRb->surface->u.tex.first_layer; + info->dst.res = dstRb->texture; + info->dst.level = dstRb->surface->u.tex.level; + info->dst.layer = dstRb->surface->u.tex.first_layer; + + st->pipe->resource_resolve(st->pipe, info); + } + + if (mask & GL_STENCIL_BUFFER_BIT) { + /* resolve separate stencil buffer */ + srcRb = st_renderbuffer(srcStencil->Renderbuffer); + dstRb = st_renderbuffer(dstStencil->Renderbuffer); + + info->mask = PIPE_MASK_S; + + info->src.res = srcRb->texture; + info->src.layer = srcRb->surface->u.tex.first_layer; + info->dst.res = dstRb->texture; + info->dst.level = dstRb->surface->u.tex.level; + info->dst.layer = dstRb->surface->u.tex.first_layer; + + st->pipe->resource_resolve(st->pipe, info); + } + } +} + +static void +st_BlitFramebuffer(struct gl_context *ctx, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT | + GL_STENCIL_BUFFER_BIT); + struct st_context *st = st_context(ctx); + const uint pFilter = ((filter == GL_NEAREST) + ? PIPE_TEX_MIPFILTER_NEAREST + : PIPE_TEX_MIPFILTER_LINEAR); + struct gl_framebuffer *readFB = ctx->ReadBuffer; + struct gl_framebuffer *drawFB = ctx->DrawBuffer; + + st_validate_state(st); + + if (!_mesa_clip_blit(ctx, &srcX0, &srcY0, &srcX1, &srcY1, + &dstX0, &dstY0, &dstX1, &dstY1)) { + return; /* nothing to draw/blit */ + } + + if (st_fb_orientation(drawFB) == Y_0_TOP) { + /* invert Y for dest */ + dstY0 = drawFB->Height - dstY0; + dstY1 = drawFB->Height - dstY1; + } + + if (st_fb_orientation(readFB) == Y_0_TOP) { + /* invert Y for src */ + srcY0 = readFB->Height - srcY0; + srcY1 = readFB->Height - srcY1; + } + + /* Disable conditional rendering. */ + if (st->render_condition) { + st->pipe->render_condition(st->pipe, NULL, 0); + } + + if (readFB->Visual.sampleBuffers > drawFB->Visual.sampleBuffers) { + struct pipe_resolve_info info; + + if (dstX0 < dstX1) { + info.dst.x0 = dstX0; + info.dst.x1 = dstX1; + info.src.x0 = srcX0; + info.src.x1 = srcX1; + } else { + info.dst.x0 = dstX1; + info.dst.x1 = dstX0; + info.src.x0 = srcX1; + info.src.x1 = srcX0; + } + if (dstY0 < dstY1) { + info.dst.y0 = dstY0; + info.dst.y1 = dstY1; + info.src.y0 = srcY0; + info.src.y1 = srcY1; + } else { + info.dst.y0 = dstY1; + info.dst.y1 = dstY0; + info.src.y0 = srcY1; + info.src.y1 = srcY0; + } + + st_BlitFramebuffer_resolve(ctx, mask, &info); /* filter doesn't apply */ + + goto done; + } + + if (srcY0 > srcY1 && dstY0 > dstY1) { + /* Both src and dst are upside down. Swap Y to make it + * right-side up to increase odds of using a fast path. + * Recall that all Gallium raster coords have Y=0=top. + */ + GLint tmp; + tmp = srcY0; + srcY0 = srcY1; + srcY1 = tmp; + tmp = dstY0; + dstY0 = dstY1; + dstY1 = tmp; + } + + if (mask & GL_COLOR_BUFFER_BIT) { + struct gl_renderbuffer_attachment *srcAtt = + &readFB->Attachment[readFB->_ColorReadBufferIndex]; + + if(srcAtt->Type == GL_TEXTURE) { + struct st_texture_object *srcObj = + st_texture_object(srcAtt->Texture); + struct st_renderbuffer *dstRb = + st_renderbuffer(drawFB->_ColorDrawBuffers[0]); + struct pipe_surface *dstSurf = dstRb->surface; + + if (!srcObj->pt) + goto done; + + util_blit_pixels(st->blit, srcObj->pt, srcAtt->TextureLevel, + srcX0, srcY0, srcX1, srcY1, + srcAtt->Zoffset + srcAtt->CubeMapFace, + dstSurf, dstX0, dstY0, dstX1, dstY1, + 0.0, pFilter); + } + else { + struct st_renderbuffer *srcRb = + st_renderbuffer(readFB->_ColorReadBuffer); + struct st_renderbuffer *dstRb = + st_renderbuffer(drawFB->_ColorDrawBuffers[0]); + struct pipe_surface *srcSurf = srcRb->surface; + struct pipe_surface *dstSurf = dstRb->surface; + + util_blit_pixels(st->blit, + srcRb->texture, srcSurf->u.tex.level, + srcX0, srcY0, srcX1, srcY1, + srcSurf->u.tex.first_layer, + dstSurf, dstX0, dstY0, dstX1, dstY1, + 0.0, pFilter); + } + } + + if (mask & depthStencil) { + /* depth and/or stencil blit */ + + /* get src/dst depth surfaces */ + struct gl_renderbuffer_attachment *srcDepth = + &readFB->Attachment[BUFFER_DEPTH]; + struct gl_renderbuffer_attachment *dstDepth = + &drawFB->Attachment[BUFFER_DEPTH]; + struct gl_renderbuffer_attachment *srcStencil = + &readFB->Attachment[BUFFER_STENCIL]; + struct gl_renderbuffer_attachment *dstStencil = + &drawFB->Attachment[BUFFER_STENCIL]; + + struct st_renderbuffer *srcDepthRb = + st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); + struct st_renderbuffer *dstDepthRb = + st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); + struct pipe_surface *dstDepthSurf = + dstDepthRb ? dstDepthRb->surface : NULL; + + if ((mask & depthStencil) == depthStencil && + st_is_depth_stencil_combined(srcDepth, srcStencil) && + st_is_depth_stencil_combined(dstDepth, dstStencil)) { + + /* Blitting depth and stencil values between combined + * depth/stencil buffers. This is the ideal case for such buffers. + */ + util_blit_pixels(st->blit, + srcDepthRb->texture, + srcDepthRb->surface->u.tex.level, + srcX0, srcY0, srcX1, srcY1, + srcDepthRb->surface->u.tex.first_layer, + dstDepthSurf, dstX0, dstY0, dstX1, dstY1, + 0.0, pFilter); + } + else { + /* blitting depth and stencil separately */ + + if (mask & GL_DEPTH_BUFFER_BIT) { + util_blit_pixels(st->blit, srcDepthRb->texture, + srcDepthRb->surface->u.tex.level, + srcX0, srcY0, srcX1, srcY1, + srcDepthRb->surface->u.tex.first_layer, + dstDepthSurf, dstX0, dstY0, dstX1, dstY1, + 0.0, pFilter); + } + + if (mask & GL_STENCIL_BUFFER_BIT) { + /* blit stencil only */ + _mesa_problem(ctx, "st_BlitFramebuffer(STENCIL) not completed"); + } + } + } + +done: + /* Restore conditional rendering state. */ + if (st->render_condition) { + st->pipe->render_condition(st->pipe, st->render_condition, + st->condition_mode); + } +} + + +void +st_init_blit_functions(struct dd_function_table *functions) +{ + functions->BlitFramebuffer = st_BlitFramebuffer; +} + +#endif /* FEATURE_EXT_framebuffer_blit */ diff --git a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c index 6bb36b9b5..aab7444e2 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c +++ b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c @@ -1,395 +1,395 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-
-/**
- * Functions for pixel buffer objects and vertex/element buffer objects.
- */
-
-
-#include "main/imports.h"
-#include "main/mtypes.h"
-#include "main/arrayobj.h"
-#include "main/bufferobj.h"
-
-#include "st_context.h"
-#include "st_cb_bufferobjects.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-
-
-/**
- * There is some duplication between mesa's bufferobjects and our
- * bufmgr buffers. Both have an integer handle and a hashtable to
- * lookup an opaque structure. It would be nice if the handles and
- * internal structure where somehow shared.
- */
-static struct gl_buffer_object *
-st_bufferobj_alloc(struct gl_context *ctx, GLuint name, GLenum target)
-{
- struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object);
-
- if (!st_obj)
- return NULL;
-
- _mesa_initialize_buffer_object(&st_obj->Base, name, target);
-
- return &st_obj->Base;
-}
-
-
-
-/**
- * Deallocate/free a vertex/pixel buffer object.
- * Called via glDeleteBuffersARB().
- */
-static void
-st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj)
-{
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- assert(obj->RefCount == 0);
- assert(st_obj->transfer == NULL);
-
- if (st_obj->buffer)
- pipe_resource_reference(&st_obj->buffer, NULL);
-
- free(st_obj);
-}
-
-
-
-/**
- * Replace data in a subrange of buffer object. If the data range
- * specified by size + offset extends beyond the end of the buffer or
- * if data is NULL, no copy is performed.
- * Called via glBufferSubDataARB().
- */
-static void
-st_bufferobj_subdata(struct gl_context *ctx,
- GLintptrARB offset,
- GLsizeiptrARB size,
- const GLvoid * data, struct gl_buffer_object *obj)
-{
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- /* we may be called from VBO code, so double-check params here */
- ASSERT(offset >= 0);
- ASSERT(size >= 0);
- ASSERT(offset + size <= obj->Size);
-
- if (!size)
- return;
-
- /*
- * According to ARB_vertex_buffer_object specification, if data is null,
- * then the contents of the buffer object's data store is undefined. We just
- * ignore, and leave it unchanged.
- */
- if (!data)
- return;
-
- /* Now that transfers are per-context, we don't have to figure out
- * flushing here. Usually drivers won't need to flush in this case
- * even if the buffer is currently referenced by hardware - they
- * just queue the upload as dma rather than mapping the underlying
- * buffer directly.
- */
- pipe_buffer_write(st_context(ctx)->pipe,
- st_obj->buffer,
- offset, size, data);
-}
-
-
-/**
- * Called via glGetBufferSubDataARB().
- */
-static void
-st_bufferobj_get_subdata(struct gl_context *ctx,
- GLintptrARB offset,
- GLsizeiptrARB size,
- GLvoid * data, struct gl_buffer_object *obj)
-{
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- /* we may be called from VBO code, so double-check params here */
- ASSERT(offset >= 0);
- ASSERT(size >= 0);
- ASSERT(offset + size <= obj->Size);
-
- if (!size)
- return;
-
- pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer,
- offset, size, data);
-}
-
-
-/**
- * Allocate space for and store data in a buffer object. Any data that was
- * previously stored in the buffer object is lost. If data is NULL,
- * memory will be allocated, but no copy will occur.
- * Called via ctx->Driver.BufferData().
- * \return GL_TRUE for success, GL_FALSE if out of memory
- */
-static GLboolean
-st_bufferobj_data(struct gl_context *ctx,
- GLenum target,
- GLsizeiptrARB size,
- const GLvoid * data,
- GLenum usage,
- struct gl_buffer_object *obj)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
- unsigned bind, pipe_usage;
-
- st_obj->Base.Size = size;
- st_obj->Base.Usage = usage;
-
- switch(target) {
- case GL_PIXEL_PACK_BUFFER_ARB:
- case GL_PIXEL_UNPACK_BUFFER_ARB:
- bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
- break;
- case GL_ARRAY_BUFFER_ARB:
- bind = PIPE_BIND_VERTEX_BUFFER;
- break;
- case GL_ELEMENT_ARRAY_BUFFER_ARB:
- bind = PIPE_BIND_INDEX_BUFFER;
- break;
- default:
- bind = 0;
- }
-
- switch (usage) {
- case GL_STATIC_DRAW:
- case GL_STATIC_READ:
- case GL_STATIC_COPY:
- pipe_usage = PIPE_USAGE_STATIC;
- break;
- case GL_DYNAMIC_DRAW:
- case GL_DYNAMIC_READ:
- case GL_DYNAMIC_COPY:
- pipe_usage = PIPE_USAGE_DYNAMIC;
- break;
- case GL_STREAM_DRAW:
- case GL_STREAM_READ:
- case GL_STREAM_COPY:
- pipe_usage = PIPE_USAGE_STREAM;
- break;
- default:
- pipe_usage = PIPE_USAGE_DEFAULT;
- }
-
- pipe_resource_reference( &st_obj->buffer, NULL );
-
- if (size != 0) {
- st_obj->buffer = pipe_buffer_create(pipe->screen, bind,
- pipe_usage, size);
-
- if (!st_obj->buffer) {
- return GL_FALSE;
- }
-
- if (data)
- pipe_buffer_write(pipe, st_obj->buffer, 0, size, data);
- return GL_TRUE;
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Called via glMapBufferRange().
- */
-static void *
-st_bufferobj_map_range(struct gl_context *ctx,
- GLintptr offset, GLsizeiptr length, GLbitfield access,
- struct gl_buffer_object *obj)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
- enum pipe_transfer_usage flags = 0x0;
-
- if (access & GL_MAP_WRITE_BIT)
- flags |= PIPE_TRANSFER_WRITE;
-
- if (access & GL_MAP_READ_BIT)
- flags |= PIPE_TRANSFER_READ;
-
- if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
- flags |= PIPE_TRANSFER_FLUSH_EXPLICIT;
-
- if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
- flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
- }
- else if (access & GL_MAP_INVALIDATE_RANGE_BIT) {
- if (offset == 0 && length == obj->Size)
- flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
- else
- flags |= PIPE_TRANSFER_DISCARD_RANGE;
- }
-
- if (access & GL_MAP_UNSYNCHRONIZED_BIT)
- flags |= PIPE_TRANSFER_UNSYNCHRONIZED;
-
- /* ... other flags ...
- */
-
- if (access & MESA_MAP_NOWAIT_BIT)
- flags |= PIPE_TRANSFER_DONTBLOCK;
-
- assert(offset >= 0);
- assert(length >= 0);
- assert(offset < obj->Size);
- assert(offset + length <= obj->Size);
-
- obj->Pointer = pipe_buffer_map_range(pipe,
- st_obj->buffer,
- offset, length,
- flags,
- &st_obj->transfer);
- if (obj->Pointer) {
- obj->Pointer = (ubyte *) obj->Pointer + offset;
- }
-
- if (obj->Pointer) {
- obj->Offset = offset;
- obj->Length = length;
- obj->AccessFlags = access;
- }
-
- return obj->Pointer;
-}
-
-
-static void
-st_bufferobj_flush_mapped_range(struct gl_context *ctx,
- GLintptr offset, GLsizeiptr length,
- struct gl_buffer_object *obj)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- /* Subrange is relative to mapped range */
- assert(offset >= 0);
- assert(length >= 0);
- assert(offset + length <= obj->Length);
- assert(obj->Pointer);
-
- if (!length)
- return;
-
- pipe_buffer_flush_mapped_range(pipe, st_obj->transfer,
- obj->Offset + offset, length);
-}
-
-
-/**
- * Called via glUnmapBufferARB().
- */
-static GLboolean
-st_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *st_obj = st_buffer_object(obj);
-
- if (obj->Length)
- pipe_buffer_unmap(pipe, st_obj->transfer);
-
- st_obj->transfer = NULL;
- obj->Pointer = NULL;
- obj->Offset = 0;
- obj->Length = 0;
- return GL_TRUE;
-}
-
-
-/**
- * Called via glCopyBufferSubData().
- */
-static void
-st_copy_buffer_subdata(struct gl_context *ctx,
- struct gl_buffer_object *src,
- struct gl_buffer_object *dst,
- GLintptr readOffset, GLintptr writeOffset,
- GLsizeiptr size)
-{
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_buffer_object *srcObj = st_buffer_object(src);
- struct st_buffer_object *dstObj = st_buffer_object(dst);
- struct pipe_box box;
-
- if(!size)
- return;
-
- /* buffer should not already be mapped */
- assert(!src->Pointer);
- assert(!dst->Pointer);
-
- u_box_1d(readOffset, size, &box);
-
- pipe->resource_copy_region(pipe, dstObj->buffer, 0, writeOffset, 0, 0,
- srcObj->buffer, 0, &box);
-}
-
-
-/* TODO: if buffer wasn't created with appropriate usage flags, need
- * to recreate it now and copy contents -- or possibly create a
- * gallium entrypoint to extend the usage flags and let the driver
- * decide if a copy is necessary.
- */
-void
-st_bufferobj_validate_usage(struct st_context *st,
- struct st_buffer_object *obj,
- unsigned usage)
-{
-}
-
-
-void
-st_init_bufferobject_functions(struct dd_function_table *functions)
-{
- functions->NewBufferObject = st_bufferobj_alloc;
- functions->DeleteBuffer = st_bufferobj_free;
- functions->BufferData = st_bufferobj_data;
- functions->BufferSubData = st_bufferobj_subdata;
- functions->GetBufferSubData = st_bufferobj_get_subdata;
- functions->MapBufferRange = st_bufferobj_map_range;
- functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range;
- functions->UnmapBuffer = st_bufferobj_unmap;
- functions->CopyBufferSubData = st_copy_buffer_subdata;
-
- /* For GL_APPLE_vertex_array_object */
- functions->NewArrayObject = _mesa_new_array_object;
- functions->DeleteArrayObject = _mesa_delete_array_object;
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + +/** + * Functions for pixel buffer objects and vertex/element buffer objects. + */ + + +#include "main/imports.h" +#include "main/mtypes.h" +#include "main/arrayobj.h" +#include "main/bufferobj.h" + +#include "st_context.h" +#include "st_cb_bufferobjects.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" + + +/** + * There is some duplication between mesa's bufferobjects and our + * bufmgr buffers. Both have an integer handle and a hashtable to + * lookup an opaque structure. It would be nice if the handles and + * internal structure where somehow shared. + */ +static struct gl_buffer_object * +st_bufferobj_alloc(struct gl_context *ctx, GLuint name, GLenum target) +{ + struct st_buffer_object *st_obj = ST_CALLOC_STRUCT(st_buffer_object); + + if (!st_obj) + return NULL; + + _mesa_initialize_buffer_object(&st_obj->Base, name, target); + + return &st_obj->Base; +} + + + +/** + * Deallocate/free a vertex/pixel buffer object. + * Called via glDeleteBuffersARB(). + */ +static void +st_bufferobj_free(struct gl_context *ctx, struct gl_buffer_object *obj) +{ + struct st_buffer_object *st_obj = st_buffer_object(obj); + + assert(obj->RefCount == 0); + assert(st_obj->transfer == NULL); + + if (st_obj->buffer) + pipe_resource_reference(&st_obj->buffer, NULL); + + free(st_obj); +} + + + +/** + * Replace data in a subrange of buffer object. If the data range + * specified by size + offset extends beyond the end of the buffer or + * if data is NULL, no copy is performed. + * Called via glBufferSubDataARB(). + */ +static void +st_bufferobj_subdata(struct gl_context *ctx, + GLintptrARB offset, + GLsizeiptrARB size, + const GLvoid * data, struct gl_buffer_object *obj) +{ + struct st_buffer_object *st_obj = st_buffer_object(obj); + + /* we may be called from VBO code, so double-check params here */ + ASSERT(offset >= 0); + ASSERT(size >= 0); + ASSERT(offset + size <= obj->Size); + + if (!size) + return; + + /* + * According to ARB_vertex_buffer_object specification, if data is null, + * then the contents of the buffer object's data store is undefined. We just + * ignore, and leave it unchanged. + */ + if (!data) + return; + + /* Now that transfers are per-context, we don't have to figure out + * flushing here. Usually drivers won't need to flush in this case + * even if the buffer is currently referenced by hardware - they + * just queue the upload as dma rather than mapping the underlying + * buffer directly. + */ + pipe_buffer_write(st_context(ctx)->pipe, + st_obj->buffer, + offset, size, data); +} + + +/** + * Called via glGetBufferSubDataARB(). + */ +static void +st_bufferobj_get_subdata(struct gl_context *ctx, + GLintptrARB offset, + GLsizeiptrARB size, + GLvoid * data, struct gl_buffer_object *obj) +{ + struct st_buffer_object *st_obj = st_buffer_object(obj); + + /* we may be called from VBO code, so double-check params here */ + ASSERT(offset >= 0); + ASSERT(size >= 0); + ASSERT(offset + size <= obj->Size); + + if (!size) + return; + + pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer, + offset, size, data); +} + + +/** + * Allocate space for and store data in a buffer object. Any data that was + * previously stored in the buffer object is lost. If data is NULL, + * memory will be allocated, but no copy will occur. + * Called via ctx->Driver.BufferData(). + * \return GL_TRUE for success, GL_FALSE if out of memory + */ +static GLboolean +st_bufferobj_data(struct gl_context *ctx, + GLenum target, + GLsizeiptrARB size, + const GLvoid * data, + GLenum usage, + struct gl_buffer_object *obj) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + unsigned bind, pipe_usage; + + st_obj->Base.Size = size; + st_obj->Base.Usage = usage; + + switch(target) { + case GL_PIXEL_PACK_BUFFER_ARB: + case GL_PIXEL_UNPACK_BUFFER_ARB: + bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; + break; + case GL_ARRAY_BUFFER_ARB: + bind = PIPE_BIND_VERTEX_BUFFER; + break; + case GL_ELEMENT_ARRAY_BUFFER_ARB: + bind = PIPE_BIND_INDEX_BUFFER; + break; + default: + bind = 0; + } + + switch (usage) { + case GL_STATIC_DRAW: + case GL_STATIC_READ: + case GL_STATIC_COPY: + pipe_usage = PIPE_USAGE_STATIC; + break; + case GL_DYNAMIC_DRAW: + case GL_DYNAMIC_READ: + case GL_DYNAMIC_COPY: + pipe_usage = PIPE_USAGE_DYNAMIC; + break; + case GL_STREAM_DRAW: + case GL_STREAM_READ: + case GL_STREAM_COPY: + pipe_usage = PIPE_USAGE_STREAM; + break; + default: + pipe_usage = PIPE_USAGE_DEFAULT; + } + + pipe_resource_reference( &st_obj->buffer, NULL ); + + if (size != 0) { + st_obj->buffer = pipe_buffer_create(pipe->screen, bind, + pipe_usage, size); + + if (!st_obj->buffer) { + return GL_FALSE; + } + + if (data) + pipe_buffer_write(pipe, st_obj->buffer, 0, size, data); + return GL_TRUE; + } + + return GL_TRUE; +} + + +/** + * Called via glMapBufferRange(). + */ +static void * +st_bufferobj_map_range(struct gl_context *ctx, + GLintptr offset, GLsizeiptr length, GLbitfield access, + struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + enum pipe_transfer_usage flags = 0x0; + + if (access & GL_MAP_WRITE_BIT) + flags |= PIPE_TRANSFER_WRITE; + + if (access & GL_MAP_READ_BIT) + flags |= PIPE_TRANSFER_READ; + + if (access & GL_MAP_FLUSH_EXPLICIT_BIT) + flags |= PIPE_TRANSFER_FLUSH_EXPLICIT; + + if (access & GL_MAP_INVALIDATE_BUFFER_BIT) { + flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; + } + else if (access & GL_MAP_INVALIDATE_RANGE_BIT) { + if (offset == 0 && length == obj->Size) + flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; + else + flags |= PIPE_TRANSFER_DISCARD_RANGE; + } + + if (access & GL_MAP_UNSYNCHRONIZED_BIT) + flags |= PIPE_TRANSFER_UNSYNCHRONIZED; + + /* ... other flags ... + */ + + if (access & MESA_MAP_NOWAIT_BIT) + flags |= PIPE_TRANSFER_DONTBLOCK; + + assert(offset >= 0); + assert(length >= 0); + assert(offset < obj->Size); + assert(offset + length <= obj->Size); + + obj->Pointer = pipe_buffer_map_range(pipe, + st_obj->buffer, + offset, length, + flags, + &st_obj->transfer); + if (obj->Pointer) { + obj->Pointer = (ubyte *) obj->Pointer + offset; + } + + if (obj->Pointer) { + obj->Offset = offset; + obj->Length = length; + obj->AccessFlags = access; + } + + return obj->Pointer; +} + + +static void +st_bufferobj_flush_mapped_range(struct gl_context *ctx, + GLintptr offset, GLsizeiptr length, + struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + + /* Subrange is relative to mapped range */ + assert(offset >= 0); + assert(length >= 0); + assert(offset + length <= obj->Length); + assert(obj->Pointer); + + if (!length) + return; + + pipe_buffer_flush_mapped_range(pipe, st_obj->transfer, + obj->Offset + offset, length); +} + + +/** + * Called via glUnmapBufferARB(). + */ +static GLboolean +st_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *st_obj = st_buffer_object(obj); + + if (obj->Length) + pipe_buffer_unmap(pipe, st_obj->transfer); + + st_obj->transfer = NULL; + obj->Pointer = NULL; + obj->Offset = 0; + obj->Length = 0; + return GL_TRUE; +} + + +/** + * Called via glCopyBufferSubData(). + */ +static void +st_copy_buffer_subdata(struct gl_context *ctx, + struct gl_buffer_object *src, + struct gl_buffer_object *dst, + GLintptr readOffset, GLintptr writeOffset, + GLsizeiptr size) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_buffer_object *srcObj = st_buffer_object(src); + struct st_buffer_object *dstObj = st_buffer_object(dst); + struct pipe_box box; + + if(!size) + return; + + /* buffer should not already be mapped */ + assert(!src->Pointer); + assert(!dst->Pointer); + + u_box_1d(readOffset, size, &box); + + pipe->resource_copy_region(pipe, dstObj->buffer, 0, writeOffset, 0, 0, + srcObj->buffer, 0, &box); +} + + +/* TODO: if buffer wasn't created with appropriate usage flags, need + * to recreate it now and copy contents -- or possibly create a + * gallium entrypoint to extend the usage flags and let the driver + * decide if a copy is necessary. + */ +void +st_bufferobj_validate_usage(struct st_context *st, + struct st_buffer_object *obj, + unsigned usage) +{ +} + + +void +st_init_bufferobject_functions(struct dd_function_table *functions) +{ + functions->NewBufferObject = st_bufferobj_alloc; + functions->DeleteBuffer = st_bufferobj_free; + functions->BufferData = st_bufferobj_data; + functions->BufferSubData = st_bufferobj_subdata; + functions->GetBufferSubData = st_bufferobj_get_subdata; + functions->MapBufferRange = st_bufferobj_map_range; + functions->FlushMappedBufferRange = st_bufferobj_flush_mapped_range; + functions->UnmapBuffer = st_bufferobj_unmap; + functions->CopyBufferSubData = st_copy_buffer_subdata; + + /* For GL_APPLE_vertex_array_object */ + functions->NewArrayObject = _mesa_new_array_object; + functions->DeleteArrayObject = _mesa_delete_array_object; +} diff --git a/mesalib/src/mesa/state_tracker/st_cb_clear.c b/mesalib/src/mesa/state_tracker/st_cb_clear.c index 487e93d26..117000ba7 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_clear.c +++ b/mesalib/src/mesa/state_tracker/st_cb_clear.c @@ -1,603 +1,603 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- * Copyright 2009 VMware, Inc. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sub license, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL 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.
- *
- **************************************************************************/
-
- /*
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Brian Paul
- * Michel Dänzer
- */
-
-#include "main/glheader.h"
-#include "main/formats.h"
-#include "main/macros.h"
-#include "program/prog_instruction.h"
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_accum.h"
-#include "st_cb_clear.h"
-#include "st_cb_fbo.h"
-#include "st_format.h"
-#include "st_program.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_shader_tokens.h"
-#include "pipe/p_state.h"
-#include "pipe/p_defines.h"
-#include "util/u_format.h"
-#include "util/u_inlines.h"
-#include "util/u_simple_shaders.h"
-#include "util/u_draw_quad.h"
-
-#include "cso_cache/cso_context.h"
-
-
-/**
- * Do per-context initialization for glClear.
- */
-void
-st_init_clear(struct st_context *st)
-{
- struct pipe_screen *pscreen = st->pipe->screen;
-
- memset(&st->clear, 0, sizeof(st->clear));
-
- st->clear.raster.gl_rasterization_rules = 1;
- st->clear.enable_ds_separate = pscreen->get_param(pscreen, PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE);
-}
-
-
-/**
- * Free per-context state for glClear.
- */
-void
-st_destroy_clear(struct st_context *st)
-{
- if (st->clear.fs) {
- cso_delete_fragment_shader(st->cso_context, st->clear.fs);
- st->clear.fs = NULL;
- }
- if (st->clear.vs) {
- cso_delete_vertex_shader(st->cso_context, st->clear.vs);
- st->clear.vs = NULL;
- }
- if (st->clear.vbuf) {
- pipe_resource_reference(&st->clear.vbuf, NULL);
- st->clear.vbuf = NULL;
- }
-}
-
-
-/**
- * Helper function to set the fragment shaders.
- */
-static INLINE void
-set_fragment_shader(struct st_context *st)
-{
- if (!st->clear.fs)
- st->clear.fs = util_make_fragment_passthrough_shader(st->pipe);
-
- cso_set_fragment_shader_handle(st->cso_context, st->clear.fs);
-}
-
-
-/**
- * Helper function to set the vertex shader.
- */
-static INLINE void
-set_vertex_shader(struct st_context *st)
-{
- /* vertex shader - still required to provide the linkage between
- * fragment shader input semantics and vertex_element/buffers.
- */
- if (!st->clear.vs)
- {
- const uint semantic_names[] = { TGSI_SEMANTIC_POSITION,
- TGSI_SEMANTIC_COLOR };
- const uint semantic_indexes[] = { 0, 0 };
- st->clear.vs = util_make_vertex_passthrough_shader(st->pipe, 2,
- semantic_names,
- semantic_indexes);
- }
-
- cso_set_vertex_shader_handle(st->cso_context, st->clear.vs);
-}
-
-
-/**
- * Draw a screen-aligned quadrilateral.
- * Coords are clip coords with y=0=bottom.
- */
-static void
-draw_quad(struct st_context *st,
- float x0, float y0, float x1, float y1, GLfloat z,
- const GLfloat color[4])
-{
- struct pipe_context *pipe = st->pipe;
-
- /* XXX: Need to improve buffer_write to allow NO_WAIT (as well as
- * no_flush) updates to buffers where we know there is no conflict
- * with previous data. Currently using max_slots > 1 will cause
- * synchronous rendering if the driver flushes its command buffers
- * between one bitmap and the next. Our flush hook below isn't
- * sufficient to catch this as the driver doesn't tell us when it
- * flushes its own command buffers. Until this gets fixed, pay the
- * price of allocating a new buffer for each bitmap cache-flush to
- * avoid synchronous rendering.
- */
- const GLuint max_slots = 1; /* 1024 / sizeof(st->clear.vertices); */
- GLuint i;
-
- if (st->clear.vbuf_slot >= max_slots) {
- pipe_resource_reference(&st->clear.vbuf, NULL);
- st->clear.vbuf_slot = 0;
- }
-
- if (!st->clear.vbuf) {
- st->clear.vbuf = pipe_buffer_create(pipe->screen,
- PIPE_BIND_VERTEX_BUFFER,
- PIPE_USAGE_STREAM,
- max_slots * sizeof(st->clear.vertices));
- }
-
- /* positions */
- st->clear.vertices[0][0][0] = x0;
- st->clear.vertices[0][0][1] = y0;
-
- st->clear.vertices[1][0][0] = x1;
- st->clear.vertices[1][0][1] = y0;
-
- st->clear.vertices[2][0][0] = x1;
- st->clear.vertices[2][0][1] = y1;
-
- st->clear.vertices[3][0][0] = x0;
- st->clear.vertices[3][0][1] = y1;
-
- /* same for all verts: */
- for (i = 0; i < 4; i++) {
- st->clear.vertices[i][0][2] = z;
- st->clear.vertices[i][0][3] = 1.0;
- st->clear.vertices[i][1][0] = color[0];
- st->clear.vertices[i][1][1] = color[1];
- st->clear.vertices[i][1][2] = color[2];
- st->clear.vertices[i][1][3] = color[3];
- }
-
- /* put vertex data into vbuf */
- pipe_buffer_write_nooverlap(st->pipe, st->clear.vbuf,
- st->clear.vbuf_slot
- * sizeof(st->clear.vertices),
- sizeof(st->clear.vertices),
- st->clear.vertices);
-
- /* draw */
- util_draw_vertex_buffer(pipe,
- st->cso_context,
- st->clear.vbuf,
- st->clear.vbuf_slot * sizeof(st->clear.vertices),
- PIPE_PRIM_TRIANGLE_FAN,
- 4, /* verts */
- 2); /* attribs/vert */
-
- /* Increment slot */
- st->clear.vbuf_slot++;
-}
-
-
-
-/**
- * Do glClear by drawing a quadrilateral.
- * The vertices of the quad will be computed from the
- * ctx->DrawBuffer->_X/Ymin/max fields.
- */
-static void
-clear_with_quad(struct gl_context *ctx,
- GLboolean color, GLboolean depth, GLboolean stencil)
-{
- struct st_context *st = st_context(ctx);
- const struct gl_framebuffer *fb = ctx->DrawBuffer;
- const GLfloat fb_width = (GLfloat) fb->Width;
- const GLfloat fb_height = (GLfloat) fb->Height;
- const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f;
- const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f;
- const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f;
- const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f;
- float clearColor[4];
-
- /*
- printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__,
- color ? "color, " : "",
- depth ? "depth, " : "",
- stencil ? "stencil" : "",
- x0, y0,
- x1, y1);
- */
-
- cso_save_blend(st->cso_context);
- cso_save_stencil_ref(st->cso_context);
- cso_save_depth_stencil_alpha(st->cso_context);
- cso_save_rasterizer(st->cso_context);
- cso_save_viewport(st->cso_context);
- cso_save_clip(st->cso_context);
- cso_save_fragment_shader(st->cso_context);
- cso_save_vertex_shader(st->cso_context);
- cso_save_vertex_elements(st->cso_context);
- cso_save_vertex_buffers(st->cso_context);
-
- /* blend state: RGBA masking */
- {
- struct pipe_blend_state blend;
- memset(&blend, 0, sizeof(blend));
- blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE;
- blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE;
- blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO;
- blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
- if (color) {
- if (ctx->Color.ColorMask[0][0])
- blend.rt[0].colormask |= PIPE_MASK_R;
- if (ctx->Color.ColorMask[0][1])
- blend.rt[0].colormask |= PIPE_MASK_G;
- if (ctx->Color.ColorMask[0][2])
- blend.rt[0].colormask |= PIPE_MASK_B;
- if (ctx->Color.ColorMask[0][3])
- blend.rt[0].colormask |= PIPE_MASK_A;
- if (st->ctx->Color.DitherFlag)
- blend.dither = 1;
- }
- cso_set_blend(st->cso_context, &blend);
- }
-
- /* depth_stencil state: always pass/set to ref value */
- {
- struct pipe_depth_stencil_alpha_state depth_stencil;
- memset(&depth_stencil, 0, sizeof(depth_stencil));
- if (depth) {
- depth_stencil.depth.enabled = 1;
- depth_stencil.depth.writemask = 1;
- depth_stencil.depth.func = PIPE_FUNC_ALWAYS;
- }
-
- if (stencil) {
- struct pipe_stencil_ref stencil_ref;
- memset(&stencil_ref, 0, sizeof(stencil_ref));
- depth_stencil.stencil[0].enabled = 1;
- depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS;
- depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE;
- depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
- depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE;
- depth_stencil.stencil[0].valuemask = 0xff;
- depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
- stencil_ref.ref_value[0] = ctx->Stencil.Clear;
- cso_set_stencil_ref(st->cso_context, &stencil_ref);
- }
-
- cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil);
- }
-
- cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw);
-
- cso_set_rasterizer(st->cso_context, &st->clear.raster);
-
- /* viewport state: viewport matching window dims */
- {
- const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
- struct pipe_viewport_state vp;
- vp.scale[0] = 0.5f * fb_width;
- vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f);
- 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(st->cso_context, &vp);
- }
-
- cso_set_clip(st->cso_context, &st->clear.clip);
- set_fragment_shader(st);
- set_vertex_shader(st);
-
- if (ctx->DrawBuffer->_ColorDrawBuffers[0]) {
- st_translate_color(ctx->Color.ClearColorUnclamped,
- ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat,
- clearColor);
- }
-
- /* draw quad matching scissor rect */
- draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, clearColor);
-
- /* Restore pipe state */
- cso_restore_blend(st->cso_context);
- cso_restore_stencil_ref(st->cso_context);
- cso_restore_depth_stencil_alpha(st->cso_context);
- cso_restore_rasterizer(st->cso_context);
- cso_restore_viewport(st->cso_context);
- cso_restore_clip(st->cso_context);
- cso_restore_fragment_shader(st->cso_context);
- cso_restore_vertex_shader(st->cso_context);
- cso_restore_vertex_elements(st->cso_context);
- cso_restore_vertex_buffers(st->cso_context);
-}
-
-
-/**
- * Determine if we need to clear the depth buffer by drawing a quad.
- */
-static INLINE GLboolean
-check_clear_color_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb)
-{
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- if (!ctx->Color.ColorMask[0][0] ||
- !ctx->Color.ColorMask[0][1] ||
- !ctx->Color.ColorMask[0][2] ||
- !ctx->Color.ColorMask[0][3])
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Determine if we need to clear the combiend depth/stencil buffer by
- * drawing a quad.
- */
-static INLINE GLboolean
-check_clear_depth_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb)
-{
- const GLuint stencilMax = 0xff;
- GLboolean maskStencil
- = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax;
-
- assert(rb->Format == MESA_FORMAT_S8 ||
- rb->Format == MESA_FORMAT_Z24_S8 ||
- rb->Format == MESA_FORMAT_S8_Z24 ||
- rb->Format == MESA_FORMAT_Z32_FLOAT_X24S8);
-
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- if (maskStencil)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Determine if we need to clear the depth buffer by drawing a quad.
- */
-static INLINE GLboolean
-check_clear_depth_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb,
- boolean ds_separate)
-{
- const struct st_renderbuffer *strb = st_renderbuffer(rb);
- const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format);
-
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- if (!ds_separate && isDS && ctx->DrawBuffer->Visual.stencilBits > 0)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-/**
- * Determine if we need to clear the stencil buffer by drawing a quad.
- */
-static INLINE GLboolean
-check_clear_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb,
- boolean ds_separate)
-{
- const struct st_renderbuffer *strb = st_renderbuffer(rb);
- const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format);
- const GLuint stencilMax = 0xff;
- const GLboolean maskStencil
- = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax;
-
- assert(rb->Format == MESA_FORMAT_S8 ||
- rb->Format == MESA_FORMAT_Z24_S8 ||
- rb->Format == MESA_FORMAT_S8_Z24 ||
- rb->Format == MESA_FORMAT_Z32_FLOAT_X24S8);
-
- if (maskStencil)
- return GL_TRUE;
-
- if (ctx->Scissor.Enabled &&
- (ctx->Scissor.X != 0 ||
- ctx->Scissor.Y != 0 ||
- ctx->Scissor.Width < rb->Width ||
- ctx->Scissor.Height < rb->Height))
- return GL_TRUE;
-
- /* This is correct, but it is necessary to look at the depth clear
- * value held in the surface when it comes time to issue the clear,
- * rather than taking depth and stencil clear values from the
- * current state.
- */
- if (!ds_separate && isDS && ctx->DrawBuffer->Visual.depthBits > 0)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-
-/**
- * Called when we need to flush.
- */
-void
-st_flush_clear(struct st_context *st)
-{
- /* Release vertex buffer to avoid synchronous rendering if we were
- * to map it in the next frame.
- */
- pipe_resource_reference(&st->clear.vbuf, NULL);
- st->clear.vbuf_slot = 0;
-}
-
-
-
-/**
- * Called via ctx->Driver.Clear()
- */
-static void
-st_Clear(struct gl_context *ctx, GLbitfield mask)
-{
- static const GLbitfield BUFFER_BITS_DS
- = (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL);
- struct st_context *st = st_context(ctx);
- struct gl_renderbuffer *depthRb
- = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
- struct gl_renderbuffer *stencilRb
- = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
- GLbitfield quad_buffers = 0x0;
- GLbitfield clear_buffers = 0x0;
- GLuint i;
-
- /* This makes sure the pipe has the latest scissor, etc values */
- st_validate_state( st );
-
- if (mask & BUFFER_BITS_COLOR) {
- for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
- GLuint b = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
-
- if (mask & (1 << b)) {
- struct gl_renderbuffer *rb
- = ctx->DrawBuffer->Attachment[b].Renderbuffer;
- struct st_renderbuffer *strb = st_renderbuffer(rb);
-
- if (!strb || !strb->surface)
- continue;
-
- if (check_clear_color_with_quad( ctx, rb ))
- quad_buffers |= PIPE_CLEAR_COLOR;
- else
- clear_buffers |= PIPE_CLEAR_COLOR;
- }
- }
- }
-
- if ((mask & BUFFER_BITS_DS) == BUFFER_BITS_DS && depthRb == stencilRb) {
- /* clearing combined depth + stencil */
- struct st_renderbuffer *strb = st_renderbuffer(depthRb);
-
- if (strb->surface) {
- if (check_clear_depth_stencil_with_quad(ctx, depthRb))
- quad_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
- else
- clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
- }
- }
- else {
- /* separate depth/stencil clears */
- /* I don't think truly separate buffers are actually possible in gallium or hw? */
- if (mask & BUFFER_BIT_DEPTH) {
- struct st_renderbuffer *strb = st_renderbuffer(depthRb);
-
- if (strb->surface) {
- if (check_clear_depth_with_quad(ctx, depthRb,
- st->clear.enable_ds_separate))
- quad_buffers |= PIPE_CLEAR_DEPTH;
- else
- clear_buffers |= PIPE_CLEAR_DEPTH;
- }
- }
- if (mask & BUFFER_BIT_STENCIL) {
- struct st_renderbuffer *strb = st_renderbuffer(stencilRb);
-
- if (strb->surface) {
- if (check_clear_stencil_with_quad(ctx, stencilRb,
- st->clear.enable_ds_separate))
- quad_buffers |= PIPE_CLEAR_STENCIL;
- else
- clear_buffers |= PIPE_CLEAR_STENCIL;
- }
- }
- }
-
- /*
- * If we're going to use clear_with_quad() for any reason, use it for
- * everything possible.
- */
- if (quad_buffers) {
- quad_buffers |= clear_buffers;
- clear_with_quad(ctx,
- quad_buffers & PIPE_CLEAR_COLOR,
- quad_buffers & PIPE_CLEAR_DEPTH,
- quad_buffers & PIPE_CLEAR_STENCIL);
- } else if (clear_buffers) {
- /* driver cannot know it can clear everything if the buffer
- * is a combined depth/stencil buffer but this wasn't actually
- * required from the visual. Hence fix this up to avoid potential
- * read-modify-write in the driver.
- */
- float clearColor[4];
-
- if ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) &&
- ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) &&
- (depthRb == stencilRb) &&
- (ctx->DrawBuffer->Visual.depthBits == 0 ||
- ctx->DrawBuffer->Visual.stencilBits == 0))
- clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL;
-
- if (ctx->DrawBuffer->_ColorDrawBuffers[0]) {
- st_translate_color(ctx->Color.ClearColor,
- ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat,
- clearColor);
- }
-
- st->pipe->clear(st->pipe, clear_buffers, ctx->Color.ClearColorUnclamped,
- ctx->Depth.Clear, ctx->Stencil.Clear);
- }
- if (mask & BUFFER_BIT_ACCUM)
- st_clear_accum_buffer(ctx,
- ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
-}
-
-
-void
-st_init_clear_functions(struct dd_function_table *functions)
-{
- functions->Clear = st_Clear;
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * Copyright 2009 VMware, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL 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. + * + **************************************************************************/ + + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + * Michel Dänzer + */ + +#include "main/glheader.h" +#include "main/formats.h" +#include "main/macros.h" +#include "program/prog_instruction.h" +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_accum.h" +#include "st_cb_clear.h" +#include "st_cb_fbo.h" +#include "st_format.h" +#include "st_program.h" + +#include "pipe/p_context.h" +#include "pipe/p_shader_tokens.h" +#include "pipe/p_state.h" +#include "pipe/p_defines.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "util/u_simple_shaders.h" +#include "util/u_draw_quad.h" + +#include "cso_cache/cso_context.h" + + +/** + * Do per-context initialization for glClear. + */ +void +st_init_clear(struct st_context *st) +{ + struct pipe_screen *pscreen = st->pipe->screen; + + memset(&st->clear, 0, sizeof(st->clear)); + + st->clear.raster.gl_rasterization_rules = 1; + st->clear.enable_ds_separate = pscreen->get_param(pscreen, PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE); +} + + +/** + * Free per-context state for glClear. + */ +void +st_destroy_clear(struct st_context *st) +{ + if (st->clear.fs) { + cso_delete_fragment_shader(st->cso_context, st->clear.fs); + st->clear.fs = NULL; + } + if (st->clear.vs) { + cso_delete_vertex_shader(st->cso_context, st->clear.vs); + st->clear.vs = NULL; + } + if (st->clear.vbuf) { + pipe_resource_reference(&st->clear.vbuf, NULL); + st->clear.vbuf = NULL; + } +} + + +/** + * Helper function to set the fragment shaders. + */ +static INLINE void +set_fragment_shader(struct st_context *st) +{ + if (!st->clear.fs) + st->clear.fs = util_make_fragment_passthrough_shader(st->pipe); + + cso_set_fragment_shader_handle(st->cso_context, st->clear.fs); +} + + +/** + * Helper function to set the vertex shader. + */ +static INLINE void +set_vertex_shader(struct st_context *st) +{ + /* vertex shader - still required to provide the linkage between + * fragment shader input semantics and vertex_element/buffers. + */ + if (!st->clear.vs) + { + const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_COLOR }; + const uint semantic_indexes[] = { 0, 0 }; + st->clear.vs = util_make_vertex_passthrough_shader(st->pipe, 2, + semantic_names, + semantic_indexes); + } + + cso_set_vertex_shader_handle(st->cso_context, st->clear.vs); +} + + +/** + * Draw a screen-aligned quadrilateral. + * Coords are clip coords with y=0=bottom. + */ +static void +draw_quad(struct st_context *st, + float x0, float y0, float x1, float y1, GLfloat z, + const GLfloat color[4]) +{ + struct pipe_context *pipe = st->pipe; + + /* XXX: Need to improve buffer_write to allow NO_WAIT (as well as + * no_flush) updates to buffers where we know there is no conflict + * with previous data. Currently using max_slots > 1 will cause + * synchronous rendering if the driver flushes its command buffers + * between one bitmap and the next. Our flush hook below isn't + * sufficient to catch this as the driver doesn't tell us when it + * flushes its own command buffers. Until this gets fixed, pay the + * price of allocating a new buffer for each bitmap cache-flush to + * avoid synchronous rendering. + */ + const GLuint max_slots = 1; /* 1024 / sizeof(st->clear.vertices); */ + GLuint i; + + if (st->clear.vbuf_slot >= max_slots) { + pipe_resource_reference(&st->clear.vbuf, NULL); + st->clear.vbuf_slot = 0; + } + + if (!st->clear.vbuf) { + st->clear.vbuf = pipe_buffer_create(pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, + max_slots * sizeof(st->clear.vertices)); + } + + /* positions */ + st->clear.vertices[0][0][0] = x0; + st->clear.vertices[0][0][1] = y0; + + st->clear.vertices[1][0][0] = x1; + st->clear.vertices[1][0][1] = y0; + + st->clear.vertices[2][0][0] = x1; + st->clear.vertices[2][0][1] = y1; + + st->clear.vertices[3][0][0] = x0; + st->clear.vertices[3][0][1] = y1; + + /* same for all verts: */ + for (i = 0; i < 4; i++) { + st->clear.vertices[i][0][2] = z; + st->clear.vertices[i][0][3] = 1.0; + st->clear.vertices[i][1][0] = color[0]; + st->clear.vertices[i][1][1] = color[1]; + st->clear.vertices[i][1][2] = color[2]; + st->clear.vertices[i][1][3] = color[3]; + } + + /* put vertex data into vbuf */ + pipe_buffer_write_nooverlap(st->pipe, st->clear.vbuf, + st->clear.vbuf_slot + * sizeof(st->clear.vertices), + sizeof(st->clear.vertices), + st->clear.vertices); + + /* draw */ + util_draw_vertex_buffer(pipe, + st->cso_context, + st->clear.vbuf, + st->clear.vbuf_slot * sizeof(st->clear.vertices), + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 2); /* attribs/vert */ + + /* Increment slot */ + st->clear.vbuf_slot++; +} + + + +/** + * Do glClear by drawing a quadrilateral. + * The vertices of the quad will be computed from the + * ctx->DrawBuffer->_X/Ymin/max fields. + */ +static void +clear_with_quad(struct gl_context *ctx, + GLboolean color, GLboolean depth, GLboolean stencil) +{ + struct st_context *st = st_context(ctx); + const struct gl_framebuffer *fb = ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat) fb->Width; + const GLfloat fb_height = (GLfloat) fb->Height; + const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f; + const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f; + const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f; + const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f; + float clearColor[4]; + + /* + printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__, + color ? "color, " : "", + depth ? "depth, " : "", + stencil ? "stencil" : "", + x0, y0, + x1, y1); + */ + + cso_save_blend(st->cso_context); + cso_save_stencil_ref(st->cso_context); + cso_save_depth_stencil_alpha(st->cso_context); + cso_save_rasterizer(st->cso_context); + cso_save_viewport(st->cso_context); + cso_save_clip(st->cso_context); + cso_save_fragment_shader(st->cso_context); + cso_save_vertex_shader(st->cso_context); + cso_save_vertex_elements(st->cso_context); + cso_save_vertex_buffers(st->cso_context); + + /* blend state: RGBA masking */ + { + struct pipe_blend_state blend; + memset(&blend, 0, sizeof(blend)); + blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; + blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ZERO; + blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO; + if (color) { + if (ctx->Color.ColorMask[0][0]) + blend.rt[0].colormask |= PIPE_MASK_R; + if (ctx->Color.ColorMask[0][1]) + blend.rt[0].colormask |= PIPE_MASK_G; + if (ctx->Color.ColorMask[0][2]) + blend.rt[0].colormask |= PIPE_MASK_B; + if (ctx->Color.ColorMask[0][3]) + blend.rt[0].colormask |= PIPE_MASK_A; + if (st->ctx->Color.DitherFlag) + blend.dither = 1; + } + cso_set_blend(st->cso_context, &blend); + } + + /* depth_stencil state: always pass/set to ref value */ + { + struct pipe_depth_stencil_alpha_state depth_stencil; + memset(&depth_stencil, 0, sizeof(depth_stencil)); + if (depth) { + depth_stencil.depth.enabled = 1; + depth_stencil.depth.writemask = 1; + depth_stencil.depth.func = PIPE_FUNC_ALWAYS; + } + + if (stencil) { + struct pipe_stencil_ref stencil_ref; + memset(&stencil_ref, 0, sizeof(stencil_ref)); + depth_stencil.stencil[0].enabled = 1; + depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS; + depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; + depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; + depth_stencil.stencil[0].valuemask = 0xff; + depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; + stencil_ref.ref_value[0] = ctx->Stencil.Clear; + cso_set_stencil_ref(st->cso_context, &stencil_ref); + } + + cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil); + } + + cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw); + + cso_set_rasterizer(st->cso_context, &st->clear.raster); + + /* viewport state: viewport matching window dims */ + { + const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); + struct pipe_viewport_state vp; + vp.scale[0] = 0.5f * fb_width; + vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f); + 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(st->cso_context, &vp); + } + + cso_set_clip(st->cso_context, &st->clear.clip); + set_fragment_shader(st); + set_vertex_shader(st); + + if (ctx->DrawBuffer->_ColorDrawBuffers[0]) { + st_translate_color(ctx->Color.ClearColorUnclamped, + ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat, + clearColor); + } + + /* draw quad matching scissor rect */ + draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, clearColor); + + /* Restore pipe state */ + cso_restore_blend(st->cso_context); + cso_restore_stencil_ref(st->cso_context); + cso_restore_depth_stencil_alpha(st->cso_context); + cso_restore_rasterizer(st->cso_context); + cso_restore_viewport(st->cso_context); + cso_restore_clip(st->cso_context); + cso_restore_fragment_shader(st->cso_context); + cso_restore_vertex_shader(st->cso_context); + cso_restore_vertex_elements(st->cso_context); + cso_restore_vertex_buffers(st->cso_context); +} + + +/** + * Determine if we need to clear the depth buffer by drawing a quad. + */ +static INLINE GLboolean +check_clear_color_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb) +{ + if (ctx->Scissor.Enabled && + (ctx->Scissor.X != 0 || + ctx->Scissor.Y != 0 || + ctx->Scissor.Width < rb->Width || + ctx->Scissor.Height < rb->Height)) + return GL_TRUE; + + if (!ctx->Color.ColorMask[0][0] || + !ctx->Color.ColorMask[0][1] || + !ctx->Color.ColorMask[0][2] || + !ctx->Color.ColorMask[0][3]) + return GL_TRUE; + + return GL_FALSE; +} + + +/** + * Determine if we need to clear the combiend depth/stencil buffer by + * drawing a quad. + */ +static INLINE GLboolean +check_clear_depth_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb) +{ + const GLuint stencilMax = 0xff; + GLboolean maskStencil + = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax; + + assert(rb->Format == MESA_FORMAT_S8 || + rb->Format == MESA_FORMAT_Z24_S8 || + rb->Format == MESA_FORMAT_S8_Z24 || + rb->Format == MESA_FORMAT_Z32_FLOAT_X24S8); + + if (ctx->Scissor.Enabled && + (ctx->Scissor.X != 0 || + ctx->Scissor.Y != 0 || + ctx->Scissor.Width < rb->Width || + ctx->Scissor.Height < rb->Height)) + return GL_TRUE; + + if (maskStencil) + return GL_TRUE; + + return GL_FALSE; +} + + +/** + * Determine if we need to clear the depth buffer by drawing a quad. + */ +static INLINE GLboolean +check_clear_depth_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb, + boolean ds_separate) +{ + const struct st_renderbuffer *strb = st_renderbuffer(rb); + const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format); + + if (ctx->Scissor.Enabled && + (ctx->Scissor.X != 0 || + ctx->Scissor.Y != 0 || + ctx->Scissor.Width < rb->Width || + ctx->Scissor.Height < rb->Height)) + return GL_TRUE; + + if (!ds_separate && isDS && ctx->DrawBuffer->Visual.stencilBits > 0) + return GL_TRUE; + + return GL_FALSE; +} + + +/** + * Determine if we need to clear the stencil buffer by drawing a quad. + */ +static INLINE GLboolean +check_clear_stencil_with_quad(struct gl_context *ctx, struct gl_renderbuffer *rb, + boolean ds_separate) +{ + const struct st_renderbuffer *strb = st_renderbuffer(rb); + const GLboolean isDS = util_format_is_depth_and_stencil(strb->surface->format); + const GLuint stencilMax = 0xff; + const GLboolean maskStencil + = (ctx->Stencil.WriteMask[0] & stencilMax) != stencilMax; + + assert(rb->Format == MESA_FORMAT_S8 || + rb->Format == MESA_FORMAT_Z24_S8 || + rb->Format == MESA_FORMAT_S8_Z24 || + rb->Format == MESA_FORMAT_Z32_FLOAT_X24S8); + + if (maskStencil) + return GL_TRUE; + + if (ctx->Scissor.Enabled && + (ctx->Scissor.X != 0 || + ctx->Scissor.Y != 0 || + ctx->Scissor.Width < rb->Width || + ctx->Scissor.Height < rb->Height)) + return GL_TRUE; + + /* This is correct, but it is necessary to look at the depth clear + * value held in the surface when it comes time to issue the clear, + * rather than taking depth and stencil clear values from the + * current state. + */ + if (!ds_separate && isDS && ctx->DrawBuffer->Visual.depthBits > 0) + return GL_TRUE; + + return GL_FALSE; +} + + + +/** + * Called when we need to flush. + */ +void +st_flush_clear(struct st_context *st) +{ + /* Release vertex buffer to avoid synchronous rendering if we were + * to map it in the next frame. + */ + pipe_resource_reference(&st->clear.vbuf, NULL); + st->clear.vbuf_slot = 0; +} + + + +/** + * Called via ctx->Driver.Clear() + */ +static void +st_Clear(struct gl_context *ctx, GLbitfield mask) +{ + static const GLbitfield BUFFER_BITS_DS + = (BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL); + struct st_context *st = st_context(ctx); + struct gl_renderbuffer *depthRb + = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; + struct gl_renderbuffer *stencilRb + = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; + GLbitfield quad_buffers = 0x0; + GLbitfield clear_buffers = 0x0; + GLuint i; + + /* This makes sure the pipe has the latest scissor, etc values */ + st_validate_state( st ); + + if (mask & BUFFER_BITS_COLOR) { + for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { + GLuint b = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; + + if (mask & (1 << b)) { + struct gl_renderbuffer *rb + = ctx->DrawBuffer->Attachment[b].Renderbuffer; + struct st_renderbuffer *strb = st_renderbuffer(rb); + + if (!strb || !strb->surface) + continue; + + if (check_clear_color_with_quad( ctx, rb )) + quad_buffers |= PIPE_CLEAR_COLOR; + else + clear_buffers |= PIPE_CLEAR_COLOR; + } + } + } + + if ((mask & BUFFER_BITS_DS) == BUFFER_BITS_DS && depthRb == stencilRb) { + /* clearing combined depth + stencil */ + struct st_renderbuffer *strb = st_renderbuffer(depthRb); + + if (strb->surface) { + if (check_clear_depth_stencil_with_quad(ctx, depthRb)) + quad_buffers |= PIPE_CLEAR_DEPTHSTENCIL; + else + clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL; + } + } + else { + /* separate depth/stencil clears */ + /* I don't think truly separate buffers are actually possible in gallium or hw? */ + if (mask & BUFFER_BIT_DEPTH) { + struct st_renderbuffer *strb = st_renderbuffer(depthRb); + + if (strb->surface) { + if (check_clear_depth_with_quad(ctx, depthRb, + st->clear.enable_ds_separate)) + quad_buffers |= PIPE_CLEAR_DEPTH; + else + clear_buffers |= PIPE_CLEAR_DEPTH; + } + } + if (mask & BUFFER_BIT_STENCIL) { + struct st_renderbuffer *strb = st_renderbuffer(stencilRb); + + if (strb->surface) { + if (check_clear_stencil_with_quad(ctx, stencilRb, + st->clear.enable_ds_separate)) + quad_buffers |= PIPE_CLEAR_STENCIL; + else + clear_buffers |= PIPE_CLEAR_STENCIL; + } + } + } + + /* + * If we're going to use clear_with_quad() for any reason, use it for + * everything possible. + */ + if (quad_buffers) { + quad_buffers |= clear_buffers; + clear_with_quad(ctx, + quad_buffers & PIPE_CLEAR_COLOR, + quad_buffers & PIPE_CLEAR_DEPTH, + quad_buffers & PIPE_CLEAR_STENCIL); + } else if (clear_buffers) { + /* driver cannot know it can clear everything if the buffer + * is a combined depth/stencil buffer but this wasn't actually + * required from the visual. Hence fix this up to avoid potential + * read-modify-write in the driver. + */ + float clearColor[4]; + + if ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) && + ((clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) != PIPE_CLEAR_DEPTHSTENCIL) && + (depthRb == stencilRb) && + (ctx->DrawBuffer->Visual.depthBits == 0 || + ctx->DrawBuffer->Visual.stencilBits == 0)) + clear_buffers |= PIPE_CLEAR_DEPTHSTENCIL; + + if (ctx->DrawBuffer->_ColorDrawBuffers[0]) { + st_translate_color(ctx->Color.ClearColor, + ctx->DrawBuffer->_ColorDrawBuffers[0]->_BaseFormat, + clearColor); + } + + st->pipe->clear(st->pipe, clear_buffers, ctx->Color.ClearColorUnclamped, + ctx->Depth.Clear, ctx->Stencil.Clear); + } + if (mask & BUFFER_BIT_ACCUM) + st_clear_accum_buffer(ctx, + ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer); +} + + +void +st_init_clear_functions(struct dd_function_table *functions) +{ + functions->Clear = st_Clear; +} diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c index 98616e33b..390c51869 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c @@ -1,1644 +1,1644 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
- /*
- * Authors:
- * Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/bufferobj.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "main/pack.h"
-#include "main/pbo.h"
-#include "main/texformat.h"
-#include "main/teximage.h"
-#include "main/texstore.h"
-#include "program/program.h"
-#include "program/prog_print.h"
-#include "program/prog_instruction.h"
-
-#include "st_atom.h"
-#include "st_atom_constbuf.h"
-#include "st_cb_drawpixels.h"
-#include "st_cb_readpixels.h"
-#include "st_cb_fbo.h"
-#include "st_context.h"
-#include "st_debug.h"
-#include "st_format.h"
-#include "st_program.h"
-#include "st_texture.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "tgsi/tgsi_ureg.h"
-#include "util/u_draw_quad.h"
-#include "util/u_format.h"
-#include "util/u_inlines.h"
-#include "util/u_math.h"
-#include "util/u_tile.h"
-#include "cso_cache/cso_context.h"
-
-
-#if FEATURE_drawpix
-
-/**
- * Check if the given program is:
- * 0: MOVE result.color, fragment.color;
- * 1: END;
- */
-static GLboolean
-is_passthrough_program(const struct gl_fragment_program *prog)
-{
- if (prog->Base.NumInstructions == 2) {
- const struct prog_instruction *inst = prog->Base.Instructions;
- if (inst[0].Opcode == OPCODE_MOV &&
- inst[1].Opcode == OPCODE_END &&
- inst[0].DstReg.File == PROGRAM_OUTPUT &&
- inst[0].DstReg.Index == FRAG_RESULT_COLOR &&
- inst[0].DstReg.WriteMask == WRITEMASK_XYZW &&
- inst[0].SrcReg[0].File == PROGRAM_INPUT &&
- inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 &&
- inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) {
- return GL_TRUE;
- }
- }
- return GL_FALSE;
-}
-
-
-/**
- * Returns a fragment program which implements the current pixel transfer ops.
- */
-static struct gl_fragment_program *
-get_glsl_pixel_transfer_program(struct st_context *st,
- struct st_fragment_program *orig)
-{
- int pixelMaps = 0, scaleAndBias = 0;
- struct gl_context *ctx = st->ctx;
- struct st_fragment_program *fp = (struct st_fragment_program *)
- ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
-
- if (!fp)
- return NULL;
-
- if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 ||
- ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 ||
- ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 ||
- ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) {
- scaleAndBias = 1;
- }
-
- pixelMaps = ctx->Pixel.MapColorFlag;
-
- if (pixelMaps) {
- /* create the colormap/texture now if not already done */
- if (!st->pixel_xfer.pixelmap_texture) {
- st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx);
- st->pixel_xfer.pixelmap_sampler_view =
- st_create_texture_sampler_view(st->pipe,
- st->pixel_xfer.pixelmap_texture);
- }
- }
-
- get_pixel_transfer_visitor(fp, orig->glsl_to_tgsi,
- scaleAndBias, pixelMaps);
-
- return &fp->Base;
-}
-
-
-/**
- * Make fragment shader for glDraw/CopyPixels. This shader is made
- * by combining the pixel transfer shader with the user-defined shader.
- * \param fpIn the current/incoming fragment program
- * \param fpOut returns the combined fragment program
- */
-void
-st_make_drawpix_fragment_program(struct st_context *st,
- struct gl_fragment_program *fpIn,
- struct gl_fragment_program **fpOut)
-{
- struct gl_program *newProg;
- struct st_fragment_program *stfp = (struct st_fragment_program *) fpIn;
-
- if (is_passthrough_program(fpIn)) {
- newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx,
- &st->pixel_xfer.program->Base);
- }
- else if (stfp->glsl_to_tgsi != NULL) {
- newProg = (struct gl_program *) get_glsl_pixel_transfer_program(st, stfp);
- }
- else {
-#if 0
- /* debug */
- printf("Base program:\n");
- _mesa_print_program(&fpIn->Base);
- printf("DrawPix program:\n");
- _mesa_print_program(&st->pixel_xfer.program->Base.Base);
-#endif
- newProg = _mesa_combine_programs(st->ctx,
- &st->pixel_xfer.program->Base.Base,
- &fpIn->Base);
- }
-
-#if 0
- /* debug */
- printf("Combined DrawPixels program:\n");
- _mesa_print_program(newProg);
- printf("InputsRead: 0x%x\n", newProg->InputsRead);
- printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten);
- _mesa_print_parameter_list(newProg->Parameters);
-#endif
-
- *fpOut = (struct gl_fragment_program *) newProg;
-}
-
-
-/**
- * Create fragment program that does a TEX() instruction to get a Z and/or
- * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL.
- * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX).
- * Pass fragment color through as-is.
- * \return pointer to the gl_fragment program
- */
-struct gl_fragment_program *
-st_make_drawpix_z_stencil_program(struct st_context *st,
- GLboolean write_depth,
- GLboolean write_stencil)
-{
- struct gl_context *ctx = st->ctx;
- struct gl_program *p;
- struct gl_fragment_program *fp;
- GLuint ic = 0;
- const GLuint shaderIndex = write_depth * 2 + write_stencil;
-
- assert(shaderIndex < Elements(st->drawpix.shaders));
-
- if (st->drawpix.shaders[shaderIndex]) {
- /* already have the proper shader */
- return st->drawpix.shaders[shaderIndex];
- }
-
- /*
- * Create shader now
- */
- p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
- if (!p)
- return NULL;
-
- p->NumInstructions = write_depth ? 2 : 1;
- p->NumInstructions += write_stencil ? 1 : 0;
-
- p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
- if (!p->Instructions) {
- ctx->Driver.DeleteProgram(ctx, p);
- return NULL;
- }
- _mesa_init_instructions(p->Instructions, p->NumInstructions);
-
- if (write_depth) {
- /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */
- p->Instructions[ic].Opcode = OPCODE_TEX;
- p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
- p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH;
- p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z;
- p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
- p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
- p->Instructions[ic].TexSrcUnit = 0;
- p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
- }
-
- if (write_stencil) {
- /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */
- p->Instructions[ic].Opcode = OPCODE_TEX;
- p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT;
- p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL;
- p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y;
- p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
- p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0;
- p->Instructions[ic].TexSrcUnit = 1;
- p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
- ic++;
- }
-
- /* END; */
- p->Instructions[ic++].Opcode = OPCODE_END;
-
- assert(ic == p->NumInstructions);
-
- p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0;
- p->OutputsWritten = 0;
- if (write_depth)
- p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_DEPTH);
- if (write_stencil)
- p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_STENCIL);
-
- p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */
- if (write_stencil)
- p->SamplersUsed |= 1 << 1;
-
- fp = (struct gl_fragment_program *) p;
-
- /* save the new shader */
- st->drawpix.shaders[shaderIndex] = fp;
-
- return fp;
-}
-
-
-/**
- * Create a simple vertex shader that just passes through the
- * vertex position and texcoord (and optionally, color).
- */
-static void *
-make_passthrough_vertex_shader(struct st_context *st,
- GLboolean passColor)
-{
- if (!st->drawpix.vert_shaders[passColor]) {
- struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX );
-
- if (ureg == NULL)
- return NULL;
-
- /* MOV result.pos, vertex.pos; */
- ureg_MOV(ureg,
- ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ),
- ureg_DECL_vs_input( ureg, 0 ));
-
- /* MOV result.texcoord0, vertex.attr[1]; */
- ureg_MOV(ureg,
- ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ),
- ureg_DECL_vs_input( ureg, 1 ));
-
- if (passColor) {
- /* MOV result.color0, vertex.attr[2]; */
- ureg_MOV(ureg,
- ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ),
- ureg_DECL_vs_input( ureg, 2 ));
- }
-
- ureg_END( ureg );
-
- st->drawpix.vert_shaders[passColor] =
- ureg_create_shader_and_destroy( ureg, st->pipe );
- }
-
- return st->drawpix.vert_shaders[passColor];
-}
-
-
-/**
- * Return a texture internalFormat for drawing/copying an image
- * of the given format and type.
- */
-static GLenum
-internal_format(struct gl_context *ctx, GLenum format, GLenum type)
-{
- switch (format) {
- case GL_DEPTH_COMPONENT:
- switch (type) {
- case GL_UNSIGNED_SHORT:
- return GL_DEPTH_COMPONENT16;
-
- case GL_UNSIGNED_INT:
- return GL_DEPTH_COMPONENT32;
-
- case GL_FLOAT:
- if (ctx->Extensions.ARB_depth_buffer_float)
- return GL_DEPTH_COMPONENT32F;
- else
- return GL_DEPTH_COMPONENT;
-
- default:
- return GL_DEPTH_COMPONENT;
- }
-
- case GL_DEPTH_STENCIL:
- switch (type) {
- case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
- return GL_DEPTH32F_STENCIL8;
-
- case GL_UNSIGNED_INT_24_8:
- default:
- return GL_DEPTH24_STENCIL8;
- }
-
- case GL_STENCIL_INDEX:
- return GL_STENCIL_INDEX;
-
- default:
- if (_mesa_is_integer_format(format)) {
- switch (type) {
- case GL_BYTE:
- return GL_RGBA8I;
- case GL_UNSIGNED_BYTE:
- return GL_RGBA8UI;
- case GL_SHORT:
- return GL_RGBA16I;
- case GL_UNSIGNED_SHORT:
- return GL_RGBA16UI;
- case GL_INT:
- return GL_RGBA32I;
- case GL_UNSIGNED_INT:
- return GL_RGBA32UI;
- default:
- assert(0 && "Unexpected type in internal_format()");
- return GL_RGBA_INTEGER;
- }
- }
- else {
- switch (type) {
- case GL_UNSIGNED_BYTE:
- case GL_UNSIGNED_INT_8_8_8_8:
- case GL_UNSIGNED_INT_8_8_8_8_REV:
- default:
- return GL_RGBA8;
-
- case GL_UNSIGNED_BYTE_3_3_2:
- case GL_UNSIGNED_BYTE_2_3_3_REV:
- case GL_UNSIGNED_SHORT_4_4_4_4:
- case GL_UNSIGNED_SHORT_4_4_4_4_REV:
- return GL_RGBA4;
-
- case GL_UNSIGNED_SHORT_5_6_5:
- case GL_UNSIGNED_SHORT_5_6_5_REV:
- case GL_UNSIGNED_SHORT_5_5_5_1:
- case GL_UNSIGNED_SHORT_1_5_5_5_REV:
- return GL_RGB5_A1;
-
- case GL_UNSIGNED_INT_10_10_10_2:
- case GL_UNSIGNED_INT_2_10_10_10_REV:
- return GL_RGB10_A2;
-
- case GL_UNSIGNED_SHORT:
- case GL_UNSIGNED_INT:
- return GL_RGBA16;
-
- case GL_BYTE:
- return
- ctx->Extensions.EXT_texture_snorm ? GL_RGBA8_SNORM : GL_RGBA8;
-
- case GL_SHORT:
- case GL_INT:
- return
- ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16;
-
- case GL_HALF_FLOAT_ARB:
- return
- ctx->Extensions.ARB_texture_float ? GL_RGBA16F :
- ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16;
-
- case GL_FLOAT:
- case GL_DOUBLE:
- return
- ctx->Extensions.ARB_texture_float ? GL_RGBA32F :
- ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16;
-
- case GL_UNSIGNED_INT_5_9_9_9_REV:
- assert(ctx->Extensions.EXT_texture_shared_exponent);
- return GL_RGB9_E5;
-
- case GL_UNSIGNED_INT_10F_11F_11F_REV:
- assert(ctx->Extensions.EXT_packed_float);
- return GL_R11F_G11F_B10F;
- }
- }
- }
-}
-
-
-/**
- * Create a temporary texture to hold an image of the given size.
- * If width, height are not POT and the driver only handles POT textures,
- * allocate the next larger size of texture that is POT.
- */
-static struct pipe_resource *
-alloc_texture(struct st_context *st, GLsizei width, GLsizei height,
- enum pipe_format texFormat)
-{
- struct pipe_resource *pt;
-
- pt = st_texture_create(st, st->internal_target, texFormat, 0,
- width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW);
-
- return pt;
-}
-
-
-/**
- * Make texture containing an image for glDrawPixels image.
- * If 'pixels' is NULL, leave the texture image data undefined.
- */
-static struct pipe_resource *
-make_texture(struct st_context *st,
- GLsizei width, GLsizei height, GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *unpack,
- const GLvoid *pixels)
-{
- struct gl_context *ctx = st->ctx;
- struct pipe_context *pipe = st->pipe;
- gl_format mformat;
- struct pipe_resource *pt;
- enum pipe_format pipeFormat;
- GLenum baseInternalFormat, intFormat;
-
- intFormat = internal_format(ctx, format, type);
- baseInternalFormat = _mesa_base_tex_format(ctx, intFormat);
-
- mformat = st_ChooseTextureFormat_renderable(ctx, intFormat,
- format, type, GL_FALSE);
- assert(mformat);
-
- pipeFormat = st_mesa_format_to_pipe_format(mformat);
- assert(pipeFormat);
-
- pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
- if (!pixels)
- return NULL;
-
- /* alloc temporary texture */
- pt = alloc_texture(st, width, height, pipeFormat);
- if (!pt) {
- _mesa_unmap_pbo_source(ctx, unpack);
- return NULL;
- }
-
- {
- struct pipe_transfer *transfer;
- static const GLuint dstImageOffsets = 0;
- GLboolean success;
- GLubyte *dest;
- const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
-
- /* we'll do pixel transfer in a fragment shader */
- ctx->_ImageTransferState = 0x0;
-
- transfer = pipe_get_transfer(st->pipe, pt, 0, 0,
- PIPE_TRANSFER_WRITE, 0, 0,
- width, height);
-
- /* map texture transfer */
- dest = pipe_transfer_map(pipe, transfer);
-
-
- /* Put image into texture transfer.
- * Note that the image is actually going to be upside down in
- * the texture. We deal with that with texcoords.
- */
- success = _mesa_texstore(ctx, 2, /* dims */
- baseInternalFormat, /* baseInternalFormat */
- mformat, /* gl_format */
- dest, /* dest */
- 0, 0, 0, /* dstX/Y/Zoffset */
- transfer->stride, /* dstRowStride, bytes */
- &dstImageOffsets, /* dstImageOffsets */
- width, height, 1, /* size */
- format, type, /* src format/type */
- pixels, /* data source */
- unpack);
-
- /* unmap */
- pipe_transfer_unmap(pipe, transfer);
- pipe->transfer_destroy(pipe, transfer);
-
- assert(success);
-
- /* restore */
- ctx->_ImageTransferState = imageTransferStateSave;
- }
-
- _mesa_unmap_pbo_source(ctx, unpack);
-
- return pt;
-}
-
-
-/**
- * Draw quad with texcoords and optional color.
- * Coords are gallium window coords with y=0=top.
- * \param color may be null
- * \param invertTex if true, flip texcoords vertically
- */
-static void
-draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z,
- GLfloat x1, GLfloat y1, const GLfloat *color,
- GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */
-
- /* setup vertex data */
- {
- const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- const GLfloat fb_width = (GLfloat) fb->Width;
- const GLfloat fb_height = (GLfloat) fb->Height;
- const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f;
- const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f;
- const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f;
- const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f;
- const GLfloat sLeft = 0.0f, sRight = maxXcoord;
- const GLfloat tTop = invertTex ? maxYcoord : 0.0f;
- const GLfloat tBot = invertTex ? 0.0f : maxYcoord;
- GLuint i;
-
- /* upper-left */
- verts[0][0][0] = clip_x0; /* v[0].attr[0].x */
- verts[0][0][1] = clip_y0; /* v[0].attr[0].y */
-
- /* upper-right */
- verts[1][0][0] = clip_x1;
- verts[1][0][1] = clip_y0;
-
- /* lower-right */
- verts[2][0][0] = clip_x1;
- verts[2][0][1] = clip_y1;
-
- /* lower-left */
- verts[3][0][0] = clip_x0;
- verts[3][0][1] = clip_y1;
-
- verts[0][1][0] = sLeft; /* v[0].attr[1].S */
- verts[0][1][1] = tTop; /* v[0].attr[1].T */
- verts[1][1][0] = sRight;
- verts[1][1][1] = tTop;
- verts[2][1][0] = sRight;
- verts[2][1][1] = tBot;
- verts[3][1][0] = sLeft;
- verts[3][1][1] = tBot;
-
- /* same for all verts: */
- if (color) {
- for (i = 0; i < 4; i++) {
- verts[i][0][2] = z; /* v[i].attr[0].z */
- verts[i][0][3] = 1.0f; /* v[i].attr[0].w */
- verts[i][2][0] = color[0]; /* v[i].attr[2].r */
- verts[i][2][1] = color[1]; /* v[i].attr[2].g */
- verts[i][2][2] = color[2]; /* v[i].attr[2].b */
- verts[i][2][3] = color[3]; /* v[i].attr[2].a */
- verts[i][1][2] = 0.0f; /* v[i].attr[1].R */
- verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */
- }
- }
- else {
- for (i = 0; i < 4; i++) {
- verts[i][0][2] = z; /*Z*/
- verts[i][0][3] = 1.0f; /*W*/
- verts[i][1][2] = 0.0f; /*R*/
- verts[i][1][3] = 1.0f; /*Q*/
- }
- }
- }
-
- {
- struct pipe_resource *buf;
-
- /* allocate/load buffer object with vertex data */
- buf = pipe_buffer_create(pipe->screen,
- PIPE_BIND_VERTEX_BUFFER,
- PIPE_USAGE_STATIC,
- sizeof(verts));
- pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts);
-
- util_draw_vertex_buffer(pipe, st->cso_context, buf, 0,
- PIPE_PRIM_QUADS,
- 4, /* verts */
- 3); /* attribs/vert */
- pipe_resource_reference(&buf, NULL);
- }
-}
-
-
-
-static void
-draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
- GLsizei width, GLsizei height,
- GLfloat zoomX, GLfloat zoomY,
- struct pipe_sampler_view **sv,
- int num_sampler_view,
- void *driver_vp,
- void *driver_fp,
- const GLfloat *color,
- GLboolean invertTex,
- GLboolean write_depth, GLboolean write_stencil)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct cso_context *cso = st->cso_context;
- GLfloat x0, y0, x1, y1;
- GLsizei maxSize;
- boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT;
-
- /* limit checks */
- /* XXX if DrawPixels image is larger than max texture size, break
- * it up into chunks.
- */
- maxSize = 1 << (pipe->screen->get_param(pipe->screen,
- PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
- assert(width <= maxSize);
- assert(height <= maxSize);
-
- cso_save_rasterizer(cso);
- cso_save_viewport(cso);
- cso_save_samplers(cso);
- cso_save_fragment_sampler_views(cso);
- cso_save_fragment_shader(cso);
- cso_save_vertex_shader(cso);
- cso_save_vertex_elements(cso);
- cso_save_vertex_buffers(cso);
- if (write_stencil) {
- cso_save_depth_stencil_alpha(cso);
- cso_save_blend(cso);
- }
-
- /* rasterizer state: just scissor */
- {
- struct pipe_rasterizer_state rasterizer;
- memset(&rasterizer, 0, sizeof(rasterizer));
- rasterizer.clamp_fragment_color = ctx->Color._ClampFragmentColor;
- rasterizer.gl_rasterization_rules = 1;
- rasterizer.scissor = ctx->Scissor.Enabled;
- cso_set_rasterizer(cso, &rasterizer);
- }
-
- if (write_stencil) {
- /* Stencil writing bypasses the normal fragment pipeline to
- * disable color writing and set stencil test to always pass.
- */
- struct pipe_depth_stencil_alpha_state dsa;
- struct pipe_blend_state blend;
-
- /* depth/stencil */
- memset(&dsa, 0, sizeof(dsa));
- dsa.stencil[0].enabled = 1;
- dsa.stencil[0].func = PIPE_FUNC_ALWAYS;
- dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff;
- dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE;
- if (write_depth) {
- /* writing depth+stencil: depth test always passes */
- dsa.depth.enabled = 1;
- dsa.depth.writemask = ctx->Depth.Mask;
- dsa.depth.func = PIPE_FUNC_ALWAYS;
- }
- cso_set_depth_stencil_alpha(cso, &dsa);
-
- /* blend (colormask) */
- memset(&blend, 0, sizeof(blend));
- cso_set_blend(cso, &blend);
- }
-
- /* fragment shader state: TEX lookup program */
- cso_set_fragment_shader_handle(cso, driver_fp);
-
- /* vertex shader state: position + texcoord pass-through */
- cso_set_vertex_shader_handle(cso, driver_vp);
-
-
- /* texture sampling state: */
- {
- struct pipe_sampler_state sampler;
- memset(&sampler, 0, sizeof(sampler));
- sampler.wrap_s = PIPE_TEX_WRAP_CLAMP;
- sampler.wrap_t = PIPE_TEX_WRAP_CLAMP;
- sampler.wrap_r = PIPE_TEX_WRAP_CLAMP;
- sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST;
- sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
- sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
- sampler.normalized_coords = normalized;
-
- cso_single_sampler(cso, 0, &sampler);
- if (num_sampler_view > 1) {
- cso_single_sampler(cso, 1, &sampler);
- }
- cso_single_sampler_done(cso);
- }
-
- /* viewport state: viewport matching window dims */
- {
- const float w = (float) ctx->DrawBuffer->Width;
- const float h = (float) ctx->DrawBuffer->Height;
- struct pipe_viewport_state vp;
- vp.scale[0] = 0.5f * w;
- vp.scale[1] = -0.5f * h;
- vp.scale[2] = 0.5f;
- vp.scale[3] = 1.0f;
- vp.translate[0] = 0.5f * w;
- vp.translate[1] = 0.5f * h;
- vp.translate[2] = 0.5f;
- vp.translate[3] = 0.0f;
- cso_set_viewport(cso, &vp);
- }
-
- cso_set_vertex_elements(cso, 3, st->velems_util_draw);
-
- /* texture state: */
- cso_set_fragment_sampler_views(cso, num_sampler_view, sv);
-
- /* Compute Gallium window coords (y=0=top) with pixel zoom.
- * Recall that these coords are transformed by the current
- * vertex shader and viewport transformation.
- */
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) {
- y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY);
- invertTex = !invertTex;
- }
-
- x0 = (GLfloat) x;
- x1 = x + width * ctx->Pixel.ZoomX;
- y0 = (GLfloat) y;
- y1 = y + height * ctx->Pixel.ZoomY;
-
- /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */
- z = z * 2.0 - 1.0;
-
- draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex,
- normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width,
- normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height);
-
- /* restore state */
- cso_restore_rasterizer(cso);
- cso_restore_viewport(cso);
- cso_restore_samplers(cso);
- cso_restore_fragment_sampler_views(cso);
- cso_restore_fragment_shader(cso);
- cso_restore_vertex_shader(cso);
- cso_restore_vertex_elements(cso);
- cso_restore_vertex_buffers(cso);
- if (write_stencil) {
- cso_restore_depth_stencil_alpha(cso);
- cso_restore_blend(cso);
- }
-}
-
-
-/**
- * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we
- * can't use a fragment shader to write stencil values.
- */
-static void
-draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y,
- GLsizei width, GLsizei height, GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *unpack,
- const GLvoid *pixels)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct st_renderbuffer *strb;
- enum pipe_transfer_usage usage;
- struct pipe_transfer *pt;
- const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
- GLint skipPixels;
- ubyte *stmap;
- struct gl_pixelstore_attrib clippedUnpack = *unpack;
-
- if (!zoom) {
- if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height,
- &clippedUnpack)) {
- /* totally clipped */
- return;
- }
- }
-
- strb = st_renderbuffer(ctx->DrawBuffer->
- Attachment[BUFFER_STENCIL].Renderbuffer);
-
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
- y = ctx->DrawBuffer->Height - y - height;
- }
-
- if(format != GL_DEPTH_STENCIL &&
- util_format_get_component_bits(strb->format,
- UTIL_FORMAT_COLORSPACE_ZS, 0) != 0)
- usage = PIPE_TRANSFER_READ_WRITE;
- else
- usage = PIPE_TRANSFER_WRITE;
-
- pt = pipe_get_transfer(pipe, strb->texture,
- strb->rtt_level, strb->rtt_face + strb->rtt_slice,
- usage, x, y,
- width, height);
-
- stmap = pipe_transfer_map(pipe, pt);
-
- pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels);
- assert(pixels);
-
- /* if width > MAX_WIDTH, have to process image in chunks */
- skipPixels = 0;
- while (skipPixels < width) {
- const GLint spanX = skipPixels;
- const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH);
- GLint row;
- for (row = 0; row < height; row++) {
- GLubyte sValues[MAX_WIDTH];
- GLuint zValues[MAX_WIDTH];
- GLfloat *zValuesFloat = (GLfloat*)zValues;
- GLenum destType = GL_UNSIGNED_BYTE;
- const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels,
- width, height,
- format, type,
- row, skipPixels);
- _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues,
- type, source, &clippedUnpack,
- ctx->_ImageTransferState);
-
- if (format == GL_DEPTH_STENCIL) {
- GLenum ztype =
- pt->resource->format == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED ?
- GL_FLOAT : GL_UNSIGNED_INT;
-
- _mesa_unpack_depth_span(ctx, spanWidth, ztype, zValues,
- (1 << 24) - 1, type, source,
- &clippedUnpack);
- }
-
- if (zoom) {
- _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with "
- "zoom not complete");
- }
-
- {
- GLint spanY;
-
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
- spanY = height - row - 1;
- }
- else {
- spanY = row;
- }
-
- /* now pack the stencil (and Z) values in the dest format */
- switch (pt->resource->format) {
- case PIPE_FORMAT_S8_USCALED:
- {
- ubyte *dest = stmap + spanY * pt->stride + spanX;
- assert(usage == PIPE_TRANSFER_WRITE);
- memcpy(dest, sValues, spanWidth);
- }
- break;
- case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
- if (format == GL_DEPTH_STENCIL) {
- uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
- GLint k;
- assert(usage == PIPE_TRANSFER_WRITE);
- for (k = 0; k < spanWidth; k++) {
- dest[k] = zValues[k] | (sValues[k] << 24);
- }
- }
- else {
- uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
- GLint k;
- assert(usage == PIPE_TRANSFER_READ_WRITE);
- for (k = 0; k < spanWidth; k++) {
- dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24);
- }
- }
- break;
- case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
- if (format == GL_DEPTH_STENCIL) {
- uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
- GLint k;
- assert(usage == PIPE_TRANSFER_WRITE);
- for (k = 0; k < spanWidth; k++) {
- dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff);
- }
- }
- else {
- uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
- GLint k;
- assert(usage == PIPE_TRANSFER_READ_WRITE);
- for (k = 0; k < spanWidth; k++) {
- dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff);
- }
- }
- break;
- case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
- if (format == GL_DEPTH_STENCIL) {
- uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
- GLfloat *destf = (GLfloat*)dest;
- GLint k;
- assert(usage == PIPE_TRANSFER_WRITE);
- for (k = 0; k < spanWidth; k++) {
- destf[k*2] = zValuesFloat[k];
- dest[k*2+1] = sValues[k] & 0xff;
- }
- }
- else {
- uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4);
- GLint k;
- assert(usage == PIPE_TRANSFER_READ_WRITE);
- for (k = 0; k < spanWidth; k++) {
- dest[k*2+1] = sValues[k] & 0xff;
- }
- }
- break;
- default:
- assert(0);
- }
- }
- }
- skipPixels += spanWidth;
- }
-
- _mesa_unmap_pbo_source(ctx, &clippedUnpack);
-
- /* unmap the stencil buffer */
- pipe_transfer_unmap(pipe, pt);
- pipe->transfer_destroy(pipe, pt);
-}
-
-
-/**
- * Get fragment program variant for a glDrawPixels or glCopyPixels
- * command for RGBA data.
- */
-static struct st_fp_variant *
-get_color_fp_variant(struct st_context *st)
-{
- struct gl_context *ctx = st->ctx;
- struct st_fp_variant_key key;
- struct st_fp_variant *fpv;
-
- memset(&key, 0, sizeof(key));
-
- key.st = st;
- key.drawpixels = 1;
- key.scaleAndBias = (ctx->Pixel.RedBias != 0.0 ||
- ctx->Pixel.RedScale != 1.0 ||
- ctx->Pixel.GreenBias != 0.0 ||
- ctx->Pixel.GreenScale != 1.0 ||
- ctx->Pixel.BlueBias != 0.0 ||
- ctx->Pixel.BlueScale != 1.0 ||
- ctx->Pixel.AlphaBias != 0.0 ||
- ctx->Pixel.AlphaScale != 1.0);
- key.pixelMaps = ctx->Pixel.MapColorFlag;
-
- fpv = st_get_fp_variant(st, st->fp, &key);
-
- return fpv;
-}
-
-
-/**
- * Get fragment program variant for a glDrawPixels or glCopyPixels
- * command for depth/stencil data.
- */
-static struct st_fp_variant *
-get_depth_stencil_fp_variant(struct st_context *st, GLboolean write_depth,
- GLboolean write_stencil)
-{
- struct st_fp_variant_key key;
- struct st_fp_variant *fpv;
-
- memset(&key, 0, sizeof(key));
-
- key.st = st;
- key.drawpixels = 1;
- key.drawpixels_z = write_depth;
- key.drawpixels_stencil = write_stencil;
-
- fpv = st_get_fp_variant(st, st->fp, &key);
-
- return fpv;
-}
-
-
-/**
- * Called via ctx->Driver.DrawPixels()
- */
-static void
-st_DrawPixels(struct gl_context *ctx, GLint x, GLint y,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels)
-{
- void *driver_vp, *driver_fp;
- struct st_context *st = st_context(ctx);
- const GLfloat *color;
- struct pipe_context *pipe = st->pipe;
- GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE;
- struct pipe_sampler_view *sv[2];
- int num_sampler_view = 1;
- struct st_fp_variant *fpv;
-
- if (format == GL_DEPTH_STENCIL)
- write_stencil = write_depth = GL_TRUE;
- else if (format == GL_STENCIL_INDEX)
- write_stencil = GL_TRUE;
- else if (format == GL_DEPTH_COMPONENT)
- write_depth = GL_TRUE;
-
- if (write_stencil &&
- !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) {
- /* software fallback */
- draw_stencil_pixels(ctx, x, y, width, height, format, type,
- unpack, pixels);
- return;
- }
-
- /* Mesa state should be up to date by now */
- assert(ctx->NewState == 0x0);
-
- st_validate_state(st);
-
- /*
- * Get vertex/fragment shaders
- */
- if (write_depth || write_stencil) {
- fpv = get_depth_stencil_fp_variant(st, write_depth, write_stencil);
-
- driver_fp = fpv->driver_shader;
-
- driver_vp = make_passthrough_vertex_shader(st, GL_TRUE);
-
- color = ctx->Current.RasterColor;
- }
- else {
- fpv = get_color_fp_variant(st);
-
- driver_fp = fpv->driver_shader;
-
- driver_vp = make_passthrough_vertex_shader(st, GL_FALSE);
-
- color = NULL;
- if (st->pixel_xfer.pixelmap_enabled) {
- sv[1] = st->pixel_xfer.pixelmap_sampler_view;
- num_sampler_view++;
- }
- }
-
- /* update fragment program constants */
- st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT);
-
- /* draw with textured quad */
- {
- struct pipe_resource *pt
- = make_texture(st, width, height, format, type, unpack, pixels);
- if (pt) {
- sv[0] = st_create_texture_sampler_view(st->pipe, pt);
-
- if (sv[0]) {
- /* Create a second sampler view to read stencil.
- * The stencil is written using the shader stencil export
- * functionality. */
- if (write_stencil) {
- enum pipe_format stencil_format = PIPE_FORMAT_NONE;
-
- switch (pt->format) {
- case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
- case PIPE_FORMAT_X24S8_USCALED:
- stencil_format = PIPE_FORMAT_X24S8_USCALED;
- break;
- case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
- case PIPE_FORMAT_S8X24_USCALED:
- stencil_format = PIPE_FORMAT_S8X24_USCALED;
- break;
- case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
- case PIPE_FORMAT_X32_S8X24_USCALED:
- stencil_format = PIPE_FORMAT_X32_S8X24_USCALED;
- break;
- case PIPE_FORMAT_S8_USCALED:
- stencil_format = PIPE_FORMAT_S8_USCALED;
- break;
- default:
- assert(0);
- }
-
- sv[1] = st_create_texture_sampler_view_format(st->pipe, pt,
- stencil_format);
- num_sampler_view++;
- }
-
- draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
- width, height,
- ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
- sv,
- num_sampler_view,
- driver_vp,
- driver_fp,
- color, GL_FALSE, write_depth, write_stencil);
- pipe_sampler_view_reference(&sv[0], NULL);
- if (num_sampler_view > 1)
- pipe_sampler_view_reference(&sv[1], NULL);
- }
- pipe_resource_reference(&pt, NULL);
- }
- }
-}
-
-
-
-/**
- * Software fallback for glCopyPixels(GL_STENCIL).
- */
-static void
-copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
- GLsizei width, GLsizei height,
- GLint dstx, GLint dsty)
-{
- struct st_renderbuffer *rbDraw;
- struct pipe_context *pipe = st_context(ctx)->pipe;
- enum pipe_transfer_usage usage;
- struct pipe_transfer *ptDraw;
- ubyte *drawMap;
- ubyte *buffer;
- int i;
-
- buffer = malloc(width * height * sizeof(ubyte));
- if (!buffer) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)");
- return;
- }
-
- /* Get the dest renderbuffer. If there's a wrapper, use the
- * underlying renderbuffer.
- */
- rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer);
- if (rbDraw->Base.Wrapped)
- rbDraw = st_renderbuffer(rbDraw->Base.Wrapped);
-
- /* this will do stencil pixel transfer ops */
- st_read_stencil_pixels(ctx, srcx, srcy, width, height,
- GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
- &ctx->DefaultPacking, buffer);
-
- if (0) {
- /* debug code: dump stencil values */
- GLint row, col;
- for (row = 0; row < height; row++) {
- printf("%3d: ", row);
- for (col = 0; col < width; col++) {
- printf("%02x ", buffer[col + row * width]);
- }
- printf("\n");
- }
- }
-
- if (util_format_get_component_bits(rbDraw->format,
- UTIL_FORMAT_COLORSPACE_ZS, 0) != 0)
- usage = PIPE_TRANSFER_READ_WRITE;
- else
- usage = PIPE_TRANSFER_WRITE;
-
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
- dsty = rbDraw->Base.Height - dsty - height;
- }
-
- ptDraw = pipe_get_transfer(pipe,
- rbDraw->texture,
- rbDraw->rtt_level,
- rbDraw->rtt_face + rbDraw->rtt_slice,
- usage, dstx, dsty,
- width, height);
-
- assert(util_format_get_blockwidth(ptDraw->resource->format) == 1);
- assert(util_format_get_blockheight(ptDraw->resource->format) == 1);
-
- /* map the stencil buffer */
- drawMap = pipe_transfer_map(pipe, ptDraw);
-
- /* draw */
- /* XXX PixelZoom not handled yet */
- for (i = 0; i < height; i++) {
- ubyte *dst;
- const ubyte *src;
- int y;
-
- y = i;
-
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
- y = height - y - 1;
- }
-
- dst = drawMap + y * ptDraw->stride;
- src = buffer + i * width;
-
- switch (ptDraw->resource->format) {
- case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
- {
- uint *dst4 = (uint *) dst;
- int j;
- assert(usage == PIPE_TRANSFER_READ_WRITE);
- for (j = 0; j < width; j++) {
- *dst4 = (*dst4 & 0xffffff) | (src[j] << 24);
- dst4++;
- }
- }
- break;
- case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
- {
- uint *dst4 = (uint *) dst;
- int j;
- assert(usage == PIPE_TRANSFER_READ_WRITE);
- for (j = 0; j < width; j++) {
- *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff);
- dst4++;
- }
- }
- break;
- case PIPE_FORMAT_S8_USCALED:
- assert(usage == PIPE_TRANSFER_WRITE);
- memcpy(dst, src, width);
- break;
- case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
- {
- uint *dst4 = (uint *) dst;
- int j;
- dst4++;
- assert(usage == PIPE_TRANSFER_READ_WRITE);
- for (j = 0; j < width; j++) {
- *dst4 = src[j] & 0xff;
- dst4 += 2;
- }
- }
- break;
- default:
- assert(0);
- }
- }
-
- free(buffer);
-
- /* unmap the stencil buffer */
- pipe_transfer_unmap(pipe, ptDraw);
- pipe->transfer_destroy(pipe, ptDraw);
-}
-
-
-/** Do the src/dest regions overlap? */
-static GLboolean
-regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY,
- GLsizei width, GLsizei height)
-{
- if (srcX + width <= dstX ||
- dstX + width <= srcX ||
- srcY + height <= dstY ||
- dstY + height <= srcY)
- return GL_FALSE;
- else
- return GL_TRUE;
-}
-
-
-/**
- * Try to do a glCopyPixels for simple cases with a blit by calling
- * pipe->resource_copy_region().
- *
- * We can do this when we're copying color pixels (depth/stencil
- * eventually) with no pixel zoom, no pixel transfer ops, no
- * per-fragment ops, the src/dest regions don't overlap and the
- * src/dest pixel formats are the same.
- */
-static GLboolean
-blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
- GLsizei width, GLsizei height,
- GLint dstx, GLint dsty, GLenum type)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct gl_pixelstore_attrib pack, unpack;
- GLint readX, readY, readW, readH;
-
- if (type == GL_COLOR &&
- ctx->Pixel.ZoomX == 1.0 &&
- ctx->Pixel.ZoomY == 1.0 &&
- ctx->_ImageTransferState == 0x0 &&
- !ctx->Color.BlendEnabled &&
- !ctx->Color.AlphaEnabled &&
- !ctx->Depth.Test &&
- !ctx->Fog.Enabled &&
- !ctx->Stencil.Enabled &&
- !ctx->FragmentProgram.Enabled &&
- !ctx->VertexProgram.Enabled &&
- !ctx->Shader.CurrentFragmentProgram &&
- st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) &&
- ctx->DrawBuffer->_NumColorDrawBuffers == 1 &&
- !ctx->Query.CondRenderQuery) {
- struct st_renderbuffer *rbRead, *rbDraw;
- GLint drawX, drawY;
-
- /*
- * Clip the read region against the src buffer bounds.
- * We'll still allocate a temporary buffer/texture for the original
- * src region size but we'll only read the region which is on-screen.
- * This may mean that we draw garbage pixels into the dest region, but
- * that's expected.
- */
- readX = srcx;
- readY = srcy;
- readW = width;
- readH = height;
- pack = ctx->DefaultPacking;
- if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack))
- return GL_TRUE; /* all done */
-
- /* clip against dest buffer bounds and scissor box */
- drawX = dstx + pack.SkipPixels;
- drawY = dsty + pack.SkipRows;
- unpack = pack;
- if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack))
- return GL_TRUE; /* all done */
-
- readX = readX - pack.SkipPixels + unpack.SkipPixels;
- readY = readY - pack.SkipRows + unpack.SkipRows;
-
- rbRead = st_get_color_read_renderbuffer(ctx);
- rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
-
- if ((rbRead != rbDraw ||
- !regions_overlap(readX, readY, drawX, drawY, readW, readH)) &&
- rbRead->Base.Format == rbDraw->Base.Format) {
- struct pipe_box srcBox;
-
- /* flip src/dst position if needed */
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- /* both buffers will have the same orientation */
- readY = ctx->ReadBuffer->Height - readY - readH;
- drawY = ctx->DrawBuffer->Height - drawY - readH;
- }
-
- u_box_2d(readX, readY, readW, readH, &srcBox);
-
- pipe->resource_copy_region(pipe,
- rbDraw->texture,
- rbDraw->rtt_level, drawX, drawY, 0,
- rbRead->texture,
- rbRead->rtt_level, &srcBox);
- return GL_TRUE;
- }
- }
-
- return GL_FALSE;
-}
-
-
-static void
-st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
- GLsizei width, GLsizei height,
- GLint dstx, GLint dsty, GLenum type)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_screen *screen = pipe->screen;
- struct st_renderbuffer *rbRead;
- void *driver_vp, *driver_fp;
- struct pipe_resource *pt;
- struct pipe_sampler_view *sv[2];
- int num_sampler_view = 1;
- GLfloat *color;
- enum pipe_format srcFormat, texFormat;
- GLboolean invertTex = GL_FALSE;
- GLint readX, readY, readW, readH;
- GLuint sample_count;
- struct gl_pixelstore_attrib pack = ctx->DefaultPacking;
- struct st_fp_variant *fpv;
-
- st_validate_state(st);
-
- if (type == GL_STENCIL) {
- /* can't use texturing to do stencil */
- copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
- return;
- }
-
- if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type))
- return;
-
- /*
- * The subsequent code implements glCopyPixels by copying the source
- * pixels into a temporary texture that's then applied to a textured quad.
- * When we draw the textured quad, all the usual per-fragment operations
- * are handled.
- */
-
-
- /*
- * Get vertex/fragment shaders
- */
- if (type == GL_COLOR) {
- rbRead = st_get_color_read_renderbuffer(ctx);
- color = NULL;
-
- fpv = get_color_fp_variant(st);
- driver_fp = fpv->driver_shader;
-
- driver_vp = make_passthrough_vertex_shader(st, GL_FALSE);
-
- if (st->pixel_xfer.pixelmap_enabled) {
- sv[1] = st->pixel_xfer.pixelmap_sampler_view;
- num_sampler_view++;
- }
- }
- else {
- assert(type == GL_DEPTH);
- rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
- color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
-
- fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE);
- driver_fp = fpv->driver_shader;
-
- driver_vp = make_passthrough_vertex_shader(st, GL_TRUE);
- }
-
- /* update fragment program constants */
- st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT);
-
-
- if (rbRead->Base.Wrapped)
- rbRead = st_renderbuffer(rbRead->Base.Wrapped);
-
- sample_count = rbRead->texture->nr_samples;
- /* I believe this would be legal, presumably would need to do a resolve
- for color, and for depth/stencil spec says to just use one of the
- depth/stencil samples per pixel? Need some transfer clarifications. */
- assert(sample_count < 2);
-
- srcFormat = rbRead->texture->format;
-
- if (screen->is_format_supported(screen, srcFormat, st->internal_target,
- sample_count,
- PIPE_BIND_SAMPLER_VIEW)) {
- texFormat = srcFormat;
- }
- else {
- /* srcFormat can't be used as a texture format */
- if (type == GL_DEPTH) {
- texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT,
- GL_NONE, GL_NONE, st->internal_target,
- sample_count, PIPE_BIND_DEPTH_STENCIL);
- assert(texFormat != PIPE_FORMAT_NONE);
- }
- else {
- /* default color format */
- texFormat = st_choose_format(screen, GL_RGBA,
- GL_NONE, GL_NONE, st->internal_target,
- sample_count, PIPE_BIND_SAMPLER_VIEW);
- assert(texFormat != PIPE_FORMAT_NONE);
- }
- }
-
- /* Invert src region if needed */
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- srcy = ctx->ReadBuffer->Height - srcy - height;
- invertTex = !invertTex;
- }
-
- /* Clip the read region against the src buffer bounds.
- * We'll still allocate a temporary buffer/texture for the original
- * src region size but we'll only read the region which is on-screen.
- * This may mean that we draw garbage pixels into the dest region, but
- * that's expected.
- */
- readX = srcx;
- readY = srcy;
- readW = width;
- readH = height;
- _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack);
- readW = MAX2(0, readW);
- readH = MAX2(0, readH);
-
- /* alloc temporary texture */
- pt = alloc_texture(st, width, height, texFormat);
- if (!pt)
- return;
-
- sv[0] = st_create_texture_sampler_view(st->pipe, pt);
- if (!sv[0]) {
- pipe_resource_reference(&pt, NULL);
- return;
- }
-
- /* Make temporary texture which is a copy of the src region.
- */
- if (srcFormat == texFormat) {
- struct pipe_box src_box;
- u_box_2d(readX, readY, readW, readH, &src_box);
- /* copy source framebuffer surface into mipmap/texture */
- pipe->resource_copy_region(pipe,
- pt, /* dest tex */
- 0, /* dest lvl */
- pack.SkipPixels, pack.SkipRows, 0, /* dest pos */
- rbRead->texture, /* src tex */
- rbRead->rtt_level, /* src lvl */
- &src_box);
-
- }
- else {
- /* CPU-based fallback/conversion */
- struct pipe_transfer *ptRead =
- pipe_get_transfer(st->pipe, rbRead->texture,
- rbRead->rtt_level,
- rbRead->rtt_face + rbRead->rtt_slice,
- PIPE_TRANSFER_READ,
- readX, readY, readW, readH);
- struct pipe_transfer *ptTex;
- enum pipe_transfer_usage transfer_usage;
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback processing\n", __FUNCTION__);
-
- if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format))
- transfer_usage = PIPE_TRANSFER_READ_WRITE;
- else
- transfer_usage = PIPE_TRANSFER_WRITE;
-
- ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage,
- 0, 0, width, height);
-
- /* copy image from ptRead surface to ptTex surface */
- if (type == GL_COLOR) {
- /* alternate path using get/put_tile() */
- GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
- enum pipe_format readFormat, drawFormat;
- readFormat = util_format_linear(rbRead->texture->format);
- drawFormat = util_format_linear(pt->format);
- pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH,
- readFormat, buf);
- pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows,
- readW, readH, drawFormat, buf);
- free(buf);
- }
- else {
- /* GL_DEPTH */
- GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint));
- pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf);
- pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows,
- readW, readH, buf);
- free(buf);
- }
-
- pipe->transfer_destroy(pipe, ptRead);
- pipe->transfer_destroy(pipe, ptTex);
- }
-
- /* OK, the texture 'pt' contains the src image/pixels. Now draw a
- * textured quad with that texture.
- */
- draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2],
- width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
- sv,
- num_sampler_view,
- driver_vp,
- driver_fp,
- color, invertTex, GL_FALSE, GL_FALSE);
-
- pipe_resource_reference(&pt, NULL);
- pipe_sampler_view_reference(&sv[0], NULL);
-}
-
-
-
-void st_init_drawpixels_functions(struct dd_function_table *functions)
-{
- functions->DrawPixels = st_DrawPixels;
- functions->CopyPixels = st_CopyPixels;
-}
-
-
-void
-st_destroy_drawpix(struct st_context *st)
-{
- GLuint i;
-
- for (i = 0; i < Elements(st->drawpix.shaders); i++) {
- if (st->drawpix.shaders[i])
- _mesa_reference_fragprog(st->ctx, &st->drawpix.shaders[i], NULL);
- }
-
- st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL);
- if (st->drawpix.vert_shaders[0])
- ureg_free_tokens(st->drawpix.vert_shaders[0]);
- if (st->drawpix.vert_shaders[1])
- ureg_free_tokens(st->drawpix.vert_shaders[1]);
-}
-
-#endif /* FEATURE_drawpix */
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + /* + * Authors: + * Brian Paul + */ + +#include "main/imports.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/macros.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "main/pack.h" +#include "main/pbo.h" +#include "main/texformat.h" +#include "main/teximage.h" +#include "main/texstore.h" +#include "program/program.h" +#include "program/prog_print.h" +#include "program/prog_instruction.h" + +#include "st_atom.h" +#include "st_atom_constbuf.h" +#include "st_cb_drawpixels.h" +#include "st_cb_readpixels.h" +#include "st_cb_fbo.h" +#include "st_context.h" +#include "st_debug.h" +#include "st_format.h" +#include "st_program.h" +#include "st_texture.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "tgsi/tgsi_ureg.h" +#include "util/u_draw_quad.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "util/u_math.h" +#include "util/u_tile.h" +#include "cso_cache/cso_context.h" + + +#if FEATURE_drawpix + +/** + * Check if the given program is: + * 0: MOVE result.color, fragment.color; + * 1: END; + */ +static GLboolean +is_passthrough_program(const struct gl_fragment_program *prog) +{ + if (prog->Base.NumInstructions == 2) { + const struct prog_instruction *inst = prog->Base.Instructions; + if (inst[0].Opcode == OPCODE_MOV && + inst[1].Opcode == OPCODE_END && + inst[0].DstReg.File == PROGRAM_OUTPUT && + inst[0].DstReg.Index == FRAG_RESULT_COLOR && + inst[0].DstReg.WriteMask == WRITEMASK_XYZW && + inst[0].SrcReg[0].File == PROGRAM_INPUT && + inst[0].SrcReg[0].Index == FRAG_ATTRIB_COL0 && + inst[0].SrcReg[0].Swizzle == SWIZZLE_XYZW) { + return GL_TRUE; + } + } + return GL_FALSE; +} + + +/** + * Returns a fragment program which implements the current pixel transfer ops. + */ +static struct gl_fragment_program * +get_glsl_pixel_transfer_program(struct st_context *st, + struct st_fragment_program *orig) +{ + int pixelMaps = 0, scaleAndBias = 0; + struct gl_context *ctx = st->ctx; + struct st_fragment_program *fp = (struct st_fragment_program *) + ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + + if (!fp) + return NULL; + + if (ctx->Pixel.RedBias != 0.0 || ctx->Pixel.RedScale != 1.0 || + ctx->Pixel.GreenBias != 0.0 || ctx->Pixel.GreenScale != 1.0 || + ctx->Pixel.BlueBias != 0.0 || ctx->Pixel.BlueScale != 1.0 || + ctx->Pixel.AlphaBias != 0.0 || ctx->Pixel.AlphaScale != 1.0) { + scaleAndBias = 1; + } + + pixelMaps = ctx->Pixel.MapColorFlag; + + if (pixelMaps) { + /* create the colormap/texture now if not already done */ + if (!st->pixel_xfer.pixelmap_texture) { + st->pixel_xfer.pixelmap_texture = st_create_color_map_texture(ctx); + st->pixel_xfer.pixelmap_sampler_view = + st_create_texture_sampler_view(st->pipe, + st->pixel_xfer.pixelmap_texture); + } + } + + get_pixel_transfer_visitor(fp, orig->glsl_to_tgsi, + scaleAndBias, pixelMaps); + + return &fp->Base; +} + + +/** + * Make fragment shader for glDraw/CopyPixels. This shader is made + * by combining the pixel transfer shader with the user-defined shader. + * \param fpIn the current/incoming fragment program + * \param fpOut returns the combined fragment program + */ +void +st_make_drawpix_fragment_program(struct st_context *st, + struct gl_fragment_program *fpIn, + struct gl_fragment_program **fpOut) +{ + struct gl_program *newProg; + struct st_fragment_program *stfp = (struct st_fragment_program *) fpIn; + + if (is_passthrough_program(fpIn)) { + newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, + &st->pixel_xfer.program->Base); + } + else if (stfp->glsl_to_tgsi != NULL) { + newProg = (struct gl_program *) get_glsl_pixel_transfer_program(st, stfp); + } + else { +#if 0 + /* debug */ + printf("Base program:\n"); + _mesa_print_program(&fpIn->Base); + printf("DrawPix program:\n"); + _mesa_print_program(&st->pixel_xfer.program->Base.Base); +#endif + newProg = _mesa_combine_programs(st->ctx, + &st->pixel_xfer.program->Base.Base, + &fpIn->Base); + } + +#if 0 + /* debug */ + printf("Combined DrawPixels program:\n"); + _mesa_print_program(newProg); + printf("InputsRead: 0x%x\n", newProg->InputsRead); + printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten); + _mesa_print_parameter_list(newProg->Parameters); +#endif + + *fpOut = (struct gl_fragment_program *) newProg; +} + + +/** + * Create fragment program that does a TEX() instruction to get a Z and/or + * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. + * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). + * Pass fragment color through as-is. + * \return pointer to the gl_fragment program + */ +struct gl_fragment_program * +st_make_drawpix_z_stencil_program(struct st_context *st, + GLboolean write_depth, + GLboolean write_stencil) +{ + struct gl_context *ctx = st->ctx; + struct gl_program *p; + struct gl_fragment_program *fp; + GLuint ic = 0; + const GLuint shaderIndex = write_depth * 2 + write_stencil; + + assert(shaderIndex < Elements(st->drawpix.shaders)); + + if (st->drawpix.shaders[shaderIndex]) { + /* already have the proper shader */ + return st->drawpix.shaders[shaderIndex]; + } + + /* + * Create shader now + */ + p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!p) + return NULL; + + p->NumInstructions = write_depth ? 2 : 1; + p->NumInstructions += write_stencil ? 1 : 0; + + p->Instructions = _mesa_alloc_instructions(p->NumInstructions); + if (!p->Instructions) { + ctx->Driver.DeleteProgram(ctx, p); + return NULL; + } + _mesa_init_instructions(p->Instructions, p->NumInstructions); + + if (write_depth) { + /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 0; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } + + if (write_stencil) { + /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 1; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } + + /* END; */ + p->Instructions[ic++].Opcode = OPCODE_END; + + assert(ic == p->NumInstructions); + + p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; + p->OutputsWritten = 0; + if (write_depth) + p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_DEPTH); + if (write_stencil) + p->OutputsWritten |= BITFIELD64_BIT(FRAG_RESULT_STENCIL); + + p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + if (write_stencil) + p->SamplersUsed |= 1 << 1; + + fp = (struct gl_fragment_program *) p; + + /* save the new shader */ + st->drawpix.shaders[shaderIndex] = fp; + + return fp; +} + + +/** + * Create a simple vertex shader that just passes through the + * vertex position and texcoord (and optionally, color). + */ +static void * +make_passthrough_vertex_shader(struct st_context *st, + GLboolean passColor) +{ + if (!st->drawpix.vert_shaders[passColor]) { + struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); + + if (ureg == NULL) + return NULL; + + /* MOV result.pos, vertex.pos; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), + ureg_DECL_vs_input( ureg, 0 )); + + /* MOV result.texcoord0, vertex.attr[1]; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ), + ureg_DECL_vs_input( ureg, 1 )); + + if (passColor) { + /* MOV result.color0, vertex.attr[2]; */ + ureg_MOV(ureg, + ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), + ureg_DECL_vs_input( ureg, 2 )); + } + + ureg_END( ureg ); + + st->drawpix.vert_shaders[passColor] = + ureg_create_shader_and_destroy( ureg, st->pipe ); + } + + return st->drawpix.vert_shaders[passColor]; +} + + +/** + * Return a texture internalFormat for drawing/copying an image + * of the given format and type. + */ +static GLenum +internal_format(struct gl_context *ctx, GLenum format, GLenum type) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + switch (type) { + case GL_UNSIGNED_SHORT: + return GL_DEPTH_COMPONENT16; + + case GL_UNSIGNED_INT: + return GL_DEPTH_COMPONENT32; + + case GL_FLOAT: + if (ctx->Extensions.ARB_depth_buffer_float) + return GL_DEPTH_COMPONENT32F; + else + return GL_DEPTH_COMPONENT; + + default: + return GL_DEPTH_COMPONENT; + } + + case GL_DEPTH_STENCIL: + switch (type) { + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return GL_DEPTH32F_STENCIL8; + + case GL_UNSIGNED_INT_24_8: + default: + return GL_DEPTH24_STENCIL8; + } + + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + + default: + if (_mesa_is_integer_format(format)) { + switch (type) { + case GL_BYTE: + return GL_RGBA8I; + case GL_UNSIGNED_BYTE: + return GL_RGBA8UI; + case GL_SHORT: + return GL_RGBA16I; + case GL_UNSIGNED_SHORT: + return GL_RGBA16UI; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + default: + assert(0 && "Unexpected type in internal_format()"); + return GL_RGBA_INTEGER; + } + } + else { + switch (type) { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + default: + return GL_RGBA8; + + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + return GL_RGBA4; + + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + return GL_RGB5_A1; + + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + return GL_RGB10_A2; + + case GL_UNSIGNED_SHORT: + case GL_UNSIGNED_INT: + return GL_RGBA16; + + case GL_BYTE: + return + ctx->Extensions.EXT_texture_snorm ? GL_RGBA8_SNORM : GL_RGBA8; + + case GL_SHORT: + case GL_INT: + return + ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; + + case GL_HALF_FLOAT_ARB: + return + ctx->Extensions.ARB_texture_float ? GL_RGBA16F : + ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; + + case GL_FLOAT: + case GL_DOUBLE: + return + ctx->Extensions.ARB_texture_float ? GL_RGBA32F : + ctx->Extensions.EXT_texture_snorm ? GL_RGBA16_SNORM : GL_RGBA16; + + case GL_UNSIGNED_INT_5_9_9_9_REV: + assert(ctx->Extensions.EXT_texture_shared_exponent); + return GL_RGB9_E5; + + case GL_UNSIGNED_INT_10F_11F_11F_REV: + assert(ctx->Extensions.EXT_packed_float); + return GL_R11F_G11F_B10F; + } + } + } +} + + +/** + * Create a temporary texture to hold an image of the given size. + * If width, height are not POT and the driver only handles POT textures, + * allocate the next larger size of texture that is POT. + */ +static struct pipe_resource * +alloc_texture(struct st_context *st, GLsizei width, GLsizei height, + enum pipe_format texFormat) +{ + struct pipe_resource *pt; + + pt = st_texture_create(st, st->internal_target, texFormat, 0, + width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); + + return pt; +} + + +/** + * Make texture containing an image for glDrawPixels image. + * If 'pixels' is NULL, leave the texture image data undefined. + */ +static struct pipe_resource * +make_texture(struct st_context *st, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct gl_context *ctx = st->ctx; + struct pipe_context *pipe = st->pipe; + gl_format mformat; + struct pipe_resource *pt; + enum pipe_format pipeFormat; + GLenum baseInternalFormat, intFormat; + + intFormat = internal_format(ctx, format, type); + baseInternalFormat = _mesa_base_tex_format(ctx, intFormat); + + mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, + format, type, GL_FALSE); + assert(mformat); + + pipeFormat = st_mesa_format_to_pipe_format(mformat); + assert(pipeFormat); + + pixels = _mesa_map_pbo_source(ctx, unpack, pixels); + if (!pixels) + return NULL; + + /* alloc temporary texture */ + pt = alloc_texture(st, width, height, pipeFormat); + if (!pt) { + _mesa_unmap_pbo_source(ctx, unpack); + return NULL; + } + + { + struct pipe_transfer *transfer; + static const GLuint dstImageOffsets = 0; + GLboolean success; + GLubyte *dest; + const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; + + /* we'll do pixel transfer in a fragment shader */ + ctx->_ImageTransferState = 0x0; + + transfer = pipe_get_transfer(st->pipe, pt, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, + width, height); + + /* map texture transfer */ + dest = pipe_transfer_map(pipe, transfer); + + + /* Put image into texture transfer. + * Note that the image is actually going to be upside down in + * the texture. We deal with that with texcoords. + */ + success = _mesa_texstore(ctx, 2, /* dims */ + baseInternalFormat, /* baseInternalFormat */ + mformat, /* gl_format */ + dest, /* dest */ + 0, 0, 0, /* dstX/Y/Zoffset */ + transfer->stride, /* dstRowStride, bytes */ + &dstImageOffsets, /* dstImageOffsets */ + width, height, 1, /* size */ + format, type, /* src format/type */ + pixels, /* data source */ + unpack); + + /* unmap */ + pipe_transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); + + assert(success); + + /* restore */ + ctx->_ImageTransferState = imageTransferStateSave; + } + + _mesa_unmap_pbo_source(ctx, unpack); + + return pt; +} + + +/** + * Draw quad with texcoords and optional color. + * Coords are gallium window coords with y=0=top. + * \param color may be null + * \param invertTex if true, flip texcoords vertically + */ +static void +draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, + GLfloat x1, GLfloat y1, const GLfloat *color, + GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLfloat verts[4][3][4]; /* four verts, three attribs, XYZW */ + + /* setup vertex data */ + { + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat) fb->Width; + const GLfloat fb_height = (GLfloat) fb->Height; + const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; + const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; + const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; + const GLfloat sLeft = 0.0f, sRight = maxXcoord; + const GLfloat tTop = invertTex ? maxYcoord : 0.0f; + const GLfloat tBot = invertTex ? 0.0f : maxYcoord; + GLuint i; + + /* upper-left */ + verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ + verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ + + /* upper-right */ + verts[1][0][0] = clip_x1; + verts[1][0][1] = clip_y0; + + /* lower-right */ + verts[2][0][0] = clip_x1; + verts[2][0][1] = clip_y1; + + /* lower-left */ + verts[3][0][0] = clip_x0; + verts[3][0][1] = clip_y1; + + verts[0][1][0] = sLeft; /* v[0].attr[1].S */ + verts[0][1][1] = tTop; /* v[0].attr[1].T */ + verts[1][1][0] = sRight; + verts[1][1][1] = tTop; + verts[2][1][0] = sRight; + verts[2][1][1] = tBot; + verts[3][1][0] = sLeft; + verts[3][1][1] = tBot; + + /* same for all verts: */ + if (color) { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /* v[i].attr[0].z */ + verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ + verts[i][2][0] = color[0]; /* v[i].attr[2].r */ + verts[i][2][1] = color[1]; /* v[i].attr[2].g */ + verts[i][2][2] = color[2]; /* v[i].attr[2].b */ + verts[i][2][3] = color[3]; /* v[i].attr[2].a */ + verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ + verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ + } + } + else { + for (i = 0; i < 4; i++) { + verts[i][0][2] = z; /*Z*/ + verts[i][0][3] = 1.0f; /*W*/ + verts[i][1][2] = 0.0f; /*R*/ + verts[i][1][3] = 1.0f; /*Q*/ + } + } + } + + { + struct pipe_resource *buf; + + /* allocate/load buffer object with vertex data */ + buf = pipe_buffer_create(pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STATIC, + sizeof(verts)); + pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); + + util_draw_vertex_buffer(pipe, st->cso_context, buf, 0, + PIPE_PRIM_QUADS, + 4, /* verts */ + 3); /* attribs/vert */ + pipe_resource_reference(&buf, NULL); + } +} + + + +static void +draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, + GLsizei width, GLsizei height, + GLfloat zoomX, GLfloat zoomY, + struct pipe_sampler_view **sv, + int num_sampler_view, + void *driver_vp, + void *driver_fp, + const GLfloat *color, + GLboolean invertTex, + GLboolean write_depth, GLboolean write_stencil) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + GLfloat x0, y0, x1, y1; + GLsizei maxSize; + boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; + + /* limit checks */ + /* XXX if DrawPixels image is larger than max texture size, break + * it up into chunks. + */ + maxSize = 1 << (pipe->screen->get_param(pipe->screen, + PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + assert(width <= maxSize); + assert(height <= maxSize); + + cso_save_rasterizer(cso); + cso_save_viewport(cso); + cso_save_samplers(cso); + cso_save_fragment_sampler_views(cso); + cso_save_fragment_shader(cso); + cso_save_vertex_shader(cso); + cso_save_vertex_elements(cso); + cso_save_vertex_buffers(cso); + if (write_stencil) { + cso_save_depth_stencil_alpha(cso); + cso_save_blend(cso); + } + + /* rasterizer state: just scissor */ + { + struct pipe_rasterizer_state rasterizer; + memset(&rasterizer, 0, sizeof(rasterizer)); + rasterizer.clamp_fragment_color = ctx->Color._ClampFragmentColor; + rasterizer.gl_rasterization_rules = 1; + rasterizer.scissor = ctx->Scissor.Enabled; + cso_set_rasterizer(cso, &rasterizer); + } + + if (write_stencil) { + /* Stencil writing bypasses the normal fragment pipeline to + * disable color writing and set stencil test to always pass. + */ + struct pipe_depth_stencil_alpha_state dsa; + struct pipe_blend_state blend; + + /* depth/stencil */ + memset(&dsa, 0, sizeof(dsa)); + dsa.stencil[0].enabled = 1; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + if (write_depth) { + /* writing depth+stencil: depth test always passes */ + dsa.depth.enabled = 1; + dsa.depth.writemask = ctx->Depth.Mask; + dsa.depth.func = PIPE_FUNC_ALWAYS; + } + cso_set_depth_stencil_alpha(cso, &dsa); + + /* blend (colormask) */ + memset(&blend, 0, sizeof(blend)); + cso_set_blend(cso, &blend); + } + + /* fragment shader state: TEX lookup program */ + cso_set_fragment_shader_handle(cso, driver_fp); + + /* vertex shader state: position + texcoord pass-through */ + cso_set_vertex_shader_handle(cso, driver_vp); + + + /* texture sampling state: */ + { + struct pipe_sampler_state sampler; + memset(&sampler, 0, sizeof(sampler)); + sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; + sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; + sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; + sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; + sampler.normalized_coords = normalized; + + cso_single_sampler(cso, 0, &sampler); + if (num_sampler_view > 1) { + cso_single_sampler(cso, 1, &sampler); + } + cso_single_sampler_done(cso); + } + + /* viewport state: viewport matching window dims */ + { + const float w = (float) ctx->DrawBuffer->Width; + const float h = (float) ctx->DrawBuffer->Height; + struct pipe_viewport_state vp; + vp.scale[0] = 0.5f * w; + vp.scale[1] = -0.5f * h; + vp.scale[2] = 0.5f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * w; + vp.translate[1] = 0.5f * h; + vp.translate[2] = 0.5f; + vp.translate[3] = 0.0f; + cso_set_viewport(cso, &vp); + } + + cso_set_vertex_elements(cso, 3, st->velems_util_draw); + + /* texture state: */ + cso_set_fragment_sampler_views(cso, num_sampler_view, sv); + + /* Compute Gallium window coords (y=0=top) with pixel zoom. + * Recall that these coords are transformed by the current + * vertex shader and viewport transformation. + */ + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { + y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); + invertTex = !invertTex; + } + + x0 = (GLfloat) x; + x1 = x + width * ctx->Pixel.ZoomX; + y0 = (GLfloat) y; + y1 = y + height * ctx->Pixel.ZoomY; + + /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ + z = z * 2.0 - 1.0; + + draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, + normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, + normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); + + /* restore state */ + cso_restore_rasterizer(cso); + cso_restore_viewport(cso); + cso_restore_samplers(cso); + cso_restore_fragment_sampler_views(cso); + cso_restore_fragment_shader(cso); + cso_restore_vertex_shader(cso); + cso_restore_vertex_elements(cso); + cso_restore_vertex_buffers(cso); + if (write_stencil) { + cso_restore_depth_stencil_alpha(cso); + cso_restore_blend(cso); + } +} + + +/** + * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we + * can't use a fragment shader to write stencil values. + */ +static void +draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct st_renderbuffer *strb; + enum pipe_transfer_usage usage; + struct pipe_transfer *pt; + const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0; + GLint skipPixels; + ubyte *stmap; + struct gl_pixelstore_attrib clippedUnpack = *unpack; + + if (!zoom) { + if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, + &clippedUnpack)) { + /* totally clipped */ + return; + } + } + + strb = st_renderbuffer(ctx->DrawBuffer-> + Attachment[BUFFER_STENCIL].Renderbuffer); + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = ctx->DrawBuffer->Height - y - height; + } + + if(format != GL_DEPTH_STENCIL && + util_format_get_component_bits(strb->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + usage = PIPE_TRANSFER_READ_WRITE; + else + usage = PIPE_TRANSFER_WRITE; + + pt = pipe_get_transfer(pipe, strb->texture, + strb->rtt_level, strb->rtt_face + strb->rtt_slice, + usage, x, y, + width, height); + + stmap = pipe_transfer_map(pipe, pt); + + pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); + assert(pixels); + + /* if width > MAX_WIDTH, have to process image in chunks */ + skipPixels = 0; + while (skipPixels < width) { + const GLint spanX = skipPixels; + const GLint spanWidth = MIN2(width - skipPixels, MAX_WIDTH); + GLint row; + for (row = 0; row < height; row++) { + GLubyte sValues[MAX_WIDTH]; + GLuint zValues[MAX_WIDTH]; + GLfloat *zValuesFloat = (GLfloat*)zValues; + GLenum destType = GL_UNSIGNED_BYTE; + const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, + width, height, + format, type, + row, skipPixels); + _mesa_unpack_stencil_span(ctx, spanWidth, destType, sValues, + type, source, &clippedUnpack, + ctx->_ImageTransferState); + + if (format == GL_DEPTH_STENCIL) { + GLenum ztype = + pt->resource->format == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED ? + GL_FLOAT : GL_UNSIGNED_INT; + + _mesa_unpack_depth_span(ctx, spanWidth, ztype, zValues, + (1 << 24) - 1, type, source, + &clippedUnpack); + } + + if (zoom) { + _mesa_problem(ctx, "Gallium glDrawPixels(GL_STENCIL) with " + "zoom not complete"); + } + + { + GLint spanY; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + spanY = height - row - 1; + } + else { + spanY = row; + } + + /* now pack the stencil (and Z) values in the dest format */ + switch (pt->resource->format) { + case PIPE_FORMAT_S8_USCALED: + { + ubyte *dest = stmap + spanY * pt->stride + spanX; + assert(usage == PIPE_TRANSFER_WRITE); + memcpy(dest, sValues, spanWidth); + } + break; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + if (format == GL_DEPTH_STENCIL) { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = zValues[k] | (sValues[k] << 24); + } + } + else { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (dest[k] & 0xffffff) | (sValues[k] << 24); + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + if (format == GL_DEPTH_STENCIL) { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (zValues[k] << 8) | (sValues[k] & 0xff); + } + } + else { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k] = (dest[k] & 0xffffff00) | (sValues[k] & 0xff); + } + } + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + if (format == GL_DEPTH_STENCIL) { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLfloat *destf = (GLfloat*)dest; + GLint k; + assert(usage == PIPE_TRANSFER_WRITE); + for (k = 0; k < spanWidth; k++) { + destf[k*2] = zValuesFloat[k]; + dest[k*2+1] = sValues[k] & 0xff; + } + } + else { + uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); + GLint k; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (k = 0; k < spanWidth; k++) { + dest[k*2+1] = sValues[k] & 0xff; + } + } + break; + default: + assert(0); + } + } + } + skipPixels += spanWidth; + } + + _mesa_unmap_pbo_source(ctx, &clippedUnpack); + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, pt); + pipe->transfer_destroy(pipe, pt); +} + + +/** + * Get fragment program variant for a glDrawPixels or glCopyPixels + * command for RGBA data. + */ +static struct st_fp_variant * +get_color_fp_variant(struct st_context *st) +{ + struct gl_context *ctx = st->ctx; + struct st_fp_variant_key key; + struct st_fp_variant *fpv; + + memset(&key, 0, sizeof(key)); + + key.st = st; + key.drawpixels = 1; + key.scaleAndBias = (ctx->Pixel.RedBias != 0.0 || + ctx->Pixel.RedScale != 1.0 || + ctx->Pixel.GreenBias != 0.0 || + ctx->Pixel.GreenScale != 1.0 || + ctx->Pixel.BlueBias != 0.0 || + ctx->Pixel.BlueScale != 1.0 || + ctx->Pixel.AlphaBias != 0.0 || + ctx->Pixel.AlphaScale != 1.0); + key.pixelMaps = ctx->Pixel.MapColorFlag; + + fpv = st_get_fp_variant(st, st->fp, &key); + + return fpv; +} + + +/** + * Get fragment program variant for a glDrawPixels or glCopyPixels + * command for depth/stencil data. + */ +static struct st_fp_variant * +get_depth_stencil_fp_variant(struct st_context *st, GLboolean write_depth, + GLboolean write_stencil) +{ + struct st_fp_variant_key key; + struct st_fp_variant *fpv; + + memset(&key, 0, sizeof(key)); + + key.st = st; + key.drawpixels = 1; + key.drawpixels_z = write_depth; + key.drawpixels_stencil = write_stencil; + + fpv = st_get_fp_variant(st, st->fp, &key); + + return fpv; +} + + +/** + * Called via ctx->Driver.DrawPixels() + */ +static void +st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) +{ + void *driver_vp, *driver_fp; + struct st_context *st = st_context(ctx); + const GLfloat *color; + struct pipe_context *pipe = st->pipe; + GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; + struct st_fp_variant *fpv; + + if (format == GL_DEPTH_STENCIL) + write_stencil = write_depth = GL_TRUE; + else if (format == GL_STENCIL_INDEX) + write_stencil = GL_TRUE; + else if (format == GL_DEPTH_COMPONENT) + write_depth = GL_TRUE; + + if (write_stencil && + !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) { + /* software fallback */ + draw_stencil_pixels(ctx, x, y, width, height, format, type, + unpack, pixels); + return; + } + + /* Mesa state should be up to date by now */ + assert(ctx->NewState == 0x0); + + st_validate_state(st); + + /* + * Get vertex/fragment shaders + */ + if (write_depth || write_stencil) { + fpv = get_depth_stencil_fp_variant(st, write_depth, write_stencil); + + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); + + color = ctx->Current.RasterColor; + } + else { + fpv = get_color_fp_variant(st); + + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + + color = NULL; + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } + } + + /* update fragment program constants */ + st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); + + /* draw with textured quad */ + { + struct pipe_resource *pt + = make_texture(st, width, height, format, type, unpack, pixels); + if (pt) { + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + + if (sv[0]) { + /* Create a second sampler view to read stencil. + * The stencil is written using the shader stencil export + * functionality. */ + if (write_stencil) { + enum pipe_format stencil_format = PIPE_FORMAT_NONE; + + switch (pt->format) { + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + case PIPE_FORMAT_X24S8_USCALED: + stencil_format = PIPE_FORMAT_X24S8_USCALED; + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + case PIPE_FORMAT_S8X24_USCALED: + stencil_format = PIPE_FORMAT_S8X24_USCALED; + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + case PIPE_FORMAT_X32_S8X24_USCALED: + stencil_format = PIPE_FORMAT_X32_S8X24_USCALED; + break; + case PIPE_FORMAT_S8_USCALED: + stencil_format = PIPE_FORMAT_S8_USCALED; + break; + default: + assert(0); + } + + sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, + stencil_format); + num_sampler_view++; + } + + draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], + width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + sv, + num_sampler_view, + driver_vp, + driver_fp, + color, GL_FALSE, write_depth, write_stencil); + pipe_sampler_view_reference(&sv[0], NULL); + if (num_sampler_view > 1) + pipe_sampler_view_reference(&sv[1], NULL); + } + pipe_resource_reference(&pt, NULL); + } + } +} + + + +/** + * Software fallback for glCopyPixels(GL_STENCIL). + */ +static void +copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty) +{ + struct st_renderbuffer *rbDraw; + struct pipe_context *pipe = st_context(ctx)->pipe; + enum pipe_transfer_usage usage; + struct pipe_transfer *ptDraw; + ubyte *drawMap; + ubyte *buffer; + int i; + + buffer = malloc(width * height * sizeof(ubyte)); + if (!buffer) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels(stencil)"); + return; + } + + /* Get the dest renderbuffer. If there's a wrapper, use the + * underlying renderbuffer. + */ + rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); + if (rbDraw->Base.Wrapped) + rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); + + /* this will do stencil pixel transfer ops */ + st_read_stencil_pixels(ctx, srcx, srcy, width, height, + GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, + &ctx->DefaultPacking, buffer); + + if (0) { + /* debug code: dump stencil values */ + GLint row, col; + for (row = 0; row < height; row++) { + printf("%3d: ", row); + for (col = 0; col < width; col++) { + printf("%02x ", buffer[col + row * width]); + } + printf("\n"); + } + } + + if (util_format_get_component_bits(rbDraw->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + usage = PIPE_TRANSFER_READ_WRITE; + else + usage = PIPE_TRANSFER_WRITE; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + dsty = rbDraw->Base.Height - dsty - height; + } + + ptDraw = pipe_get_transfer(pipe, + rbDraw->texture, + rbDraw->rtt_level, + rbDraw->rtt_face + rbDraw->rtt_slice, + usage, dstx, dsty, + width, height); + + assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); + assert(util_format_get_blockheight(ptDraw->resource->format) == 1); + + /* map the stencil buffer */ + drawMap = pipe_transfer_map(pipe, ptDraw); + + /* draw */ + /* XXX PixelZoom not handled yet */ + for (i = 0; i < height; i++) { + ubyte *dst; + const ubyte *src; + int y; + + y = i; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = height - y - 1; + } + + dst = drawMap + y * ptDraw->stride; + src = buffer + i * width; + + switch (ptDraw->resource->format) { + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + { + uint *dst4 = (uint *) dst; + int j; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (j = 0; j < width; j++) { + *dst4 = (*dst4 & 0xffffff) | (src[j] << 24); + dst4++; + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + { + uint *dst4 = (uint *) dst; + int j; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (j = 0; j < width; j++) { + *dst4 = (*dst4 & 0xffffff00) | (src[j] & 0xff); + dst4++; + } + } + break; + case PIPE_FORMAT_S8_USCALED: + assert(usage == PIPE_TRANSFER_WRITE); + memcpy(dst, src, width); + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + { + uint *dst4 = (uint *) dst; + int j; + dst4++; + assert(usage == PIPE_TRANSFER_READ_WRITE); + for (j = 0; j < width; j++) { + *dst4 = src[j] & 0xff; + dst4 += 2; + } + } + break; + default: + assert(0); + } + } + + free(buffer); + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, ptDraw); + pipe->transfer_destroy(pipe, ptDraw); +} + + +/** Do the src/dest regions overlap? */ +static GLboolean +regions_overlap(GLint srcX, GLint srcY, GLint dstX, GLint dstY, + GLsizei width, GLsizei height) +{ + if (srcX + width <= dstX || + dstX + width <= srcX || + srcY + height <= dstY || + dstY + height <= srcY) + return GL_FALSE; + else + return GL_TRUE; +} + + +/** + * Try to do a glCopyPixels for simple cases with a blit by calling + * pipe->resource_copy_region(). + * + * We can do this when we're copying color pixels (depth/stencil + * eventually) with no pixel zoom, no pixel transfer ops, no + * per-fragment ops, the src/dest regions don't overlap and the + * src/dest pixel formats are the same. + */ +static GLboolean +blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct gl_pixelstore_attrib pack, unpack; + GLint readX, readY, readW, readH; + + if (type == GL_COLOR && + ctx->Pixel.ZoomX == 1.0 && + ctx->Pixel.ZoomY == 1.0 && + ctx->_ImageTransferState == 0x0 && + !ctx->Color.BlendEnabled && + !ctx->Color.AlphaEnabled && + !ctx->Depth.Test && + !ctx->Fog.Enabled && + !ctx->Stencil.Enabled && + !ctx->FragmentProgram.Enabled && + !ctx->VertexProgram.Enabled && + !ctx->Shader.CurrentFragmentProgram && + st_fb_orientation(ctx->ReadBuffer) == st_fb_orientation(ctx->DrawBuffer) && + ctx->DrawBuffer->_NumColorDrawBuffers == 1 && + !ctx->Query.CondRenderQuery) { + struct st_renderbuffer *rbRead, *rbDraw; + GLint drawX, drawY; + + /* + * Clip the read region against the src buffer bounds. + * We'll still allocate a temporary buffer/texture for the original + * src region size but we'll only read the region which is on-screen. + * This may mean that we draw garbage pixels into the dest region, but + * that's expected. + */ + readX = srcx; + readY = srcy; + readW = width; + readH = height; + pack = ctx->DefaultPacking; + if (!_mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack)) + return GL_TRUE; /* all done */ + + /* clip against dest buffer bounds and scissor box */ + drawX = dstx + pack.SkipPixels; + drawY = dsty + pack.SkipRows; + unpack = pack; + if (!_mesa_clip_drawpixels(ctx, &drawX, &drawY, &readW, &readH, &unpack)) + return GL_TRUE; /* all done */ + + readX = readX - pack.SkipPixels + unpack.SkipPixels; + readY = readY - pack.SkipRows + unpack.SkipRows; + + rbRead = st_get_color_read_renderbuffer(ctx); + rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); + + if ((rbRead != rbDraw || + !regions_overlap(readX, readY, drawX, drawY, readW, readH)) && + rbRead->Base.Format == rbDraw->Base.Format) { + struct pipe_box srcBox; + + /* flip src/dst position if needed */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* both buffers will have the same orientation */ + readY = ctx->ReadBuffer->Height - readY - readH; + drawY = ctx->DrawBuffer->Height - drawY - readH; + } + + u_box_2d(readX, readY, readW, readH, &srcBox); + + pipe->resource_copy_region(pipe, + rbDraw->texture, + rbDraw->rtt_level, drawX, drawY, 0, + rbRead->texture, + rbRead->rtt_level, &srcBox); + return GL_TRUE; + } + } + + return GL_FALSE; +} + + +static void +st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, + GLsizei width, GLsizei height, + GLint dstx, GLint dsty, GLenum type) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct st_renderbuffer *rbRead; + void *driver_vp, *driver_fp; + struct pipe_resource *pt; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; + GLfloat *color; + enum pipe_format srcFormat, texFormat; + GLboolean invertTex = GL_FALSE; + GLint readX, readY, readW, readH; + GLuint sample_count; + struct gl_pixelstore_attrib pack = ctx->DefaultPacking; + struct st_fp_variant *fpv; + + st_validate_state(st); + + if (type == GL_STENCIL) { + /* can't use texturing to do stencil */ + copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); + return; + } + + if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) + return; + + /* + * The subsequent code implements glCopyPixels by copying the source + * pixels into a temporary texture that's then applied to a textured quad. + * When we draw the textured quad, all the usual per-fragment operations + * are handled. + */ + + + /* + * Get vertex/fragment shaders + */ + if (type == GL_COLOR) { + rbRead = st_get_color_read_renderbuffer(ctx); + color = NULL; + + fpv = get_color_fp_variant(st); + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } + } + else { + assert(type == GL_DEPTH); + rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + + fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); + driver_fp = fpv->driver_shader; + + driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); + } + + /* update fragment program constants */ + st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); + + + if (rbRead->Base.Wrapped) + rbRead = st_renderbuffer(rbRead->Base.Wrapped); + + sample_count = rbRead->texture->nr_samples; + /* I believe this would be legal, presumably would need to do a resolve + for color, and for depth/stencil spec says to just use one of the + depth/stencil samples per pixel? Need some transfer clarifications. */ + assert(sample_count < 2); + + srcFormat = rbRead->texture->format; + + if (screen->is_format_supported(screen, srcFormat, st->internal_target, + sample_count, + PIPE_BIND_SAMPLER_VIEW)) { + texFormat = srcFormat; + } + else { + /* srcFormat can't be used as a texture format */ + if (type == GL_DEPTH) { + texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, + GL_NONE, GL_NONE, st->internal_target, + sample_count, PIPE_BIND_DEPTH_STENCIL); + assert(texFormat != PIPE_FORMAT_NONE); + } + else { + /* default color format */ + texFormat = st_choose_format(screen, GL_RGBA, + GL_NONE, GL_NONE, st->internal_target, + sample_count, PIPE_BIND_SAMPLER_VIEW); + assert(texFormat != PIPE_FORMAT_NONE); + } + } + + /* Invert src region if needed */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + srcy = ctx->ReadBuffer->Height - srcy - height; + invertTex = !invertTex; + } + + /* Clip the read region against the src buffer bounds. + * We'll still allocate a temporary buffer/texture for the original + * src region size but we'll only read the region which is on-screen. + * This may mean that we draw garbage pixels into the dest region, but + * that's expected. + */ + readX = srcx; + readY = srcy; + readW = width; + readH = height; + _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); + readW = MAX2(0, readW); + readH = MAX2(0, readH); + + /* alloc temporary texture */ + pt = alloc_texture(st, width, height, texFormat); + if (!pt) + return; + + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + if (!sv[0]) { + pipe_resource_reference(&pt, NULL); + return; + } + + /* Make temporary texture which is a copy of the src region. + */ + if (srcFormat == texFormat) { + struct pipe_box src_box; + u_box_2d(readX, readY, readW, readH, &src_box); + /* copy source framebuffer surface into mipmap/texture */ + pipe->resource_copy_region(pipe, + pt, /* dest tex */ + 0, /* dest lvl */ + pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ + rbRead->texture, /* src tex */ + rbRead->rtt_level, /* src lvl */ + &src_box); + + } + else { + /* CPU-based fallback/conversion */ + struct pipe_transfer *ptRead = + pipe_get_transfer(st->pipe, rbRead->texture, + rbRead->rtt_level, + rbRead->rtt_face + rbRead->rtt_slice, + PIPE_TRANSFER_READ, + readX, readY, readW, readH); + struct pipe_transfer *ptTex; + enum pipe_transfer_usage transfer_usage; + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback processing\n", __FUNCTION__); + + if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) + transfer_usage = PIPE_TRANSFER_READ_WRITE; + else + transfer_usage = PIPE_TRANSFER_WRITE; + + ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, + 0, 0, width, height); + + /* copy image from ptRead surface to ptTex surface */ + if (type == GL_COLOR) { + /* alternate path using get/put_tile() */ + GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + enum pipe_format readFormat, drawFormat; + readFormat = util_format_linear(rbRead->texture->format); + drawFormat = util_format_linear(pt->format); + pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH, + readFormat, buf); + pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, drawFormat, buf); + free(buf); + } + else { + /* GL_DEPTH */ + GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); + pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); + pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, buf); + free(buf); + } + + pipe->transfer_destroy(pipe, ptRead); + pipe->transfer_destroy(pipe, ptTex); + } + + /* OK, the texture 'pt' contains the src image/pixels. Now draw a + * textured quad with that texture. + */ + draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], + width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + sv, + num_sampler_view, + driver_vp, + driver_fp, + color, invertTex, GL_FALSE, GL_FALSE); + + pipe_resource_reference(&pt, NULL); + pipe_sampler_view_reference(&sv[0], NULL); +} + + + +void st_init_drawpixels_functions(struct dd_function_table *functions) +{ + functions->DrawPixels = st_DrawPixels; + functions->CopyPixels = st_CopyPixels; +} + + +void +st_destroy_drawpix(struct st_context *st) +{ + GLuint i; + + for (i = 0; i < Elements(st->drawpix.shaders); i++) { + if (st->drawpix.shaders[i]) + _mesa_reference_fragprog(st->ctx, &st->drawpix.shaders[i], NULL); + } + + st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); + if (st->drawpix.vert_shaders[0]) + ureg_free_tokens(st->drawpix.vert_shaders[0]); + if (st->drawpix.vert_shaders[1]) + ureg_free_tokens(st->drawpix.vert_shaders[1]); +} + +#endif /* FEATURE_drawpix */ diff --git a/mesalib/src/mesa/state_tracker/st_cb_drawtex.c b/mesalib/src/mesa/state_tracker/st_cb_drawtex.c index db299eb8d..86ceb9d78 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawtex.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawtex.c @@ -1,307 +1,307 @@ -/**************************************************************************
- *
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- **************************************************************************/
-
-
-/**
- * Implementation of glDrawTex() for GL_OES_draw_tex
- */
-
-
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "program/program.h"
-#include "program/prog_print.h"
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_drawtex.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_draw_quad.h"
-#include "util/u_simple_shaders.h"
-
-#include "cso_cache/cso_context.h"
-
-
-#if FEATURE_OES_draw_texture
-
-
-struct cached_shader
-{
- void *handle;
-
- uint num_attribs;
- uint semantic_names[2 + MAX_TEXTURE_UNITS];
- uint semantic_indexes[2 + MAX_TEXTURE_UNITS];
-};
-
-#define MAX_SHADERS (2 * MAX_TEXTURE_UNITS)
-
-/**
- * Simple linear list cache.
- * Most of the time there'll only be one cached shader.
- */
-static struct cached_shader CachedShaders[MAX_SHADERS];
-static GLuint NumCachedShaders = 0;
-
-
-static void *
-lookup_shader(struct pipe_context *pipe,
- uint num_attribs,
- const uint *semantic_names,
- const uint *semantic_indexes)
-{
- GLuint i, j;
-
- /* look for existing shader with same attributes */
- for (i = 0; i < NumCachedShaders; i++) {
- if (CachedShaders[i].num_attribs == num_attribs) {
- GLboolean match = GL_TRUE;
- for (j = 0; j < num_attribs; j++) {
- if (semantic_names[j] != CachedShaders[i].semantic_names[j] ||
- semantic_indexes[j] != CachedShaders[i].semantic_indexes[j]) {
- match = GL_FALSE;
- break;
- }
- }
- if (match)
- return CachedShaders[i].handle;
- }
- }
-
- /* not found - create new one now */
- if (NumCachedShaders >= MAX_SHADERS) {
- return NULL;
- }
-
- CachedShaders[i].num_attribs = num_attribs;
- for (j = 0; j < num_attribs; j++) {
- CachedShaders[i].semantic_names[j] = semantic_names[j];
- CachedShaders[i].semantic_indexes[j] = semantic_indexes[j];
- }
-
- CachedShaders[i].handle =
- util_make_vertex_passthrough_shader(pipe,
- num_attribs,
- semantic_names,
- semantic_indexes);
- NumCachedShaders++;
-
- return CachedShaders[i].handle;
-}
-
-static void
-st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
- GLfloat width, GLfloat height)
-{
- struct st_context *st = ctx->st;
- struct pipe_context *pipe = st->pipe;
- struct cso_context *cso = ctx->st->cso_context;
- struct pipe_resource *vbuffer;
- struct pipe_transfer *vbuffer_transfer;
- GLuint i, numTexCoords, numAttribs;
- GLboolean emitColor;
- uint semantic_names[2 + MAX_TEXTURE_UNITS];
- uint semantic_indexes[2 + MAX_TEXTURE_UNITS];
- struct pipe_vertex_element velements[2 + MAX_TEXTURE_UNITS];
- GLbitfield inputs = VERT_BIT_POS;
-
- st_validate_state(st);
-
- /* determine if we need vertex color */
- if (ctx->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL0)
- emitColor = GL_TRUE;
- else
- emitColor = GL_FALSE;
-
- /* determine how many enabled sets of texcoords */
- numTexCoords = 0;
- for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
- if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) {
- inputs |= VERT_BIT_TEX(i);
- numTexCoords++;
- }
- }
-
- /* total number of attributes per vertex */
- numAttribs = 1 + emitColor + numTexCoords;
-
-
- /* create the vertex buffer */
- vbuffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER,
- PIPE_USAGE_STREAM,
- numAttribs * 4 * 4 * sizeof(GLfloat));
-
- /* load vertex buffer */
- {
-#define SET_ATTRIB(VERT, ATTR, X, Y, Z, W) \
- do { \
- GLuint k = (((VERT) * numAttribs + (ATTR)) * 4); \
- assert(k < 4 * 4 * numAttribs); \
- vbuf[k + 0] = X; \
- vbuf[k + 1] = Y; \
- vbuf[k + 2] = Z; \
- vbuf[k + 3] = W; \
- } while (0)
-
- const GLfloat x0 = x, y0 = y, x1 = x + width, y1 = y + height;
- GLfloat *vbuf = (GLfloat *) pipe_buffer_map(pipe, vbuffer,
- PIPE_TRANSFER_WRITE,
- &vbuffer_transfer);
- GLuint attr;
-
- z = CLAMP(z, 0.0f, 1.0f);
-
- /* positions (in clip coords) */
- {
- const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- const GLfloat fb_width = (GLfloat)fb->Width;
- const GLfloat fb_height = (GLfloat)fb->Height;
-
- const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0);
- const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0);
- const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0);
- const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0);
-
- SET_ATTRIB(0, 0, clip_x0, clip_y0, z, 1.0f); /* lower left */
- SET_ATTRIB(1, 0, clip_x1, clip_y0, z, 1.0f); /* lower right */
- SET_ATTRIB(2, 0, clip_x1, clip_y1, z, 1.0f); /* upper right */
- SET_ATTRIB(3, 0, clip_x0, clip_y1, z, 1.0f); /* upper left */
-
- semantic_names[0] = TGSI_SEMANTIC_POSITION;
- semantic_indexes[0] = 0;
- }
-
- /* colors */
- if (emitColor) {
- const GLfloat *c = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
- SET_ATTRIB(0, 1, c[0], c[1], c[2], c[3]);
- SET_ATTRIB(1, 1, c[0], c[1], c[2], c[3]);
- SET_ATTRIB(2, 1, c[0], c[1], c[2], c[3]);
- SET_ATTRIB(3, 1, c[0], c[1], c[2], c[3]);
- semantic_names[1] = TGSI_SEMANTIC_COLOR;
- semantic_indexes[1] = 0;
- attr = 2;
- }
- else {
- attr = 1;
- }
-
- /* texcoords */
- for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
- if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) {
- struct gl_texture_object *obj = ctx->Texture.Unit[i]._Current;
- struct gl_texture_image *img = obj->Image[0][obj->BaseLevel];
- const GLfloat wt = (GLfloat) img->Width;
- const GLfloat ht = (GLfloat) img->Height;
- const GLfloat s0 = obj->CropRect[0] / wt;
- const GLfloat t0 = obj->CropRect[1] / ht;
- const GLfloat s1 = (obj->CropRect[0] + obj->CropRect[2]) / wt;
- const GLfloat t1 = (obj->CropRect[1] + obj->CropRect[3]) / ht;
-
- /*printf("crop texcoords: %g, %g .. %g, %g\n", s0, t0, s1, t1);*/
- SET_ATTRIB(0, attr, s0, t0, 0.0f, 1.0f); /* lower left */
- SET_ATTRIB(1, attr, s1, t0, 0.0f, 1.0f); /* lower right */
- SET_ATTRIB(2, attr, s1, t1, 0.0f, 1.0f); /* upper right */
- SET_ATTRIB(3, attr, s0, t1, 0.0f, 1.0f); /* upper left */
-
- semantic_names[attr] = TGSI_SEMANTIC_GENERIC;
- semantic_indexes[attr] = 0;
-
- attr++;
- }
- }
-
- pipe_buffer_unmap(pipe, vbuffer_transfer);
-
-#undef SET_ATTRIB
- }
-
-
- cso_save_viewport(cso);
- cso_save_vertex_shader(cso);
- cso_save_vertex_elements(cso);
- cso_save_vertex_buffers(cso);
-
- {
- void *vs = lookup_shader(pipe, numAttribs,
- semantic_names, semantic_indexes);
- cso_set_vertex_shader_handle(cso, vs);
- }
-
- for (i = 0; i < numAttribs; i++) {
- velements[i].src_offset = i * 4 * sizeof(float);
- velements[i].instance_divisor = 0;
- velements[i].vertex_buffer_index = 0;
- velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
- }
- cso_set_vertex_elements(cso, numAttribs, velements);
-
- /* viewport state: viewport matching window dims */
- {
- const struct gl_framebuffer *fb = st->ctx->DrawBuffer;
- const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP);
- const GLfloat width = (GLfloat)fb->Width;
- const GLfloat height = (GLfloat)fb->Height;
- struct pipe_viewport_state vp;
- vp.scale[0] = 0.5f * width;
- vp.scale[1] = height * (invert ? -0.5f : 0.5f);
- vp.scale[2] = 1.0f;
- vp.scale[3] = 1.0f;
- vp.translate[0] = 0.5f * width;
- vp.translate[1] = 0.5f * height;
- vp.translate[2] = 0.0f;
- vp.translate[3] = 0.0f;
- cso_set_viewport(cso, &vp);
- }
-
-
- util_draw_vertex_buffer(pipe, cso, vbuffer,
- 0, /* offset */
- PIPE_PRIM_TRIANGLE_FAN,
- 4, /* verts */
- numAttribs); /* attribs/vert */
-
-
- pipe_resource_reference(&vbuffer, NULL);
-
- /* restore state */
- cso_restore_viewport(cso);
- cso_restore_vertex_shader(cso);
- cso_restore_vertex_elements(cso);
- cso_restore_vertex_buffers(cso);
-}
-
-
-void
-st_init_drawtex_functions(struct dd_function_table *functions)
-{
- functions->DrawTex = st_DrawTex;
-}
-
-
-/**
- * Free any cached shaders
- */
-void
-st_destroy_drawtex(struct st_context *st)
-{
- GLuint i;
- for (i = 0; i < NumCachedShaders; i++) {
- cso_delete_vertex_shader(st->cso_context, CachedShaders[i].handle);
- }
- NumCachedShaders = 0;
-}
-
-
-#endif /* FEATURE_OES_draw_texture */
+/************************************************************************** + * + * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +/** + * Implementation of glDrawTex() for GL_OES_draw_tex + */ + + + +#include "main/imports.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/mfeatures.h" +#include "program/program.h" +#include "program/prog_print.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_drawtex.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" +#include "pipe/p_shader_tokens.h" +#include "util/u_draw_quad.h" +#include "util/u_simple_shaders.h" + +#include "cso_cache/cso_context.h" + + +#if FEATURE_OES_draw_texture + + +struct cached_shader +{ + void *handle; + + uint num_attribs; + uint semantic_names[2 + MAX_TEXTURE_UNITS]; + uint semantic_indexes[2 + MAX_TEXTURE_UNITS]; +}; + +#define MAX_SHADERS (2 * MAX_TEXTURE_UNITS) + +/** + * Simple linear list cache. + * Most of the time there'll only be one cached shader. + */ +static struct cached_shader CachedShaders[MAX_SHADERS]; +static GLuint NumCachedShaders = 0; + + +static void * +lookup_shader(struct pipe_context *pipe, + uint num_attribs, + const uint *semantic_names, + const uint *semantic_indexes) +{ + GLuint i, j; + + /* look for existing shader with same attributes */ + for (i = 0; i < NumCachedShaders; i++) { + if (CachedShaders[i].num_attribs == num_attribs) { + GLboolean match = GL_TRUE; + for (j = 0; j < num_attribs; j++) { + if (semantic_names[j] != CachedShaders[i].semantic_names[j] || + semantic_indexes[j] != CachedShaders[i].semantic_indexes[j]) { + match = GL_FALSE; + break; + } + } + if (match) + return CachedShaders[i].handle; + } + } + + /* not found - create new one now */ + if (NumCachedShaders >= MAX_SHADERS) { + return NULL; + } + + CachedShaders[i].num_attribs = num_attribs; + for (j = 0; j < num_attribs; j++) { + CachedShaders[i].semantic_names[j] = semantic_names[j]; + CachedShaders[i].semantic_indexes[j] = semantic_indexes[j]; + } + + CachedShaders[i].handle = + util_make_vertex_passthrough_shader(pipe, + num_attribs, + semantic_names, + semantic_indexes); + NumCachedShaders++; + + return CachedShaders[i].handle; +} + +static void +st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z, + GLfloat width, GLfloat height) +{ + struct st_context *st = ctx->st; + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = ctx->st->cso_context; + struct pipe_resource *vbuffer; + struct pipe_transfer *vbuffer_transfer; + GLuint i, numTexCoords, numAttribs; + GLboolean emitColor; + uint semantic_names[2 + MAX_TEXTURE_UNITS]; + uint semantic_indexes[2 + MAX_TEXTURE_UNITS]; + struct pipe_vertex_element velements[2 + MAX_TEXTURE_UNITS]; + GLbitfield inputs = VERT_BIT_POS; + + st_validate_state(st); + + /* determine if we need vertex color */ + if (ctx->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_COL0) + emitColor = GL_TRUE; + else + emitColor = GL_FALSE; + + /* determine how many enabled sets of texcoords */ + numTexCoords = 0; + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) { + inputs |= VERT_BIT_TEX(i); + numTexCoords++; + } + } + + /* total number of attributes per vertex */ + numAttribs = 1 + emitColor + numTexCoords; + + + /* create the vertex buffer */ + vbuffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, + numAttribs * 4 * 4 * sizeof(GLfloat)); + + /* load vertex buffer */ + { +#define SET_ATTRIB(VERT, ATTR, X, Y, Z, W) \ + do { \ + GLuint k = (((VERT) * numAttribs + (ATTR)) * 4); \ + assert(k < 4 * 4 * numAttribs); \ + vbuf[k + 0] = X; \ + vbuf[k + 1] = Y; \ + vbuf[k + 2] = Z; \ + vbuf[k + 3] = W; \ + } while (0) + + const GLfloat x0 = x, y0 = y, x1 = x + width, y1 = y + height; + GLfloat *vbuf = (GLfloat *) pipe_buffer_map(pipe, vbuffer, + PIPE_TRANSFER_WRITE, + &vbuffer_transfer); + GLuint attr; + + z = CLAMP(z, 0.0f, 1.0f); + + /* positions (in clip coords) */ + { + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat)fb->Width; + const GLfloat fb_height = (GLfloat)fb->Height; + + const GLfloat clip_x0 = (GLfloat)(x0 / fb_width * 2.0 - 1.0); + const GLfloat clip_y0 = (GLfloat)(y0 / fb_height * 2.0 - 1.0); + const GLfloat clip_x1 = (GLfloat)(x1 / fb_width * 2.0 - 1.0); + const GLfloat clip_y1 = (GLfloat)(y1 / fb_height * 2.0 - 1.0); + + SET_ATTRIB(0, 0, clip_x0, clip_y0, z, 1.0f); /* lower left */ + SET_ATTRIB(1, 0, clip_x1, clip_y0, z, 1.0f); /* lower right */ + SET_ATTRIB(2, 0, clip_x1, clip_y1, z, 1.0f); /* upper right */ + SET_ATTRIB(3, 0, clip_x0, clip_y1, z, 1.0f); /* upper left */ + + semantic_names[0] = TGSI_SEMANTIC_POSITION; + semantic_indexes[0] = 0; + } + + /* colors */ + if (emitColor) { + const GLfloat *c = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + SET_ATTRIB(0, 1, c[0], c[1], c[2], c[3]); + SET_ATTRIB(1, 1, c[0], c[1], c[2], c[3]); + SET_ATTRIB(2, 1, c[0], c[1], c[2], c[3]); + SET_ATTRIB(3, 1, c[0], c[1], c[2], c[3]); + semantic_names[1] = TGSI_SEMANTIC_COLOR; + semantic_indexes[1] = 0; + attr = 2; + } + else { + attr = 1; + } + + /* texcoords */ + for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { + if (ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_2D_BIT) { + struct gl_texture_object *obj = ctx->Texture.Unit[i]._Current; + struct gl_texture_image *img = obj->Image[0][obj->BaseLevel]; + const GLfloat wt = (GLfloat) img->Width; + const GLfloat ht = (GLfloat) img->Height; + const GLfloat s0 = obj->CropRect[0] / wt; + const GLfloat t0 = obj->CropRect[1] / ht; + const GLfloat s1 = (obj->CropRect[0] + obj->CropRect[2]) / wt; + const GLfloat t1 = (obj->CropRect[1] + obj->CropRect[3]) / ht; + + /*printf("crop texcoords: %g, %g .. %g, %g\n", s0, t0, s1, t1);*/ + SET_ATTRIB(0, attr, s0, t0, 0.0f, 1.0f); /* lower left */ + SET_ATTRIB(1, attr, s1, t0, 0.0f, 1.0f); /* lower right */ + SET_ATTRIB(2, attr, s1, t1, 0.0f, 1.0f); /* upper right */ + SET_ATTRIB(3, attr, s0, t1, 0.0f, 1.0f); /* upper left */ + + semantic_names[attr] = TGSI_SEMANTIC_GENERIC; + semantic_indexes[attr] = 0; + + attr++; + } + } + + pipe_buffer_unmap(pipe, vbuffer_transfer); + +#undef SET_ATTRIB + } + + + cso_save_viewport(cso); + cso_save_vertex_shader(cso); + cso_save_vertex_elements(cso); + cso_save_vertex_buffers(cso); + + { + void *vs = lookup_shader(pipe, numAttribs, + semantic_names, semantic_indexes); + cso_set_vertex_shader_handle(cso, vs); + } + + for (i = 0; i < numAttribs; i++) { + velements[i].src_offset = i * 4 * sizeof(float); + velements[i].instance_divisor = 0; + velements[i].vertex_buffer_index = 0; + velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } + cso_set_vertex_elements(cso, numAttribs, velements); + + /* viewport state: viewport matching window dims */ + { + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); + const GLfloat width = (GLfloat)fb->Width; + const GLfloat height = (GLfloat)fb->Height; + struct pipe_viewport_state vp; + vp.scale[0] = 0.5f * width; + vp.scale[1] = height * (invert ? -0.5f : 0.5f); + vp.scale[2] = 1.0f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * width; + vp.translate[1] = 0.5f * height; + vp.translate[2] = 0.0f; + vp.translate[3] = 0.0f; + cso_set_viewport(cso, &vp); + } + + + util_draw_vertex_buffer(pipe, cso, vbuffer, + 0, /* offset */ + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + numAttribs); /* attribs/vert */ + + + pipe_resource_reference(&vbuffer, NULL); + + /* restore state */ + cso_restore_viewport(cso); + cso_restore_vertex_shader(cso); + cso_restore_vertex_elements(cso); + cso_restore_vertex_buffers(cso); +} + + +void +st_init_drawtex_functions(struct dd_function_table *functions) +{ + functions->DrawTex = st_DrawTex; +} + + +/** + * Free any cached shaders + */ +void +st_destroy_drawtex(struct st_context *st) +{ + GLuint i; + for (i = 0; i < NumCachedShaders; i++) { + cso_delete_vertex_shader(st->cso_context, CachedShaders[i].handle); + } + NumCachedShaders = 0; +} + + +#endif /* FEATURE_OES_draw_texture */ diff --git a/mesalib/src/mesa/state_tracker/st_cb_readpixels.c b/mesalib/src/mesa/state_tracker/st_cb_readpixels.c index d992b4c30..e2b29fe30 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_readpixels.c +++ b/mesalib/src/mesa/state_tracker/st_cb_readpixels.c @@ -1,642 +1,642 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-
-/**
- * glReadPixels interface to pipe
- *
- * \author Brian Paul
- */
-
-
-#include "main/imports.h"
-#include "main/bufferobj.h"
-#include "main/context.h"
-#include "main/image.h"
-#include "main/pack.h"
-#include "main/pbo.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_format.h"
-#include "util/u_inlines.h"
-#include "util/u_tile.h"
-
-#include "st_debug.h"
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_bitmap.h"
-#include "st_cb_readpixels.h"
-#include "st_cb_fbo.h"
-
-/**
- * Special case for reading stencil buffer.
- * For color/depth we use get_tile(). For stencil, map the stencil buffer.
- */
-void
-st_read_stencil_pixels(struct gl_context *ctx, GLint x, GLint y,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *packing,
- GLvoid *pixels)
-{
- struct gl_framebuffer *fb = ctx->ReadBuffer;
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer);
- struct pipe_transfer *pt;
- ubyte *stmap;
- GLint j;
-
- if (strb->Base.Wrapped) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- }
-
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
- y = ctx->DrawBuffer->Height - y - height;
- }
-
- /* Create a read transfer from the renderbuffer's texture */
-
- pt = pipe_get_transfer(pipe, strb->texture,
- strb->rtt_level,
- strb->rtt_face + strb->rtt_slice,
- PIPE_TRANSFER_READ,
- x, y, width, height);
-
- /* map the stencil buffer */
- stmap = pipe_transfer_map(pipe, pt);
-
- /* width should never be > MAX_WIDTH since we did clipping earlier */
- ASSERT(width <= MAX_WIDTH);
-
- /* process image row by row */
- for (j = 0; j < height; j++) {
- GLvoid *dest;
- GLstencil sValues[MAX_WIDTH];
- GLfloat zValues[MAX_WIDTH];
- GLint srcY;
-
- if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
- srcY = height - j - 1;
- }
- else {
- srcY = j;
- }
-
- /* get stencil (and Z) values */
- switch (pt->resource->format) {
- case PIPE_FORMAT_S8_USCALED:
- {
- const ubyte *src = stmap + srcY * pt->stride;
- memcpy(sValues, src, width);
- }
- break;
- case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
- if (format == GL_DEPTH_STENCIL) {
- const uint *src = (uint *) (stmap + srcY * pt->stride);
- const GLfloat scale = 1.0f / (0xffffff);
- GLint k;
- for (k = 0; k < width; k++) {
- sValues[k] = src[k] >> 24;
- zValues[k] = (src[k] & 0xffffff) * scale;
- }
- }
- else {
- const uint *src = (uint *) (stmap + srcY * pt->stride);
- GLint k;
- for (k = 0; k < width; k++) {
- sValues[k] = src[k] >> 24;
- }
- }
- break;
- case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
- if (format == GL_DEPTH_STENCIL) {
- const uint *src = (uint *) (stmap + srcY * pt->stride);
- const GLfloat scale = 1.0f / (0xffffff);
- GLint k;
- for (k = 0; k < width; k++) {
- sValues[k] = src[k] & 0xff;
- zValues[k] = (src[k] >> 8) * scale;
- }
- }
- else {
- const uint *src = (uint *) (stmap + srcY * pt->stride);
- GLint k;
- for (k = 0; k < width; k++) {
- sValues[k] = src[k] & 0xff;
- }
- }
- break;
- case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
- if (format == GL_DEPTH_STENCIL) {
- const uint *src = (uint *) (stmap + srcY * pt->stride);
- const GLfloat *srcf = (const GLfloat*)src;
- GLint k;
- for (k = 0; k < width; k++) {
- zValues[k] = srcf[k*2];
- sValues[k] = src[k*2+1] & 0xff;
- }
- }
- else {
- const uint *src = (uint *) (stmap + srcY * pt->stride);
- GLint k;
- for (k = 0; k < width; k++) {
- sValues[k] = src[k*2+1] & 0xff;
- }
- }
- break;
- default:
- assert(0);
- }
-
- /* store */
- dest = _mesa_image_address2d(packing, pixels, width, height,
- format, type, j, 0);
- if (format == GL_DEPTH_STENCIL) {
- _mesa_pack_depth_stencil_span(ctx, width, type, dest,
- zValues, sValues, packing);
- }
- else {
- _mesa_pack_stencil_span(ctx, width, type, dest, sValues, packing);
- }
- }
-
- /* unmap the stencil buffer */
- pipe_transfer_unmap(pipe, pt);
- pipe->transfer_destroy(pipe, pt);
-}
-
-
-/**
- * Return renderbuffer to use for reading color pixels for glRead/CopyPixel
- * commands.
- */
-struct st_renderbuffer *
-st_get_color_read_renderbuffer(struct gl_context *ctx)
-{
- struct gl_framebuffer *fb = ctx->ReadBuffer;
- struct st_renderbuffer *strb =
- st_renderbuffer(fb->_ColorReadBuffer);
-
- return strb;
-}
-
-
-/**
- * Try to do glReadPixels in a fast manner for common cases.
- * \return GL_TRUE for success, GL_FALSE for failure
- */
-static GLboolean
-st_fast_readpixels(struct gl_context *ctx, struct st_renderbuffer *strb,
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *pack,
- GLvoid *dest)
-{
- GLubyte alphaORoperand;
- enum combination {
- A8R8G8B8_UNORM_TO_RGBA_UBYTE,
- A8R8G8B8_UNORM_TO_RGB_UBYTE,
- A8R8G8B8_UNORM_TO_BGRA_UINT,
- A8R8G8B8_UNORM_TO_RGBA_UINT
- } combo;
-
- if (ctx->_ImageTransferState)
- return GL_FALSE;
-
- if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM) {
- alphaORoperand = 0;
- }
- else if (strb->format == PIPE_FORMAT_B8G8R8X8_UNORM ) {
- alphaORoperand = 0xff;
- }
- else {
- return GL_FALSE;
- }
-
- if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
- combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
- }
- else if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
- combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
- }
- else if (format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
- combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
- }
- else if (format == GL_RGBA && type == GL_UNSIGNED_INT_8_8_8_8) {
- combo = A8R8G8B8_UNORM_TO_RGBA_UINT;
- }
- else {
- return GL_FALSE;
- }
-
- /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/
-
- {
- struct pipe_context *pipe = st_context(ctx)->pipe;
- struct pipe_transfer *trans;
- const GLubyte *map;
- GLubyte *dst;
- GLint row, col, dy, dstStride;
-
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- /* convert GL Y to Gallium Y */
- y = strb->texture->height0 - y - height;
- }
-
- trans = pipe_get_transfer(pipe, strb->texture,
- strb->rtt_level,
- strb->rtt_face + strb->rtt_slice,
- PIPE_TRANSFER_READ,
- x, y, width, height);
- if (!trans) {
- return GL_FALSE;
- }
-
- map = pipe_transfer_map(pipe, trans);
- if (!map) {
- pipe->transfer_destroy(pipe, trans);
- return GL_FALSE;
- }
-
- /* We always write to the user/dest buffer from low addr to high addr
- * but the read order depends on renderbuffer orientation
- */
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- /* read source rows from bottom to top */
- y = height - 1;
- dy = -1;
- }
- else {
- /* read source rows from top to bottom */
- y = 0;
- dy = 1;
- }
-
- dst = _mesa_image_address2d(pack, dest, width, height,
- format, type, 0, 0);
- dstStride = _mesa_image_row_stride(pack, width, format, type);
-
- switch (combo) {
- case A8R8G8B8_UNORM_TO_RGBA_UBYTE:
- for (row = 0; row < height; row++) {
- const GLubyte *src = map + y * trans->stride;
- for (col = 0; col < width; col++) {
- GLuint pixel = ((GLuint *) src)[col];
- dst[col*4+0] = (pixel >> 16) & 0xff;
- dst[col*4+1] = (pixel >> 8) & 0xff;
- dst[col*4+2] = (pixel >> 0) & 0xff;
- dst[col*4+3] = ((pixel >> 24) & 0xff) | alphaORoperand;
- }
- dst += dstStride;
- y += dy;
- }
- break;
- case A8R8G8B8_UNORM_TO_RGB_UBYTE:
- for (row = 0; row < height; row++) {
- const GLubyte *src = map + y * trans->stride;
- for (col = 0; col < width; col++) {
- GLuint pixel = ((GLuint *) src)[col];
- dst[col*3+0] = (pixel >> 16) & 0xff;
- dst[col*3+1] = (pixel >> 8) & 0xff;
- dst[col*3+2] = (pixel >> 0) & 0xff;
- }
- dst += dstStride;
- y += dy;
- }
- break;
- case A8R8G8B8_UNORM_TO_BGRA_UINT:
- for (row = 0; row < height; row++) {
- const GLubyte *src = map + y * trans->stride;
- memcpy(dst, src, 4 * width);
- if (alphaORoperand) {
- assert(alphaORoperand == 0xff);
- for (col = 0; col < width; col++) {
- dst[col*4+3] = 0xff;
- }
- }
- dst += dstStride;
- y += dy;
- }
- break;
- case A8R8G8B8_UNORM_TO_RGBA_UINT:
- for (row = 0; row < height; row++) {
- const GLubyte *src = map + y * trans->stride;
- for (col = 0; col < width; col++) {
- GLuint pixel = ((GLuint *) src)[col];
- dst[col*4+0] = ((pixel >> 24) & 0xff) | alphaORoperand;
- dst[col*4+1] = (pixel >> 0) & 0xff;
- dst[col*4+2] = (pixel >> 8) & 0xff;
- dst[col*4+3] = (pixel >> 16) & 0xff;
- }
- dst += dstStride;
- y += dy;
- }
- break;
- default:
- ; /* nothing */
- }
-
- pipe_transfer_unmap(pipe, trans);
- pipe->transfer_destroy(pipe, trans);
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Do glReadPixels by getting rows from the framebuffer transfer with
- * get_tile(). Convert to requested format/type with Mesa image routines.
- * Image transfer ops are done in software too.
- */
-static void
-st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type,
- const struct gl_pixelstore_attrib *pack,
- GLvoid *dest)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- GLfloat (*temp)[4];
- GLbitfield transferOps = ctx->_ImageTransferState;
- GLsizei i, j;
- GLint yStep, dfStride;
- GLfloat *df;
- struct st_renderbuffer *strb;
- struct gl_pixelstore_attrib clippedPacking = *pack;
- struct pipe_transfer *trans;
- enum pipe_format pformat;
-
- assert(ctx->ReadBuffer->Width > 0);
-
- st_validate_state(st);
-
- /* Do all needed clipping here, so that we can forget about it later */
- if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
- /* The ReadPixels transfer is totally outside the window bounds */
- return;
- }
-
- st_flush_bitmap_cache(st);
-
- dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest);
- if (!dest)
- return;
-
- if (format == GL_STENCIL_INDEX ||
- format == GL_DEPTH_STENCIL) {
- st_read_stencil_pixels(ctx, x, y, width, height,
- format, type, pack, dest);
- return;
- }
- else if (format == GL_DEPTH_COMPONENT) {
- strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
- if (strb->Base.Wrapped) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- }
- }
- else {
- /* Read color buffer */
- strb = st_get_color_read_renderbuffer(ctx);
- }
-
- if (!strb)
- return;
-
- /* try a fast-path readpixels before anything else */
- if (st_fast_readpixels(ctx, strb, x, y, width, height,
- format, type, pack, dest)) {
- /* success! */
- _mesa_unmap_pbo_dest(ctx, &clippedPacking);
- return;
- }
-
- /* allocate temp pixel row buffer */
- temp = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
- if (!temp) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
- return;
- }
-
- if(ctx->Color._ClampReadColor)
- transferOps |= IMAGE_CLAMP_BIT;
-
- if (format == GL_RGBA && type == GL_FLOAT && !transferOps) {
- /* write tile(row) directly into user's buffer */
- df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
- height, format, type, 0, 0);
- dfStride = width * 4;
- }
- else {
- /* write tile(row) into temp row buffer */
- df = (GLfloat *) temp;
- dfStride = 0;
- }
-
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- /* convert GL Y to Gallium Y */
- y = strb->Base.Height - y - height;
- }
-
- /* Create a read transfer from the renderbuffer's texture */
- trans = pipe_get_transfer(pipe, strb->texture,
- strb->rtt_level, /* level */
- strb->rtt_face + strb->rtt_slice, /* layer */
- PIPE_TRANSFER_READ,
- x, y, width, height);
-
- /* determine bottom-to-top vs. top-to-bottom order */
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- y = height - 1;
- yStep = -1;
- }
- else {
- y = 0;
- yStep = 1;
- }
-
- /* possibly convert sRGB format to linear RGB format */
- pformat = util_format_linear(trans->resource->format);
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback processing\n", __FUNCTION__);
-
- /*
- * Copy pixels from pipe_transfer to user memory
- */
- {
- /* dest of first pixel in client memory */
- GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width,
- height, format, type, 0, 0);
- /* dest row stride */
- const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width,
- format, type);
-
- if (pformat == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
- pformat == PIPE_FORMAT_Z24X8_UNORM) {
- if (format == GL_DEPTH_COMPONENT) {
- for (i = 0; i < height; i++) {
- GLuint ztemp[MAX_WIDTH];
- GLfloat zfloat[MAX_WIDTH];
- const double scale = 1.0 / ((1 << 24) - 1);
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
- y += yStep;
- for (j = 0; j < width; j++) {
- zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff));
- }
- _mesa_pack_depth_span(ctx, width, dst, type,
- zfloat, &clippedPacking);
- dst += dstStride;
- }
- }
- else {
- /* XXX: unreachable code -- should be before st_read_stencil_pixels */
- assert(format == GL_DEPTH_STENCIL_EXT);
- for (i = 0; i < height; i++) {
- GLuint *zshort = (GLuint *)dst;
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
- y += yStep;
- /* Reverse into 24/8 */
- for (j = 0; j < width; j++) {
- zshort[j] = (zshort[j] << 8) | (zshort[j] >> 24);
- }
- dst += dstStride;
- }
- }
- }
- else if (pformat == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
- pformat == PIPE_FORMAT_X8Z24_UNORM) {
- if (format == GL_DEPTH_COMPONENT) {
- for (i = 0; i < height; i++) {
- GLuint ztemp[MAX_WIDTH];
- GLfloat zfloat[MAX_WIDTH];
- const double scale = 1.0 / ((1 << 24) - 1);
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
- y += yStep;
- for (j = 0; j < width; j++) {
- zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff));
- }
- _mesa_pack_depth_span(ctx, width, dst, type,
- zfloat, &clippedPacking);
- dst += dstStride;
- }
- }
- else {
- /* XXX: unreachable code -- should be before st_read_stencil_pixels */
- assert(format == GL_DEPTH_STENCIL_EXT);
- for (i = 0; i < height; i++) {
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
- y += yStep;
- dst += dstStride;
- }
- }
- }
- else if (pformat == PIPE_FORMAT_Z16_UNORM) {
- for (i = 0; i < height; i++) {
- GLushort ztemp[MAX_WIDTH];
- GLfloat zfloat[MAX_WIDTH];
- const double scale = 1.0 / 0xffff;
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
- y += yStep;
- for (j = 0; j < width; j++) {
- zfloat[j] = (float) (scale * ztemp[j]);
- }
- _mesa_pack_depth_span(ctx, width, dst, type,
- zfloat, &clippedPacking);
- dst += dstStride;
- }
- }
- else if (pformat == PIPE_FORMAT_Z32_UNORM) {
- for (i = 0; i < height; i++) {
- GLuint ztemp[MAX_WIDTH];
- GLfloat zfloat[MAX_WIDTH];
- const double scale = 1.0 / 0xffffffff;
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
- y += yStep;
- for (j = 0; j < width; j++) {
- zfloat[j] = (float) (scale * ztemp[j]);
- }
- _mesa_pack_depth_span(ctx, width, dst, type,
- zfloat, &clippedPacking);
- dst += dstStride;
- }
- }
- else if (pformat == PIPE_FORMAT_Z32_FLOAT) {
- for (i = 0; i < height; i++) {
- GLfloat zfloat[MAX_WIDTH];
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, zfloat, 0);
- y += yStep;
- _mesa_pack_depth_span(ctx, width, dst, type,
- zfloat, &clippedPacking);
- dst += dstStride;
- }
- }
- else if (pformat == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED) {
- assert(format == GL_DEPTH_COMPONENT);
- for (i = 0; i < height; i++) {
- GLfloat zfloat[MAX_WIDTH]; /* Z32 */
- GLfloat zfloat2[MAX_WIDTH*2]; /* Z32X32 */
- pipe_get_tile_raw(pipe, trans, 0, y, width, 1, zfloat2, 0);
- y += yStep;
- for (j = 0; j < width; j++) {
- zfloat[j] = zfloat2[j*2];
- }
- _mesa_pack_depth_span(ctx, width, dst, type,
- zfloat, &clippedPacking);
- dst += dstStride;
- }
- }
- else {
- /* RGBA format */
- /* Do a row at a time to flip image data vertically */
- for (i = 0; i < height; i++) {
- pipe_get_tile_rgba_format(pipe, trans, 0, y, width, 1,
- pformat, df);
- y += yStep;
- df += dfStride;
- if (!dfStride) {
- _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst,
- &clippedPacking, transferOps);
- dst += dstStride;
- }
- }
- }
- }
-
- free(temp);
-
- pipe->transfer_destroy(pipe, trans);
-
- _mesa_unmap_pbo_dest(ctx, &clippedPacking);
-}
-
-
-void st_init_readpixels_functions(struct dd_function_table *functions)
-{
- functions->ReadPixels = st_readpixels;
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + + +/** + * glReadPixels interface to pipe + * + * \author Brian Paul + */ + + +#include "main/imports.h" +#include "main/bufferobj.h" +#include "main/context.h" +#include "main/image.h" +#include "main/pack.h" +#include "main/pbo.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_format.h" +#include "util/u_inlines.h" +#include "util/u_tile.h" + +#include "st_debug.h" +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_bitmap.h" +#include "st_cb_readpixels.h" +#include "st_cb_fbo.h" + +/** + * Special case for reading stencil buffer. + * For color/depth we use get_tile(). For stencil, map the stencil buffer. + */ +void +st_read_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *packing, + GLvoid *pixels) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer); + struct pipe_transfer *pt; + ubyte *stmap; + GLint j; + + if (strb->Base.Wrapped) { + strb = st_renderbuffer(strb->Base.Wrapped); + } + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + y = ctx->DrawBuffer->Height - y - height; + } + + /* Create a read transfer from the renderbuffer's texture */ + + pt = pipe_get_transfer(pipe, strb->texture, + strb->rtt_level, + strb->rtt_face + strb->rtt_slice, + PIPE_TRANSFER_READ, + x, y, width, height); + + /* map the stencil buffer */ + stmap = pipe_transfer_map(pipe, pt); + + /* width should never be > MAX_WIDTH since we did clipping earlier */ + ASSERT(width <= MAX_WIDTH); + + /* process image row by row */ + for (j = 0; j < height; j++) { + GLvoid *dest; + GLstencil sValues[MAX_WIDTH]; + GLfloat zValues[MAX_WIDTH]; + GLint srcY; + + if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) { + srcY = height - j - 1; + } + else { + srcY = j; + } + + /* get stencil (and Z) values */ + switch (pt->resource->format) { + case PIPE_FORMAT_S8_USCALED: + { + const ubyte *src = stmap + srcY * pt->stride; + memcpy(sValues, src, width); + } + break; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + if (format == GL_DEPTH_STENCIL) { + const uint *src = (uint *) (stmap + srcY * pt->stride); + const GLfloat scale = 1.0f / (0xffffff); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] >> 24; + zValues[k] = (src[k] & 0xffffff) * scale; + } + } + else { + const uint *src = (uint *) (stmap + srcY * pt->stride); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] >> 24; + } + } + break; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + if (format == GL_DEPTH_STENCIL) { + const uint *src = (uint *) (stmap + srcY * pt->stride); + const GLfloat scale = 1.0f / (0xffffff); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] & 0xff; + zValues[k] = (src[k] >> 8) * scale; + } + } + else { + const uint *src = (uint *) (stmap + srcY * pt->stride); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k] & 0xff; + } + } + break; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + if (format == GL_DEPTH_STENCIL) { + const uint *src = (uint *) (stmap + srcY * pt->stride); + const GLfloat *srcf = (const GLfloat*)src; + GLint k; + for (k = 0; k < width; k++) { + zValues[k] = srcf[k*2]; + sValues[k] = src[k*2+1] & 0xff; + } + } + else { + const uint *src = (uint *) (stmap + srcY * pt->stride); + GLint k; + for (k = 0; k < width; k++) { + sValues[k] = src[k*2+1] & 0xff; + } + } + break; + default: + assert(0); + } + + /* store */ + dest = _mesa_image_address2d(packing, pixels, width, height, + format, type, j, 0); + if (format == GL_DEPTH_STENCIL) { + _mesa_pack_depth_stencil_span(ctx, width, type, dest, + zValues, sValues, packing); + } + else { + _mesa_pack_stencil_span(ctx, width, type, dest, sValues, packing); + } + } + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, pt); + pipe->transfer_destroy(pipe, pt); +} + + +/** + * Return renderbuffer to use for reading color pixels for glRead/CopyPixel + * commands. + */ +struct st_renderbuffer * +st_get_color_read_renderbuffer(struct gl_context *ctx) +{ + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct st_renderbuffer *strb = + st_renderbuffer(fb->_ColorReadBuffer); + + return strb; +} + + +/** + * Try to do glReadPixels in a fast manner for common cases. + * \return GL_TRUE for success, GL_FALSE for failure + */ +static GLboolean +st_fast_readpixels(struct gl_context *ctx, struct st_renderbuffer *strb, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + GLubyte alphaORoperand; + enum combination { + A8R8G8B8_UNORM_TO_RGBA_UBYTE, + A8R8G8B8_UNORM_TO_RGB_UBYTE, + A8R8G8B8_UNORM_TO_BGRA_UINT, + A8R8G8B8_UNORM_TO_RGBA_UINT + } combo; + + if (ctx->_ImageTransferState) + return GL_FALSE; + + if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM) { + alphaORoperand = 0; + } + else if (strb->format == PIPE_FORMAT_B8G8R8X8_UNORM ) { + alphaORoperand = 0xff; + } + else { + return GL_FALSE; + } + + if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE; + } + else if (format == GL_RGB && type == GL_UNSIGNED_BYTE) { + combo = A8R8G8B8_UNORM_TO_RGB_UBYTE; + } + else if (format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) { + combo = A8R8G8B8_UNORM_TO_BGRA_UINT; + } + else if (format == GL_RGBA && type == GL_UNSIGNED_INT_8_8_8_8) { + combo = A8R8G8B8_UNORM_TO_RGBA_UINT; + } + else { + return GL_FALSE; + } + + /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/ + + { + struct pipe_context *pipe = st_context(ctx)->pipe; + struct pipe_transfer *trans; + const GLubyte *map; + GLubyte *dst; + GLint row, col, dy, dstStride; + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* convert GL Y to Gallium Y */ + y = strb->texture->height0 - y - height; + } + + trans = pipe_get_transfer(pipe, strb->texture, + strb->rtt_level, + strb->rtt_face + strb->rtt_slice, + PIPE_TRANSFER_READ, + x, y, width, height); + if (!trans) { + return GL_FALSE; + } + + map = pipe_transfer_map(pipe, trans); + if (!map) { + pipe->transfer_destroy(pipe, trans); + return GL_FALSE; + } + + /* We always write to the user/dest buffer from low addr to high addr + * but the read order depends on renderbuffer orientation + */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* read source rows from bottom to top */ + y = height - 1; + dy = -1; + } + else { + /* read source rows from top to bottom */ + y = 0; + dy = 1; + } + + dst = _mesa_image_address2d(pack, dest, width, height, + format, type, 0, 0); + dstStride = _mesa_image_row_stride(pack, width, format, type); + + switch (combo) { + case A8R8G8B8_UNORM_TO_RGBA_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*4+0] = (pixel >> 16) & 0xff; + dst[col*4+1] = (pixel >> 8) & 0xff; + dst[col*4+2] = (pixel >> 0) & 0xff; + dst[col*4+3] = ((pixel >> 24) & 0xff) | alphaORoperand; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_RGB_UBYTE: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*3+0] = (pixel >> 16) & 0xff; + dst[col*3+1] = (pixel >> 8) & 0xff; + dst[col*3+2] = (pixel >> 0) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_BGRA_UINT: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + memcpy(dst, src, 4 * width); + if (alphaORoperand) { + assert(alphaORoperand == 0xff); + for (col = 0; col < width; col++) { + dst[col*4+3] = 0xff; + } + } + dst += dstStride; + y += dy; + } + break; + case A8R8G8B8_UNORM_TO_RGBA_UINT: + for (row = 0; row < height; row++) { + const GLubyte *src = map + y * trans->stride; + for (col = 0; col < width; col++) { + GLuint pixel = ((GLuint *) src)[col]; + dst[col*4+0] = ((pixel >> 24) & 0xff) | alphaORoperand; + dst[col*4+1] = (pixel >> 0) & 0xff; + dst[col*4+2] = (pixel >> 8) & 0xff; + dst[col*4+3] = (pixel >> 16) & 0xff; + } + dst += dstStride; + y += dy; + } + break; + default: + ; /* nothing */ + } + + pipe_transfer_unmap(pipe, trans); + pipe->transfer_destroy(pipe, trans); + } + + return GL_TRUE; +} + + +/** + * Do glReadPixels by getting rows from the framebuffer transfer with + * get_tile(). Convert to requested format/type with Mesa image routines. + * Image transfer ops are done in software too. + */ +static void +st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *dest) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLfloat (*temp)[4]; + GLbitfield transferOps = ctx->_ImageTransferState; + GLsizei i, j; + GLint yStep, dfStride; + GLfloat *df; + struct st_renderbuffer *strb; + struct gl_pixelstore_attrib clippedPacking = *pack; + struct pipe_transfer *trans; + enum pipe_format pformat; + + assert(ctx->ReadBuffer->Width > 0); + + st_validate_state(st); + + /* Do all needed clipping here, so that we can forget about it later */ + if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) { + /* The ReadPixels transfer is totally outside the window bounds */ + return; + } + + st_flush_bitmap_cache(st); + + dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest); + if (!dest) + return; + + if (format == GL_STENCIL_INDEX || + format == GL_DEPTH_STENCIL) { + st_read_stencil_pixels(ctx, x, y, width, height, + format, type, pack, dest); + return; + } + else if (format == GL_DEPTH_COMPONENT) { + strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); + if (strb->Base.Wrapped) { + strb = st_renderbuffer(strb->Base.Wrapped); + } + } + else { + /* Read color buffer */ + strb = st_get_color_read_renderbuffer(ctx); + } + + if (!strb) + return; + + /* try a fast-path readpixels before anything else */ + if (st_fast_readpixels(ctx, strb, x, y, width, height, + format, type, pack, dest)) { + /* success! */ + _mesa_unmap_pbo_dest(ctx, &clippedPacking); + return; + } + + /* allocate temp pixel row buffer */ + temp = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat)); + if (!temp) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels"); + return; + } + + if(ctx->Color._ClampReadColor) + transferOps |= IMAGE_CLAMP_BIT; + + if (format == GL_RGBA && type == GL_FLOAT && !transferOps) { + /* write tile(row) directly into user's buffer */ + df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width, + height, format, type, 0, 0); + dfStride = width * 4; + } + else { + /* write tile(row) into temp row buffer */ + df = (GLfloat *) temp; + dfStride = 0; + } + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + /* convert GL Y to Gallium Y */ + y = strb->Base.Height - y - height; + } + + /* Create a read transfer from the renderbuffer's texture */ + trans = pipe_get_transfer(pipe, strb->texture, + strb->rtt_level, /* level */ + strb->rtt_face + strb->rtt_slice, /* layer */ + PIPE_TRANSFER_READ, + x, y, width, height); + + /* determine bottom-to-top vs. top-to-bottom order */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + y = height - 1; + yStep = -1; + } + else { + y = 0; + yStep = 1; + } + + /* possibly convert sRGB format to linear RGB format */ + pformat = util_format_linear(trans->resource->format); + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback processing\n", __FUNCTION__); + + /* + * Copy pixels from pipe_transfer to user memory + */ + { + /* dest of first pixel in client memory */ + GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width, + height, format, type, 0, 0); + /* dest row stride */ + const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width, + format, type); + + if (pformat == PIPE_FORMAT_Z24_UNORM_S8_USCALED || + pformat == PIPE_FORMAT_Z24X8_UNORM) { + if (format == GL_DEPTH_COMPONENT) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / ((1 << 24) - 1); + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff)); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* XXX: unreachable code -- should be before st_read_stencil_pixels */ + assert(format == GL_DEPTH_STENCIL_EXT); + for (i = 0; i < height; i++) { + GLuint *zshort = (GLuint *)dst; + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0); + y += yStep; + /* Reverse into 24/8 */ + for (j = 0; j < width; j++) { + zshort[j] = (zshort[j] << 8) | (zshort[j] >> 24); + } + dst += dstStride; + } + } + } + else if (pformat == PIPE_FORMAT_S8_USCALED_Z24_UNORM || + pformat == PIPE_FORMAT_X8Z24_UNORM) { + if (format == GL_DEPTH_COMPONENT) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / ((1 << 24) - 1); + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff)); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* XXX: unreachable code -- should be before st_read_stencil_pixels */ + assert(format == GL_DEPTH_STENCIL_EXT); + for (i = 0; i < height; i++) { + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0); + y += yStep; + dst += dstStride; + } + } + } + else if (pformat == PIPE_FORMAT_Z16_UNORM) { + for (i = 0; i < height; i++) { + GLushort ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / 0xffff; + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ztemp[j]); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else if (pformat == PIPE_FORMAT_Z32_UNORM) { + for (i = 0; i < height; i++) { + GLuint ztemp[MAX_WIDTH]; + GLfloat zfloat[MAX_WIDTH]; + const double scale = 1.0 / 0xffffffff; + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = (float) (scale * ztemp[j]); + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else if (pformat == PIPE_FORMAT_Z32_FLOAT) { + for (i = 0; i < height; i++) { + GLfloat zfloat[MAX_WIDTH]; + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, zfloat, 0); + y += yStep; + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else if (pformat == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED) { + assert(format == GL_DEPTH_COMPONENT); + for (i = 0; i < height; i++) { + GLfloat zfloat[MAX_WIDTH]; /* Z32 */ + GLfloat zfloat2[MAX_WIDTH*2]; /* Z32X32 */ + pipe_get_tile_raw(pipe, trans, 0, y, width, 1, zfloat2, 0); + y += yStep; + for (j = 0; j < width; j++) { + zfloat[j] = zfloat2[j*2]; + } + _mesa_pack_depth_span(ctx, width, dst, type, + zfloat, &clippedPacking); + dst += dstStride; + } + } + else { + /* RGBA format */ + /* Do a row at a time to flip image data vertically */ + for (i = 0; i < height; i++) { + pipe_get_tile_rgba_format(pipe, trans, 0, y, width, 1, + pformat, df); + y += yStep; + df += dfStride; + if (!dfStride) { + _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst, + &clippedPacking, transferOps); + dst += dstStride; + } + } + } + } + + free(temp); + + pipe->transfer_destroy(pipe, trans); + + _mesa_unmap_pbo_dest(ctx, &clippedPacking); +} + + +void st_init_readpixels_functions(struct dd_function_table *functions) +{ + functions->ReadPixels = st_readpixels; +} diff --git a/mesalib/src/mesa/state_tracker/st_cb_texture.c b/mesalib/src/mesa/state_tracker/st_cb_texture.c index 726f185b4..e4be7fba4 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_texture.c +++ b/mesalib/src/mesa/state_tracker/st_cb_texture.c @@ -1,1934 +1,1934 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-#include "main/mfeatures.h"
-#include "main/bufferobj.h"
-#include "main/enums.h"
-#include "main/fbobject.h"
-#include "main/formats.h"
-#include "main/image.h"
-#include "main/imports.h"
-#include "main/macros.h"
-#include "main/mipmap.h"
-#include "main/pack.h"
-#include "main/pbo.h"
-#include "main/pixeltransfer.h"
-#include "main/texcompress.h"
-#include "main/texfetch.h"
-#include "main/texgetimage.h"
-#include "main/teximage.h"
-#include "main/texobj.h"
-#include "main/texstore.h"
-
-#include "state_tracker/st_debug.h"
-#include "state_tracker/st_context.h"
-#include "state_tracker/st_cb_fbo.h"
-#include "state_tracker/st_cb_flush.h"
-#include "state_tracker/st_cb_texture.h"
-#include "state_tracker/st_format.h"
-#include "state_tracker/st_texture.h"
-#include "state_tracker/st_gen_mipmap.h"
-#include "state_tracker/st_atom.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-#include "pipe/p_shader_tokens.h"
-#include "util/u_tile.h"
-#include "util/u_blit.h"
-#include "util/u_format.h"
-#include "util/u_surface.h"
-#include "util/u_sampler.h"
-#include "util/u_math.h"
-#include "util/u_box.h"
-
-#define DBG if (0) printf
-
-
-static enum pipe_texture_target
-gl_target_to_pipe(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- return PIPE_TEXTURE_1D;
- case GL_TEXTURE_2D:
- return PIPE_TEXTURE_2D;
- case GL_TEXTURE_RECTANGLE_NV:
- return PIPE_TEXTURE_RECT;
- case GL_TEXTURE_3D:
- return PIPE_TEXTURE_3D;
- case GL_TEXTURE_CUBE_MAP_ARB:
- return PIPE_TEXTURE_CUBE;
- case GL_TEXTURE_1D_ARRAY_EXT:
- return PIPE_TEXTURE_1D_ARRAY;
- case GL_TEXTURE_2D_ARRAY_EXT:
- return PIPE_TEXTURE_2D_ARRAY;
- case GL_TEXTURE_BUFFER:
- return PIPE_BUFFER;
- default:
- assert(0);
- return 0;
- }
-}
-
-
-/** called via ctx->Driver.NewTextureImage() */
-static struct gl_texture_image *
-st_NewTextureImage(struct gl_context * ctx)
-{
- DBG("%s\n", __FUNCTION__);
- (void) ctx;
- return (struct gl_texture_image *) ST_CALLOC_STRUCT(st_texture_image);
-}
-
-
-/** called via ctx->Driver.NewTextureObject() */
-static struct gl_texture_object *
-st_NewTextureObject(struct gl_context * ctx, GLuint name, GLenum target)
-{
- struct st_texture_object *obj = ST_CALLOC_STRUCT(st_texture_object);
-
- DBG("%s\n", __FUNCTION__);
- _mesa_initialize_texture_object(&obj->base, name, target);
-
- return &obj->base;
-}
-
-/** called via ctx->Driver.DeleteTextureObject() */
-static void
-st_DeleteTextureObject(struct gl_context *ctx,
- struct gl_texture_object *texObj)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_object *stObj = st_texture_object(texObj);
- if (stObj->pt)
- pipe_resource_reference(&stObj->pt, NULL);
- if (stObj->sampler_view) {
- if (stObj->sampler_view->context != st->pipe) {
- /* Take "ownership" of this texture sampler view by setting
- * its context pointer to this context. This avoids potential
- * crashes when the texture object is shared among contexts
- * and the original/owner context has already been destroyed.
- */
- stObj->sampler_view->context = st->pipe;
- }
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- }
- _mesa_delete_texture_object(ctx, texObj);
-}
-
-
-/** called via ctx->Driver.FreeTextureImageBuffer() */
-static void
-st_FreeTextureImageBuffer(struct gl_context * ctx, struct gl_texture_image *texImage)
-{
- struct st_texture_image *stImage = st_texture_image(texImage);
-
- DBG("%s\n", __FUNCTION__);
-
- if (stImage->pt) {
- pipe_resource_reference(&stImage->pt, NULL);
- }
-
- if (texImage->Data) {
- _mesa_align_free(texImage->Data);
- texImage->Data = NULL;
- }
-}
-
-
-/** called via ctx->Driver.MapTextureImage() */
-static void
-st_MapTextureImage(struct gl_context *ctx,
- struct gl_texture_image *texImage,
- GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h,
- GLbitfield mode,
- GLubyte **mapOut, GLint *rowStrideOut)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- unsigned pipeMode;
- GLubyte *map;
-
- pipeMode = 0x0;
- if (mode & GL_MAP_READ_BIT)
- pipeMode |= PIPE_TRANSFER_READ;
- if (mode & GL_MAP_WRITE_BIT)
- pipeMode |= PIPE_TRANSFER_WRITE;
-
- map = st_texture_image_map(st, stImage, slice, pipeMode, x, y, w, h);
- if (map) {
- *mapOut = map;
- *rowStrideOut = stImage->transfer->stride;
- }
- else {
- *mapOut = NULL;
- *rowStrideOut = 0;
- }
-}
-
-
-/** called via ctx->Driver.UnmapTextureImage() */
-static void
-st_UnmapTextureImage(struct gl_context *ctx,
- struct gl_texture_image *texImage,
- GLuint slice)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- st_texture_image_unmap(st, stImage);
-}
-
-
-/**
- * From linux kernel i386 header files, copes with odd sizes better
- * than COPY_DWORDS would:
- * XXX Put this in src/mesa/main/imports.h ???
- */
-#if defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86)
-static INLINE void *
-__memcpy(void *to, const void *from, size_t n)
-{
- int d0, d1, d2;
- __asm__ __volatile__("rep ; movsl\n\t"
- "testb $2,%b4\n\t"
- "je 1f\n\t"
- "movsw\n"
- "1:\ttestb $1,%b4\n\t"
- "je 2f\n\t"
- "movsb\n" "2:":"=&c"(d0), "=&D"(d1), "=&S"(d2)
- :"0"(n / 4), "q"(n), "1"((long) to), "2"((long) from)
- :"memory");
- return (to);
-}
-#else
-#define __memcpy(a,b,c) memcpy(a,b,c)
-#endif
-
-
-/**
- * The system memcpy (at least on ubuntu 5.10) has problems copying
- * to agp (writecombined) memory from a source which isn't 64-byte
- * aligned - there is a 4x performance falloff.
- *
- * The x86 __memcpy is immune to this but is slightly slower
- * (10%-ish) than the system memcpy.
- *
- * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but
- * isn't much faster than x86_memcpy for agp copies.
- *
- * TODO: switch dynamically.
- */
-static void *
-do_memcpy(void *dest, const void *src, size_t n)
-{
- if ((((unsigned long) src) & 63) || (((unsigned long) dest) & 63)) {
- return __memcpy(dest, src, n);
- }
- else
- return memcpy(dest, src, n);
-}
-
-
-/**
- * Return default texture resource binding bitmask for the given format.
- */
-static GLuint
-default_bindings(struct st_context *st, enum pipe_format format)
-{
- struct pipe_screen *screen = st->pipe->screen;
- const unsigned target = PIPE_TEXTURE_2D;
- unsigned bindings;
-
- if (util_format_is_depth_or_stencil(format))
- bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL;
- else
- bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
-
- if (screen->is_format_supported(screen, format, target, 0, bindings))
- return bindings;
- else {
- /* Try non-sRGB. */
- format = util_format_linear(format);
-
- if (screen->is_format_supported(screen, format, target, 0, bindings))
- return bindings;
- else
- return PIPE_BIND_SAMPLER_VIEW;
- }
-}
-
-
-/** Return number of image dimensions (1, 2 or 3) for a texture target. */
-static GLuint
-get_texture_dims(GLenum target)
-{
- switch (target) {
- case GL_TEXTURE_1D:
- case GL_TEXTURE_1D_ARRAY_EXT:
- case GL_TEXTURE_BUFFER:
- return 1;
- case GL_TEXTURE_2D:
- case GL_TEXTURE_CUBE_MAP_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
- case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
- case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
- case GL_TEXTURE_RECTANGLE_NV:
- case GL_TEXTURE_2D_ARRAY_EXT:
- return 2;
- case GL_TEXTURE_3D:
- return 3;
- default:
- assert(0 && "invalid texture target in get_texture_dims()");
- return 1;
- }
-}
-
-
-/**
- * Given the size of a mipmap image, try to compute the size of the level=0
- * mipmap image.
- *
- * Note that this isn't always accurate for odd-sized, non-POW textures.
- * For example, if level=1 and width=40 then the level=0 width may be 80 or 81.
- *
- * \return GL_TRUE for success, GL_FALSE for failure
- */
-static GLboolean
-guess_base_level_size(GLenum target,
- GLuint width, GLuint height, GLuint depth, GLuint level,
- GLuint *width0, GLuint *height0, GLuint *depth0)
-{
- const GLuint dims = get_texture_dims(target);
-
- assert(width >= 1);
- assert(height >= 1);
- assert(depth >= 1);
-
- if (level > 0) {
- /* Depending on the image's size, we can't always make a guess here */
- if ((dims >= 1 && width == 1) ||
- (dims >= 2 && height == 1) ||
- (dims >= 3 && depth == 1)) {
- /* we can't determine the image size at level=0 */
- return GL_FALSE;
- }
-
- /* grow the image size until we hit level = 0 */
- while (level > 0) {
- if (width > 1)
- width <<= 1;
- if (height > 1)
- height <<= 1;
- if (depth > 1)
- depth <<= 1;
- level--;
- }
- }
-
- *width0 = width;
- *height0 = height;
- *depth0 = depth;
-
- return GL_TRUE;
-}
-
-
-/**
- * Try to allocate a pipe_resource object for the given st_texture_object.
- *
- * We use the given st_texture_image as a clue to determine the size of the
- * mipmap image at level=0.
- *
- * \return GL_TRUE for success, GL_FALSE if out of memory.
- */
-static GLboolean
-guess_and_alloc_texture(struct st_context *st,
- struct st_texture_object *stObj,
- const struct st_texture_image *stImage)
-{
- GLuint lastLevel, width, height, depth;
- GLuint bindings;
- GLuint ptWidth, ptHeight, ptDepth, ptLayers;
- enum pipe_format fmt;
-
- DBG("%s\n", __FUNCTION__);
-
- assert(!stObj->pt);
-
- if (!guess_base_level_size(stObj->base.Target,
- stImage->base.Width2,
- stImage->base.Height2,
- stImage->base.Depth2,
- stImage->base.Level,
- &width, &height, &depth)) {
- /* we can't determine the image size at level=0 */
- stObj->width0 = stObj->height0 = stObj->depth0 = 0;
- /* this is not an out of memory error */
- return GL_TRUE;
- }
-
- /* At this point, (width x height x depth) is the expected size of
- * the level=0 mipmap image.
- */
-
- /* Guess a reasonable value for lastLevel. With OpenGL we have no
- * idea how many mipmap levels will be in a texture until we start
- * to render with it. Make an educated guess here but be prepared
- * to re-allocating a texture buffer with space for more (or fewer)
- * mipmap levels later.
- */
- if ((stObj->base.Sampler.MinFilter == GL_NEAREST ||
- stObj->base.Sampler.MinFilter == GL_LINEAR ||
- stImage->base._BaseFormat == GL_DEPTH_COMPONENT ||
- stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) &&
- !stObj->base.GenerateMipmap &&
- stImage->base.Level == 0) {
- /* only alloc space for a single mipmap level */
- lastLevel = 0;
- }
- else {
- /* alloc space for a full mipmap */
- GLuint l2width = util_logbase2(width);
- GLuint l2height = util_logbase2(height);
- GLuint l2depth = util_logbase2(depth);
- lastLevel = MAX2(MAX2(l2width, l2height), l2depth);
- }
-
- /* Save the level=0 dimensions */
- stObj->width0 = width;
- stObj->height0 = height;
- stObj->depth0 = depth;
-
- fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat);
-
- bindings = default_bindings(st, fmt);
-
- st_gl_texture_dims_to_pipe_dims(stObj->base.Target,
- width, height, depth,
- &ptWidth, &ptHeight, &ptDepth, &ptLayers);
-
- stObj->pt = st_texture_create(st,
- gl_target_to_pipe(stObj->base.Target),
- fmt,
- lastLevel,
- ptWidth,
- ptHeight,
- ptDepth,
- ptLayers,
- bindings);
-
- DBG("%s returning %d\n", __FUNCTION__, (stObj->pt != NULL));
-
- return stObj->pt != NULL;
-}
-
-
-/**
- * Adjust pixel unpack params and image dimensions to strip off the
- * texture border.
- * Gallium doesn't support texture borders. They've seldem been used
- * and seldom been implemented correctly anyway.
- * \param unpackNew returns the new pixel unpack parameters
- */
-static void
-strip_texture_border(GLint border,
- GLint *width, GLint *height, GLint *depth,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_pixelstore_attrib *unpackNew)
-{
- assert(border > 0); /* sanity check */
-
- *unpackNew = *unpack;
-
- if (unpackNew->RowLength == 0)
- unpackNew->RowLength = *width;
-
- if (depth && unpackNew->ImageHeight == 0)
- unpackNew->ImageHeight = *height;
-
- unpackNew->SkipPixels += border;
- if (height)
- unpackNew->SkipRows += border;
- if (depth)
- unpackNew->SkipImages += border;
-
- assert(*width >= 3);
- *width = *width - 2 * border;
- if (height && *height >= 3)
- *height = *height - 2 * border;
- if (depth && *depth >= 3)
- *depth = *depth - 2 * border;
-}
-
-
-/**
- * Do glTexImage1/2/3D().
- */
-static void
-st_TexImage(struct gl_context * ctx,
- GLint dims,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint depth,
- GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage,
- GLsizei imageSize, GLboolean compressed_src)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_object *stObj = st_texture_object(texObj);
- struct st_texture_image *stImage = st_texture_image(texImage);
- GLuint dstRowStride = 0;
- struct gl_pixelstore_attrib unpackNB;
- enum pipe_transfer_usage transfer_usage = 0;
-
- DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__,
- _mesa_lookup_enum_by_nr(target), level, width, height, depth, border);
-
- /* switch to "normal" */
- if (stObj->surface_based) {
- gl_format texFormat;
-
- _mesa_clear_texture_object(ctx, texObj);
- pipe_resource_reference(&stObj->pt, NULL);
-
- /* oops, need to init this image again */
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, format, type);
-
- _mesa_init_teximage_fields(ctx, target, texImage,
- width, height, depth, border,
- internalFormat, texFormat);
-
- stObj->surface_based = GL_FALSE;
- }
-
- /* gallium does not support texture borders, strip it off */
- if (border) {
- strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB);
- unpack = &unpackNB;
- texImage->Width = width;
- texImage->Height = height;
- texImage->Depth = depth;
- texImage->Border = 0;
- border = 0;
- }
- else {
- assert(texImage->Width == width);
- assert(texImage->Height == height);
- assert(texImage->Depth == depth);
- }
-
- stImage->base.Face = _mesa_tex_target_to_face(target);
- stImage->base.Level = level;
-
- _mesa_set_fetch_functions(texImage, dims);
-
- /* Release the reference to a potentially orphaned buffer.
- * Release any old malloced memory.
- */
- if (stImage->pt) {
- pipe_resource_reference(&stImage->pt, NULL);
- assert(!texImage->Data);
- }
- else if (texImage->Data) {
- _mesa_align_free(texImage->Data);
- }
-
- /*
- * See if the new image is somehow incompatible with the existing
- * mipmap. If so, free the old mipmap.
- */
- if (stObj->pt) {
- if (level > (GLint) stObj->pt->last_level ||
- !st_texture_match_image(stObj->pt, &stImage->base,
- stImage->base.Face, stImage->base.Level)) {
- DBG("release it\n");
- pipe_resource_reference(&stObj->pt, NULL);
- assert(!stObj->pt);
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- }
- }
-
- if (width == 0 || height == 0 || depth == 0) {
- /* stop after freeing old image */
- return;
- }
-
- if (!stObj->pt) {
- if (!guess_and_alloc_texture(st, stObj, stImage)) {
- /* Probably out of memory.
- * Try flushing any pending rendering, then retry.
- */
- st_finish(st);
- if (!guess_and_alloc_texture(st, stObj, stImage)) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- return;
- }
- }
- }
-
- assert(!stImage->pt);
-
- /* Check if this texture image can live inside the texture object's buffer.
- * If so, store the image there. Otherwise the image will temporarily live
- * in its own buffer.
- */
- if (stObj->pt &&
- st_texture_match_image(stObj->pt, &stImage->base,
- stImage->base.Face, stImage->base.Level)) {
-
- pipe_resource_reference(&stImage->pt, stObj->pt);
- assert(stImage->pt);
- }
-
- if (!stImage->pt)
- DBG("XXX: Image did not fit into texture - storing in local memory!\n");
-
- /* Pixel data may come from regular user memory or a PBO. For the later,
- * do bounds checking and map the PBO to read pixels data from it.
- *
- * XXX we should try to use a GPU-accelerated path to copy the image data
- * from the PBO to the texture.
- */
- if (compressed_src) {
- pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels,
- unpack,
- "glCompressedTexImage");
- }
- else {
- pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1,
- format, type,
- pixels, unpack, "glTexImage");
- }
-
- /* for a 1D array upload the image as a series of layer with height = 1 */
- if (target == GL_TEXTURE_1D_ARRAY) {
- depth = height;
- height = 1;
- }
-
- /*
- * Prepare to store the texture data. Either map the gallium texture buffer
- * memory or malloc space for it.
- */
- if (stImage->pt) {
- if (!pixels) {
- /* We've allocated texture resource, but have no pixel data - all done. */
- goto done;
- }
-
- /* Store the image in the gallium transfer object */
- if (format == GL_DEPTH_COMPONENT &&
- util_format_is_depth_and_stencil(stImage->pt->format))
- transfer_usage = PIPE_TRANSFER_READ_WRITE;
- else
- transfer_usage = PIPE_TRANSFER_WRITE;
-
- texImage->Data = st_texture_image_map(st, stImage, 0,
- transfer_usage, 0, 0, width, height);
- if(stImage->transfer)
- dstRowStride = stImage->transfer->stride;
- }
- else {
- /* Allocate regular memory and store the image there temporarily. */
- GLuint imageSize = _mesa_format_image_size(texImage->TexFormat,
- width, height, depth);
- dstRowStride = _mesa_format_row_stride(texImage->TexFormat, width);
-
- texImage->Data = _mesa_align_malloc(imageSize, 16);
- }
-
- if (!texImage->Data) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- return;
- }
-
- if (!pixels) {
- /* We've allocated texture memory, but have no pixel data - all done. */
- goto done;
- }
-
- DBG("Upload image %dx%dx%d row_len %x pitch %x\n",
- width, height, depth, width, dstRowStride);
-
- /* Copy user texture image into the texture buffer.
- */
- if (compressed_src) {
- const GLuint srcRowStride =
- _mesa_format_row_stride(texImage->TexFormat, width);
- if (dstRowStride == srcRowStride) {
- memcpy(texImage->Data, pixels, imageSize);
- }
- else {
- char *dst = texImage->Data;
- const char *src = pixels;
- GLuint i, bw, bh, lines;
- _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
- lines = (height + bh - 1) / bh;
-
- for (i = 0; i < lines; ++i) {
- memcpy(dst, src, srcRowStride);
- dst += dstRowStride;
- src += srcRowStride;
- }
- }
- }
- else {
- const GLuint srcImageStride =
- _mesa_image_image_stride(unpack, width, height, format, type);
- GLint i;
- const GLubyte *src = (const GLubyte *) pixels;
-
- for (i = 0; i < depth; i++) {
- if (!_mesa_texstore(ctx, dims,
- texImage->_BaseFormat,
- texImage->TexFormat,
- texImage->Data,
- 0, 0, 0, /* dstX/Y/Zoffset */
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- format, type, src, unpack)) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- }
-
- if (stImage->pt && i + 1 < depth) {
- /* unmap this slice */
- st_texture_image_unmap(st, stImage);
- /* map next slice of 3D texture */
- texImage->Data = st_texture_image_map(st, stImage, i + 1,
- transfer_usage, 0, 0,
- width, height);
- src += srcImageStride;
- }
- }
- }
-
-done:
- _mesa_unmap_teximage_pbo(ctx, unpack);
-
- if (stImage->pt && texImage->Data) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-static void
-st_TexImage3D(struct gl_context * ctx,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint depth,
- GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 3, target, level, internalFormat, width, height, depth,
- border, format, type, pixels, unpack, texObj, texImage,
- 0, GL_FALSE);
-}
-
-
-static void
-st_TexImage2D(struct gl_context * ctx,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border,
- format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE);
-}
-
-
-static void
-st_TexImage1D(struct gl_context * ctx,
- GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint border,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *unpack,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 1, target, level, internalFormat, width, 1, 1, border,
- format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE);
-}
-
-
-static void
-st_CompressedTexImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLint internalFormat,
- GLint width, GLint height, GLint border,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border,
- 0, 0, data, &ctx->Unpack, texObj, texImage, imageSize, GL_TRUE);
-}
-
-
-
-/**
- * glGetTexImage() helper: decompress a compressed texture by rendering
- * a textured quad. Store the results in the user's buffer.
- */
-static void
-decompress_with_blit(struct gl_context * ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid *pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct st_texture_image *stImage = st_texture_image(texImage);
- struct st_texture_object *stObj = st_texture_object(texObj);
- struct pipe_sampler_view *src_view =
- st_get_texture_sampler_view(stObj, pipe);
- const GLuint width = texImage->Width;
- const GLuint height = texImage->Height;
- struct pipe_surface *dst_surface;
- struct pipe_resource *dst_texture;
- struct pipe_transfer *tex_xfer;
- unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */
- PIPE_BIND_TRANSFER_READ);
-
- /* create temp / dest surface */
- if (!util_create_rgba_surface(pipe, width, height, bind,
- &dst_texture, &dst_surface)) {
- _mesa_problem(ctx, "util_create_rgba_surface() failed "
- "in decompress_with_blit()");
- return;
- }
-
- /* Disable conditional rendering. */
- if (st->render_condition) {
- pipe->render_condition(pipe, NULL, 0);
- }
-
- /* blit/render/decompress */
- util_blit_pixels_tex(st->blit,
- src_view, /* pipe_resource (src) */
- 0, 0, /* src x0, y0 */
- width, height, /* src x1, y1 */
- dst_surface, /* pipe_surface (dst) */
- 0, 0, /* dst x0, y0 */
- width, height, /* dst x1, y1 */
- 0.0, /* z */
- PIPE_TEX_MIPFILTER_NEAREST);
-
- /* Restore conditional rendering state. */
- if (st->render_condition) {
- pipe->render_condition(pipe, st->render_condition,
- st->condition_mode);
- }
-
- /* map the dst_surface so we can read from it */
- tex_xfer = pipe_get_transfer(pipe,
- dst_texture, 0, 0,
- PIPE_TRANSFER_READ,
- 0, 0, width, height);
-
- pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels);
-
- /* copy/pack data into user buffer */
- if (st_equal_formats(stImage->pt->format, format, type)) {
- /* memcpy */
- const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format);
- ubyte *map = pipe_transfer_map(pipe, tex_xfer);
- GLuint row;
- for (row = 0; row < height; row++) {
- GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
- height, format, type, row, 0);
- memcpy(dest, map, bytesPerRow);
- map += tex_xfer->stride;
- }
- pipe_transfer_unmap(pipe, tex_xfer);
- }
- else {
- /* format translation via floats */
- GLuint row;
- enum pipe_format pformat = util_format_linear(dst_texture->format);
- for (row = 0; row < height; row++) {
- const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */
- GLfloat rgba[4 * MAX_WIDTH];
- GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width,
- height, format, type, row, 0);
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback format translation\n", __FUNCTION__);
-
- /* get float[4] rgba row from surface */
- pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1,
- pformat, rgba);
-
- _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
- type, dest, &ctx->Pack, transferOps);
- }
- }
-
- _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
-
- pipe->transfer_destroy(pipe, tex_xfer);
-
- /* destroy the temp / dest surface */
- util_destroy_rgba_surface(dst_texture, dst_surface);
-}
-
-
-
-/**
- * Need to map texture image into memory before copying image data,
- * then unmap it.
- */
-static void
-st_get_tex_image(struct gl_context * ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid * pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage, GLboolean compressed_dst)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- const GLuint dstImageStride =
- _mesa_image_image_stride(&ctx->Pack, texImage->Width, texImage->Height,
- format, type);
- GLuint depth, i;
- GLubyte *dest;
-
- if (stImage->pt &&
- util_format_is_s3tc(stImage->pt->format) &&
- !compressed_dst) {
- /* Need to decompress the texture.
- * We'll do this by rendering a textured quad.
- * Note that we only expect RGBA formats (no Z/depth formats).
- */
- decompress_with_blit(ctx, target, level, format, type, pixels,
- texObj, texImage);
- return;
- }
-
- /* Map */
- if (stImage->pt) {
- /* Image is stored in hardware format in a buffer managed by the
- * kernel. Need to explicitly map and unmap it.
- */
- texImage->Data = st_texture_image_map(st, stImage, 0,
- PIPE_TRANSFER_READ, 0, 0,
- stImage->base.Width,
- stImage->base.Height);
- /* compute stride in texels from stride in bytes */
- texImage->RowStride = stImage->transfer->stride
- * util_format_get_blockwidth(stImage->pt->format)
- / util_format_get_blocksize(stImage->pt->format);
- }
- else {
- /* Otherwise, the image should actually be stored in
- * texImage->Data. This is pretty confusing for
- * everybody, I'd much prefer to separate the two functions of
- * texImage->Data - storage for texture images in main memory
- * and access (ie mappings) of images. In other words, we'd
- * create a new texImage->Map field and leave Data simply for
- * storage.
- */
- assert(texImage->Data);
- }
-
- depth = texImage->Depth;
- texImage->Depth = 1;
-
- dest = (GLubyte *) pixels;
-
- _mesa_set_fetch_functions(texImage, get_texture_dims(target));
-
- for (i = 0; i < depth; i++) {
- if (compressed_dst) {
- _mesa_get_compressed_teximage(ctx, target, level, dest,
- texObj, texImage);
- }
- else {
- _mesa_get_teximage(ctx, target, level, format, type, dest,
- texObj, texImage);
- }
-
- if (stImage->pt && i + 1 < depth) {
- /* unmap this slice */
- st_texture_image_unmap(st, stImage);
- /* map next slice of 3D texture */
- texImage->Data = st_texture_image_map(st, stImage, i + 1,
- PIPE_TRANSFER_READ, 0, 0,
- stImage->base.Width,
- stImage->base.Height);
- dest += dstImageStride;
- }
- }
-
- texImage->Depth = depth;
-
- /* Unmap */
- if (stImage->pt) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-static void
-st_GetTexImage(struct gl_context * ctx, GLenum target, GLint level,
- GLenum format, GLenum type, GLvoid * pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_get_tex_image(ctx, target, level, format, type, pixels, texObj, texImage,
- GL_FALSE);
-}
-
-
-static void
-st_GetCompressedTexImage(struct gl_context *ctx, GLenum target, GLint level,
- GLvoid *pixels,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_get_tex_image(ctx, target, level, 0, 0, pixels, texObj, texImage,
- GL_TRUE);
-}
-
-
-
-static void
-st_TexSubimage(struct gl_context *ctx, GLint dims, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint width, GLint height, GLint depth,
- GLenum format, GLenum type, const void *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- GLuint dstRowStride;
- const GLuint srcImageStride =
- _mesa_image_image_stride(packing, width, height, format, type);
- GLint i;
- const GLubyte *src;
- /* init to silence warning only: */
- enum pipe_transfer_usage transfer_usage = PIPE_TRANSFER_WRITE;
-
- DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__,
- _mesa_lookup_enum_by_nr(target),
- level, xoffset, yoffset, width, height);
-
- pixels =
- _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format,
- type, pixels, packing, "glTexSubImage2D");
- if (!pixels)
- return;
-
- /* for a 1D array upload the image as a series of layer with height = 1 */
- if (target == GL_TEXTURE_1D_ARRAY) {
- depth = height;
- height = 1;
- }
-
- /* Map buffer if necessary. Need to lock to prevent other contexts
- * from uploading the buffer under us.
- */
- if (stImage->pt) {
- if (format == GL_DEPTH_COMPONENT &&
- util_format_is_depth_and_stencil(stImage->pt->format))
- transfer_usage = PIPE_TRANSFER_READ_WRITE;
- else
- transfer_usage = PIPE_TRANSFER_WRITE;
-
- texImage->Data = st_texture_image_map(st, stImage, zoffset,
- transfer_usage,
- xoffset, yoffset,
- width, height);
- }
-
- if (!texImage->Data) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- goto done;
- }
-
- src = (const GLubyte *) pixels;
- dstRowStride = stImage->transfer->stride;
-
- for (i = 0; i < depth; i++) {
- if (!_mesa_texstore(ctx, dims, texImage->_BaseFormat,
- texImage->TexFormat,
- texImage->Data,
- 0, 0, 0,
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- format, type, src, packing)) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- }
-
- if (stImage->pt && i + 1 < depth) {
- /* unmap this slice */
- st_texture_image_unmap(st, stImage);
- /* map next slice of 3D texture */
- texImage->Data = st_texture_image_map(st, stImage,
- zoffset + i + 1,
- transfer_usage,
- xoffset, yoffset,
- width, height);
- src += srcImageStride;
- }
- }
-
-done:
- _mesa_unmap_teximage_pbo(ctx, packing);
-
- if (stImage->pt && texImage->Data) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-
-static void
-st_TexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const GLvoid *pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexSubimage(ctx, 3, target, level, xoffset, yoffset, zoffset,
- width, height, depth, format, type,
- pixels, packing, texObj, texImage);
-}
-
-
-static void
-st_TexSubImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type, const GLvoid * pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexSubimage(ctx, 2, target, level, xoffset, yoffset, 0,
- width, height, 1, format, type,
- pixels, packing, texObj, texImage);
-}
-
-
-static void
-st_TexSubImage1D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLsizei width, GLenum format, GLenum type,
- const GLvoid * pixels,
- const struct gl_pixelstore_attrib *packing,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- st_TexSubimage(ctx, 1, target, level, xoffset, 0, 0, width, 1, 1,
- format, type, pixels, packing, texObj, texImage);
-}
-
-
-static void
-st_CompressedTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLsizei width,
- GLenum format,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- assert(0);
-}
-
-
-static void
-st_CompressedTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLsizei width, GLint height,
- GLenum format,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_image *stImage = st_texture_image(texImage);
- int srcBlockStride;
- int dstBlockStride;
- int y;
- enum pipe_format pformat;
-
- if (stImage->pt) {
- pformat = stImage->pt->format;
-
- texImage->Data = st_texture_image_map(st, stImage, 0,
- PIPE_TRANSFER_WRITE,
- xoffset, yoffset,
- width, height);
-
- srcBlockStride = util_format_get_stride(pformat, width);
- dstBlockStride = stImage->transfer->stride;
- } else {
- assert(stImage->pt);
- /* TODO find good values for block and strides */
- /* TODO also adjust texImage->data for yoffset/xoffset */
- return;
- }
-
- if (!texImage->Data) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage");
- return;
- }
-
- assert(xoffset % util_format_get_blockwidth(pformat) == 0);
- assert(yoffset % util_format_get_blockheight(pformat) == 0);
-
- for (y = 0; y < height; y += util_format_get_blockheight(pformat)) {
- /* don't need to adjust for xoffset and yoffset as st_texture_image_map does that */
- const char *src = (const char*)data + srcBlockStride * util_format_get_nblocksy(pformat, y);
- char *dst = (char*)texImage->Data + dstBlockStride * util_format_get_nblocksy(pformat, y);
- memcpy(dst, src, util_format_get_stride(pformat, width));
- }
-
- if (stImage->pt) {
- st_texture_image_unmap(st, stImage);
- texImage->Data = NULL;
- }
-}
-
-
-static void
-st_CompressedTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLint height, GLint depth,
- GLenum format,
- GLsizei imageSize, const GLvoid *data,
- struct gl_texture_object *texObj,
- struct gl_texture_image *texImage)
-{
- assert(0);
-}
-
-
-
-/**
- * Do a CopyTexSubImage operation using a read transfer from the source,
- * a write transfer to the destination and get_tile()/put_tile() to access
- * the pixels/texels.
- *
- * Note: srcY=0=TOP of renderbuffer
- */
-static void
-fallback_copy_texsubimage(struct gl_context *ctx, GLenum target, GLint level,
- struct st_renderbuffer *strb,
- struct st_texture_image *stImage,
- GLenum baseFormat,
- GLint destX, GLint destY, GLint destZ,
- GLint srcX, GLint srcY,
- GLsizei width, GLsizei height)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_transfer *src_trans;
- GLvoid *texDest;
- enum pipe_transfer_usage transfer_usage;
-
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s: fallback processing\n", __FUNCTION__);
-
- assert(width <= MAX_WIDTH);
-
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- srcY = strb->Base.Height - srcY - height;
- }
-
- src_trans = pipe_get_transfer(pipe,
- strb->texture,
- strb->rtt_level,
- strb->rtt_face + strb->rtt_slice,
- PIPE_TRANSFER_READ,
- srcX, srcY,
- width, height);
-
- if ((baseFormat == GL_DEPTH_COMPONENT ||
- baseFormat == GL_DEPTH_STENCIL) &&
- util_format_is_depth_and_stencil(stImage->pt->format))
- transfer_usage = PIPE_TRANSFER_READ_WRITE;
- else
- transfer_usage = PIPE_TRANSFER_WRITE;
-
- /* XXX this used to ignore destZ param */
- texDest = st_texture_image_map(st, stImage, destZ, transfer_usage,
- destX, destY, width, height);
-
- if (baseFormat == GL_DEPTH_COMPONENT ||
- baseFormat == GL_DEPTH_STENCIL) {
- const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F ||
- ctx->Pixel.DepthBias != 0.0F);
- GLint row, yStep;
-
- /* determine bottom-to-top vs. top-to-bottom order for src buffer */
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- srcY = height - 1;
- yStep = -1;
- }
- else {
- srcY = 0;
- yStep = 1;
- }
-
- /* To avoid a large temp memory allocation, do copy row by row */
- for (row = 0; row < height; row++, srcY += yStep) {
- uint data[MAX_WIDTH];
- pipe_get_tile_z(pipe, src_trans, 0, srcY, width, 1, data);
- if (scaleOrBias) {
- _mesa_scale_and_bias_depth_uint(ctx, width, data);
- }
- pipe_put_tile_z(pipe, stImage->transfer, 0, row, width, 1, data);
- }
- }
- else {
- /* RGBA format */
- GLfloat *tempSrc =
- (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
-
- if (tempSrc && texDest) {
- const GLint dims = 2;
- const GLint dstRowStride = stImage->transfer->stride;
- struct gl_texture_image *texImage = &stImage->base;
- struct gl_pixelstore_attrib unpack = ctx->DefaultPacking;
-
- if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
- unpack.Invert = GL_TRUE;
- }
-
- /* get float/RGBA image from framebuffer */
- /* XXX this usually involves a lot of int/float conversion.
- * try to avoid that someday.
- */
- pipe_get_tile_rgba_format(pipe, src_trans, 0, 0, width, height,
- util_format_linear(strb->texture->format),
- tempSrc);
-
- /* Store into texture memory.
- * Note that this does some special things such as pixel transfer
- * ops and format conversion. In particular, if the dest tex format
- * is actually RGBA but the user created the texture as GL_RGB we
- * need to fill-in/override the alpha channel with 1.0.
- */
- _mesa_texstore(ctx, dims,
- texImage->_BaseFormat,
- texImage->TexFormat,
- texDest,
- 0, 0, 0,
- dstRowStride,
- texImage->ImageOffsets,
- width, height, 1,
- GL_RGBA, GL_FLOAT, tempSrc, /* src */
- &unpack);
- }
- else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage");
- }
-
- if (tempSrc)
- free(tempSrc);
- }
-
- st_texture_image_unmap(st, stImage);
- pipe->transfer_destroy(pipe, src_trans);
-}
-
-
-
-/**
- * If the format of the src renderbuffer and the format of the dest
- * texture are compatible (in terms of blitting), return a TGSI writemask
- * to be used during the blit.
- * If the src/dest are incompatible, return 0.
- */
-static unsigned
-compatible_src_dst_formats(struct gl_context *ctx,
- const struct gl_renderbuffer *src,
- const struct gl_texture_image *dst)
-{
- /* Get logical base formats for the src and dest.
- * That is, use the user-requested formats and not the actual, device-
- * chosen formats.
- * For example, the user may have requested an A8 texture but the
- * driver may actually be using an RGBA texture format. When we
- * copy/blit to that texture, we only want to copy the Alpha channel
- * and not the RGB channels.
- *
- * Similarly, when the src FBO was created an RGB format may have been
- * requested but the driver actually chose an RGBA format. In that case,
- * we don't want to copy the undefined Alpha channel to the dest texture
- * (it should be 1.0).
- */
- const GLenum srcFormat = _mesa_base_fbo_format(ctx, src->InternalFormat);
- const GLenum dstFormat = _mesa_base_tex_format(ctx, dst->InternalFormat);
-
- /**
- * XXX when we have red-only and red/green renderbuffers we'll need
- * to add more cases here (or implement a general-purpose routine that
- * queries the existance of the R,G,B,A channels in the src and dest).
- */
- if (srcFormat == dstFormat) {
- /* This is the same as matching_base_formats, which should
- * always pass, as it did previously.
- */
- return TGSI_WRITEMASK_XYZW;
- }
- else if (srcFormat == GL_RGB && dstFormat == GL_RGBA) {
- /* Make sure that A in the dest is 1. The actual src format
- * may be RGBA and have undefined A values.
- */
- return TGSI_WRITEMASK_XYZ;
- }
- else if (srcFormat == GL_RGBA && dstFormat == GL_RGB) {
- /* Make sure that A in the dest is 1. The actual dst format
- * may be RGBA and will need A=1 to provide proper alpha values
- * when sampled later.
- */
- return TGSI_WRITEMASK_XYZ;
- }
- else {
- if (ST_DEBUG & DEBUG_FALLBACK)
- debug_printf("%s failed for src %s, dst %s\n",
- __FUNCTION__,
- _mesa_lookup_enum_by_nr(srcFormat),
- _mesa_lookup_enum_by_nr(dstFormat));
-
- /* Otherwise fail.
- */
- return 0;
- }
-}
-
-
-
-/**
- * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible.
- * Note that the region to copy has already been clipped so we know we
- * won't read from outside the source renderbuffer's bounds.
- *
- * Note: srcY=0=Bottom of renderbuffer (GL convention)
- */
-static void
-st_copy_texsubimage(struct gl_context *ctx,
- GLenum target, GLint level,
- GLint destX, GLint destY, GLint destZ,
- GLint srcX, GLint srcY,
- GLsizei width, GLsizei height)
-{
- struct gl_texture_unit *texUnit =
- &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
- struct gl_texture_object *texObj =
- _mesa_select_tex_object(ctx, texUnit, target);
- struct gl_texture_image *texImage =
- _mesa_select_tex_image(ctx, texObj, target, level);
- struct st_texture_image *stImage = st_texture_image(texImage);
- const GLenum texBaseFormat = texImage->_BaseFormat;
- struct gl_framebuffer *fb = ctx->ReadBuffer;
- struct st_renderbuffer *strb;
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_screen *screen = pipe->screen;
- enum pipe_format dest_format, src_format;
- GLboolean use_fallback = GL_TRUE;
- GLboolean matching_base_formats;
- GLuint format_writemask, sample_count;
- struct pipe_surface *dest_surface = NULL;
- GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP);
-
- /* make sure finalize_textures has been called?
- */
- if (0) st_validate_state(st);
-
- /* determine if copying depth or color data */
- if (texBaseFormat == GL_DEPTH_COMPONENT ||
- texBaseFormat == GL_DEPTH_STENCIL) {
- strb = st_renderbuffer(fb->_DepthBuffer);
- if (strb->Base.Wrapped) {
- strb = st_renderbuffer(strb->Base.Wrapped);
- }
- }
- else {
- /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */
- strb = st_renderbuffer(fb->_ColorReadBuffer);
- }
-
- if (!strb || !strb->surface || !stImage->pt) {
- debug_printf("%s: null strb or stImage\n", __FUNCTION__);
- return;
- }
-
- sample_count = strb->surface->texture->nr_samples;
- /* I believe this would be legal, presumably would need to do a resolve
- for color, and for depth/stencil spec says to just use one of the
- depth/stencil samples per pixel? Need some transfer clarifications. */
- assert(sample_count < 2);
-
- assert(strb);
- assert(strb->surface);
- assert(stImage->pt);
-
- src_format = strb->surface->format;
- dest_format = stImage->pt->format;
-
- /*
- * Determine if the src framebuffer and dest texture have the same
- * base format. We need this to detect a case such as the framebuffer
- * being GL_RGBA but the texture being GL_RGB. If the actual hardware
- * texture format stores RGBA we need to set A=1 (overriding the
- * framebuffer's alpha values). We can't do that with the blit or
- * textured-quad paths.
- */
- matching_base_formats =
- (_mesa_get_format_base_format(strb->Base.Format) ==
- _mesa_get_format_base_format(texImage->TexFormat));
- format_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage);
-
- if (ctx->_ImageTransferState == 0x0) {
-
- if (matching_base_formats &&
- src_format == dest_format &&
- !do_flip)
- {
- /* use surface_copy() / blit */
- struct pipe_box src_box;
- u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer,
- width, height, &src_box);
-
- /* for resource_copy_region(), y=0=top, always */
- pipe->resource_copy_region(pipe,
- /* dest */
- stImage->pt,
- stImage->base.Level,
- destX, destY, destZ + stImage->base.Face,
- /* src */
- strb->texture,
- strb->surface->u.tex.level,
- &src_box);
- use_fallback = GL_FALSE;
- }
- else if (format_writemask &&
- texBaseFormat != GL_DEPTH_COMPONENT &&
- texBaseFormat != GL_DEPTH_STENCIL &&
- screen->is_format_supported(screen, src_format,
- PIPE_TEXTURE_2D, sample_count,
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, dest_format,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET)) {
- /* draw textured quad to do the copy */
- GLint srcY0, srcY1;
- struct pipe_surface surf_tmpl;
- memset(&surf_tmpl, 0, sizeof(surf_tmpl));
- surf_tmpl.format = util_format_linear(stImage->pt->format);
- surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
- surf_tmpl.u.tex.level = stImage->base.Level;
- surf_tmpl.u.tex.first_layer = stImage->base.Face + destZ;
- surf_tmpl.u.tex.last_layer = stImage->base.Face + destZ;
-
- dest_surface = pipe->create_surface(pipe, stImage->pt,
- &surf_tmpl);
-
- if (do_flip) {
- srcY1 = strb->Base.Height - srcY - height;
- srcY0 = srcY1 + height;
- }
- else {
- srcY0 = srcY;
- srcY1 = srcY0 + height;
- }
-
- /* Disable conditional rendering. */
- if (st->render_condition) {
- pipe->render_condition(pipe, NULL, 0);
- }
-
- util_blit_pixels_writemask(st->blit,
- strb->texture,
- strb->surface->u.tex.level,
- srcX, srcY0,
- srcX + width, srcY1,
- strb->surface->u.tex.first_layer,
- dest_surface,
- destX, destY,
- destX + width, destY + height,
- 0.0, PIPE_TEX_MIPFILTER_NEAREST,
- format_writemask);
-
- /* Restore conditional rendering state. */
- if (st->render_condition) {
- pipe->render_condition(pipe, st->render_condition,
- st->condition_mode);
- }
-
- use_fallback = GL_FALSE;
- }
-
- if (dest_surface)
- pipe_surface_reference(&dest_surface, NULL);
- }
-
- if (use_fallback) {
- /* software fallback */
- fallback_copy_texsubimage(ctx, target, level,
- strb, stImage, texBaseFormat,
- destX, destY, destZ,
- srcX, srcY, width, height);
- }
-}
-
-
-
-static void
-st_CopyTexSubImage1D(struct gl_context * ctx, GLenum target, GLint level,
- GLint xoffset, GLint x, GLint y, GLsizei width)
-{
- const GLint yoffset = 0, zoffset = 0;
- const GLsizei height = 1;
- st_copy_texsubimage(ctx, target, level,
- xoffset, yoffset, zoffset, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-static void
-st_CopyTexSubImage2D(struct gl_context * ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset,
- GLint x, GLint y, GLsizei width, GLsizei height)
-{
- const GLint zoffset = 0;
- st_copy_texsubimage(ctx, target, level,
- xoffset, yoffset, zoffset, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-static void
-st_CopyTexSubImage3D(struct gl_context * ctx, GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y, GLsizei width, GLsizei height)
-{
- st_copy_texsubimage(ctx, target, level,
- xoffset, yoffset, zoffset, /* destX,Y,Z */
- x, y, width, height); /* src X, Y, size */
-}
-
-
-/**
- * Copy image data from stImage into the texture object 'stObj' at level
- * 'dstLevel'.
- */
-static void
-copy_image_data_to_texture(struct st_context *st,
- struct st_texture_object *stObj,
- GLuint dstLevel,
- struct st_texture_image *stImage)
-{
- /* debug checks */
- {
- const struct gl_texture_image *dstImage =
- stObj->base.Image[stImage->base.Face][dstLevel];
- assert(dstImage);
- assert(dstImage->Width == stImage->base.Width);
- assert(dstImage->Height == stImage->base.Height);
- assert(dstImage->Depth == stImage->base.Depth);
- }
-
- if (stImage->pt) {
- /* Copy potentially with the blitter:
- */
- st_texture_image_copy(st->pipe,
- stObj->pt, dstLevel, /* dest texture, level */
- stImage->pt, stImage->base.Level, /* src texture, level */
- stImage->base.Face);
-
- pipe_resource_reference(&stImage->pt, NULL);
- }
- else if (stImage->base.Data) {
- st_texture_image_data(st,
- stObj->pt,
- stImage->base.Face,
- dstLevel,
- stImage->base.Data,
- stImage->base.RowStride *
- util_format_get_blocksize(stObj->pt->format),
- stImage->base.RowStride *
- stImage->base.Height *
- util_format_get_blocksize(stObj->pt->format));
- _mesa_align_free(stImage->base.Data);
- stImage->base.Data = NULL;
- }
-
- pipe_resource_reference(&stImage->pt, stObj->pt);
-}
-
-
-/**
- * Called during state validation. When this function is finished,
- * the texture object should be ready for rendering.
- * \return GL_TRUE for success, GL_FALSE for failure (out of mem)
- */
-GLboolean
-st_finalize_texture(struct gl_context *ctx,
- struct pipe_context *pipe,
- struct gl_texture_object *tObj)
-{
- struct st_context *st = st_context(ctx);
- struct st_texture_object *stObj = st_texture_object(tObj);
- const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
- GLuint face;
- struct st_texture_image *firstImage;
- enum pipe_format firstImageFormat;
- GLuint ptWidth, ptHeight, ptDepth, ptLayers;
-
- if (stObj->base._Complete) {
- /* The texture is complete and we know exactly how many mipmap levels
- * are present/needed. This is conditional because we may be called
- * from the st_generate_mipmap() function when the texture object is
- * incomplete. In that case, we'll have set stObj->lastLevel before
- * we get here.
- */
- if (stObj->base.Sampler.MinFilter == GL_LINEAR ||
- stObj->base.Sampler.MinFilter == GL_NEAREST)
- stObj->lastLevel = stObj->base.BaseLevel;
- else
- stObj->lastLevel = stObj->base._MaxLevel;
- }
-
- firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]);
- assert(firstImage);
-
- /* If both firstImage and stObj point to a texture which can contain
- * all active images, favour firstImage. Note that because of the
- * completeness requirement, we know that the image dimensions
- * will match.
- */
- if (firstImage->pt &&
- firstImage->pt != stObj->pt &&
- (!stObj->pt || firstImage->pt->last_level >= stObj->pt->last_level)) {
- pipe_resource_reference(&stObj->pt, firstImage->pt);
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- }
-
- /* Find gallium format for the Mesa texture */
- firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat);
-
- /* Find size of level=0 Gallium mipmap image, plus number of texture layers */
- {
- GLuint width, height, depth;
- if (!guess_base_level_size(stObj->base.Target,
- firstImage->base.Width2,
- firstImage->base.Height2,
- firstImage->base.Depth2,
- stObj->base.BaseLevel,
- &width, &height, &depth)) {
- width = stObj->width0;
- height = stObj->height0;
- depth = stObj->depth0;
- }
- /* convert GL dims to Gallium dims */
- st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth,
- &ptWidth, &ptHeight, &ptDepth, &ptLayers);
- }
-
- /* If we already have a gallium texture, check that it matches the texture
- * object's format, target, size, num_levels, etc.
- */
- if (stObj->pt) {
- if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) ||
- !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) ||
- stObj->pt->last_level < stObj->lastLevel ||
- stObj->pt->width0 != ptWidth ||
- stObj->pt->height0 != ptHeight ||
- stObj->pt->depth0 != ptDepth ||
- stObj->pt->array_size != ptLayers)
- {
- /* The gallium texture does not match the Mesa texture so delete the
- * gallium texture now. We'll make a new one below.
- */
- pipe_resource_reference(&stObj->pt, NULL);
- pipe_sampler_view_reference(&stObj->sampler_view, NULL);
- st->dirty.st |= ST_NEW_FRAMEBUFFER;
- }
- }
-
- /* May need to create a new gallium texture:
- */
- if (!stObj->pt) {
- GLuint bindings = default_bindings(st, firstImageFormat);
-
- stObj->pt = st_texture_create(st,
- gl_target_to_pipe(stObj->base.Target),
- firstImageFormat,
- stObj->lastLevel,
- ptWidth,
- ptHeight,
- ptDepth,
- ptLayers,
- bindings);
-
- if (!stObj->pt) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage");
- return GL_FALSE;
- }
- }
-
- /* Pull in any images not in the object's texture:
- */
- for (face = 0; face < nr_faces; face++) {
- GLuint level;
- for (level = stObj->base.BaseLevel; level <= stObj->lastLevel; level++) {
- struct st_texture_image *stImage =
- st_texture_image(stObj->base.Image[face][level]);
-
- /* Need to import images in main memory or held in other textures.
- */
- if (stImage && stObj->pt != stImage->pt) {
- if (level == 0 || (stImage->base.Width == u_minify(stObj->width0, level) &&
- stImage->base.Height == u_minify(stObj->height0, level) &&
- stImage->base.Depth == u_minify(stObj->depth0, level))) {
- /* src image fits expected dest mipmap level size */
- copy_image_data_to_texture(st, stObj, level, stImage);
- }
- }
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Returns pointer to a default/dummy texture.
- * This is typically used when the current shader has tex/sample instructions
- * but the user has not provided a (any) texture(s).
- */
-struct gl_texture_object *
-st_get_default_texture(struct st_context *st)
-{
- if (!st->default_texture) {
- static const GLenum target = GL_TEXTURE_2D;
- GLubyte pixels[16][16][4];
- struct gl_texture_object *texObj;
- struct gl_texture_image *texImg;
- GLuint i, j;
-
- /* The ARB_fragment_program spec says (0,0,0,1) should be returned
- * when attempting to sample incomplete textures.
- */
- for (i = 0; i < 16; i++) {
- for (j = 0; j < 16; j++) {
- pixels[i][j][0] = 0;
- pixels[i][j][1] = 0;
- pixels[i][j][2] = 0;
- pixels[i][j][3] = 255;
- }
- }
-
- texObj = st->ctx->Driver.NewTextureObject(st->ctx, 0, target);
-
- texImg = _mesa_get_tex_image(st->ctx, texObj, target, 0);
-
- _mesa_init_teximage_fields(st->ctx, target, texImg,
- 16, 16, 1, 0, /* w, h, d, border */
- GL_RGBA, MESA_FORMAT_RGBA8888);
-
- st_TexImage(st->ctx, 2, target,
- 0, GL_RGBA, /* level, intformat */
- 16, 16, 1, 0, /* w, h, d, border */
- GL_RGBA, GL_UNSIGNED_BYTE, pixels,
- &st->ctx->DefaultPacking,
- texObj, texImg,
- 0, 0);
-
- texObj->Sampler.MinFilter = GL_NEAREST;
- texObj->Sampler.MagFilter = GL_NEAREST;
- texObj->_Complete = GL_TRUE;
-
- st->default_texture = texObj;
- }
- return st->default_texture;
-}
-
-
-void
-st_init_texture_functions(struct dd_function_table *functions)
-{
- functions->ChooseTextureFormat = st_ChooseTextureFormat;
- functions->TexImage1D = st_TexImage1D;
- functions->TexImage2D = st_TexImage2D;
- functions->TexImage3D = st_TexImage3D;
- functions->TexSubImage1D = st_TexSubImage1D;
- functions->TexSubImage2D = st_TexSubImage2D;
- functions->TexSubImage3D = st_TexSubImage3D;
- functions->CompressedTexSubImage1D = st_CompressedTexSubImage1D;
- functions->CompressedTexSubImage2D = st_CompressedTexSubImage2D;
- functions->CompressedTexSubImage3D = st_CompressedTexSubImage3D;
- functions->CopyTexSubImage1D = st_CopyTexSubImage1D;
- functions->CopyTexSubImage2D = st_CopyTexSubImage2D;
- functions->CopyTexSubImage3D = st_CopyTexSubImage3D;
- functions->GenerateMipmap = st_generate_mipmap;
-
- functions->GetTexImage = st_GetTexImage;
-
- /* compressed texture functions */
- functions->CompressedTexImage2D = st_CompressedTexImage2D;
- functions->GetCompressedTexImage = st_GetCompressedTexImage;
-
- functions->NewTextureObject = st_NewTextureObject;
- functions->NewTextureImage = st_NewTextureImage;
- functions->DeleteTexture = st_DeleteTextureObject;
- functions->FreeTextureImageBuffer = st_FreeTextureImageBuffer;
- functions->MapTextureImage = st_MapTextureImage;
- functions->UnmapTextureImage = st_UnmapTextureImage;
-
- functions->TextureMemCpy = do_memcpy;
-
- /* XXX Temporary until we can query pipe's texture sizes */
- functions->TestProxyTexImage = _mesa_test_proxy_teximage;
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + +#include "main/mfeatures.h" +#include "main/bufferobj.h" +#include "main/enums.h" +#include "main/fbobject.h" +#include "main/formats.h" +#include "main/image.h" +#include "main/imports.h" +#include "main/macros.h" +#include "main/mipmap.h" +#include "main/pack.h" +#include "main/pbo.h" +#include "main/pixeltransfer.h" +#include "main/texcompress.h" +#include "main/texfetch.h" +#include "main/texgetimage.h" +#include "main/teximage.h" +#include "main/texobj.h" +#include "main/texstore.h" + +#include "state_tracker/st_debug.h" +#include "state_tracker/st_context.h" +#include "state_tracker/st_cb_fbo.h" +#include "state_tracker/st_cb_flush.h" +#include "state_tracker/st_cb_texture.h" +#include "state_tracker/st_format.h" +#include "state_tracker/st_texture.h" +#include "state_tracker/st_gen_mipmap.h" +#include "state_tracker/st_atom.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" +#include "pipe/p_shader_tokens.h" +#include "util/u_tile.h" +#include "util/u_blit.h" +#include "util/u_format.h" +#include "util/u_surface.h" +#include "util/u_sampler.h" +#include "util/u_math.h" +#include "util/u_box.h" + +#define DBG if (0) printf + + +static enum pipe_texture_target +gl_target_to_pipe(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + return PIPE_TEXTURE_1D; + case GL_TEXTURE_2D: + return PIPE_TEXTURE_2D; + case GL_TEXTURE_RECTANGLE_NV: + return PIPE_TEXTURE_RECT; + case GL_TEXTURE_3D: + return PIPE_TEXTURE_3D; + case GL_TEXTURE_CUBE_MAP_ARB: + return PIPE_TEXTURE_CUBE; + case GL_TEXTURE_1D_ARRAY_EXT: + return PIPE_TEXTURE_1D_ARRAY; + case GL_TEXTURE_2D_ARRAY_EXT: + return PIPE_TEXTURE_2D_ARRAY; + case GL_TEXTURE_BUFFER: + return PIPE_BUFFER; + default: + assert(0); + return 0; + } +} + + +/** called via ctx->Driver.NewTextureImage() */ +static struct gl_texture_image * +st_NewTextureImage(struct gl_context * ctx) +{ + DBG("%s\n", __FUNCTION__); + (void) ctx; + return (struct gl_texture_image *) ST_CALLOC_STRUCT(st_texture_image); +} + + +/** called via ctx->Driver.NewTextureObject() */ +static struct gl_texture_object * +st_NewTextureObject(struct gl_context * ctx, GLuint name, GLenum target) +{ + struct st_texture_object *obj = ST_CALLOC_STRUCT(st_texture_object); + + DBG("%s\n", __FUNCTION__); + _mesa_initialize_texture_object(&obj->base, name, target); + + return &obj->base; +} + +/** called via ctx->Driver.DeleteTextureObject() */ +static void +st_DeleteTextureObject(struct gl_context *ctx, + struct gl_texture_object *texObj) +{ + struct st_context *st = st_context(ctx); + struct st_texture_object *stObj = st_texture_object(texObj); + if (stObj->pt) + pipe_resource_reference(&stObj->pt, NULL); + if (stObj->sampler_view) { + if (stObj->sampler_view->context != st->pipe) { + /* Take "ownership" of this texture sampler view by setting + * its context pointer to this context. This avoids potential + * crashes when the texture object is shared among contexts + * and the original/owner context has already been destroyed. + */ + stObj->sampler_view->context = st->pipe; + } + pipe_sampler_view_reference(&stObj->sampler_view, NULL); + } + _mesa_delete_texture_object(ctx, texObj); +} + + +/** called via ctx->Driver.FreeTextureImageBuffer() */ +static void +st_FreeTextureImageBuffer(struct gl_context * ctx, struct gl_texture_image *texImage) +{ + struct st_texture_image *stImage = st_texture_image(texImage); + + DBG("%s\n", __FUNCTION__); + + if (stImage->pt) { + pipe_resource_reference(&stImage->pt, NULL); + } + + if (texImage->Data) { + _mesa_align_free(texImage->Data); + texImage->Data = NULL; + } +} + + +/** called via ctx->Driver.MapTextureImage() */ +static void +st_MapTextureImage(struct gl_context *ctx, + struct gl_texture_image *texImage, + GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h, + GLbitfield mode, + GLubyte **mapOut, GLint *rowStrideOut) +{ + struct st_context *st = st_context(ctx); + struct st_texture_image *stImage = st_texture_image(texImage); + unsigned pipeMode; + GLubyte *map; + + pipeMode = 0x0; + if (mode & GL_MAP_READ_BIT) + pipeMode |= PIPE_TRANSFER_READ; + if (mode & GL_MAP_WRITE_BIT) + pipeMode |= PIPE_TRANSFER_WRITE; + + map = st_texture_image_map(st, stImage, slice, pipeMode, x, y, w, h); + if (map) { + *mapOut = map; + *rowStrideOut = stImage->transfer->stride; + } + else { + *mapOut = NULL; + *rowStrideOut = 0; + } +} + + +/** called via ctx->Driver.UnmapTextureImage() */ +static void +st_UnmapTextureImage(struct gl_context *ctx, + struct gl_texture_image *texImage, + GLuint slice) +{ + struct st_context *st = st_context(ctx); + struct st_texture_image *stImage = st_texture_image(texImage); + st_texture_image_unmap(st, stImage); +} + + +/** + * From linux kernel i386 header files, copes with odd sizes better + * than COPY_DWORDS would: + * XXX Put this in src/mesa/main/imports.h ??? + */ +#if defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86) +static INLINE void * +__memcpy(void *to, const void *from, size_t n) +{ + int d0, d1, d2; + __asm__ __volatile__("rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" "2:":"=&c"(d0), "=&D"(d1), "=&S"(d2) + :"0"(n / 4), "q"(n), "1"((long) to), "2"((long) from) + :"memory"); + return (to); +} +#else +#define __memcpy(a,b,c) memcpy(a,b,c) +#endif + + +/** + * The system memcpy (at least on ubuntu 5.10) has problems copying + * to agp (writecombined) memory from a source which isn't 64-byte + * aligned - there is a 4x performance falloff. + * + * The x86 __memcpy is immune to this but is slightly slower + * (10%-ish) than the system memcpy. + * + * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but + * isn't much faster than x86_memcpy for agp copies. + * + * TODO: switch dynamically. + */ +static void * +do_memcpy(void *dest, const void *src, size_t n) +{ + if ((((unsigned long) src) & 63) || (((unsigned long) dest) & 63)) { + return __memcpy(dest, src, n); + } + else + return memcpy(dest, src, n); +} + + +/** + * Return default texture resource binding bitmask for the given format. + */ +static GLuint +default_bindings(struct st_context *st, enum pipe_format format) +{ + struct pipe_screen *screen = st->pipe->screen; + const unsigned target = PIPE_TEXTURE_2D; + unsigned bindings; + + if (util_format_is_depth_or_stencil(format)) + bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL; + else + bindings = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; + + if (screen->is_format_supported(screen, format, target, 0, bindings)) + return bindings; + else { + /* Try non-sRGB. */ + format = util_format_linear(format); + + if (screen->is_format_supported(screen, format, target, 0, bindings)) + return bindings; + else + return PIPE_BIND_SAMPLER_VIEW; + } +} + + +/** Return number of image dimensions (1, 2 or 3) for a texture target. */ +static GLuint +get_texture_dims(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_BUFFER: + return 1; + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: + case GL_TEXTURE_RECTANGLE_NV: + case GL_TEXTURE_2D_ARRAY_EXT: + return 2; + case GL_TEXTURE_3D: + return 3; + default: + assert(0 && "invalid texture target in get_texture_dims()"); + return 1; + } +} + + +/** + * Given the size of a mipmap image, try to compute the size of the level=0 + * mipmap image. + * + * Note that this isn't always accurate for odd-sized, non-POW textures. + * For example, if level=1 and width=40 then the level=0 width may be 80 or 81. + * + * \return GL_TRUE for success, GL_FALSE for failure + */ +static GLboolean +guess_base_level_size(GLenum target, + GLuint width, GLuint height, GLuint depth, GLuint level, + GLuint *width0, GLuint *height0, GLuint *depth0) +{ + const GLuint dims = get_texture_dims(target); + + assert(width >= 1); + assert(height >= 1); + assert(depth >= 1); + + if (level > 0) { + /* Depending on the image's size, we can't always make a guess here */ + if ((dims >= 1 && width == 1) || + (dims >= 2 && height == 1) || + (dims >= 3 && depth == 1)) { + /* we can't determine the image size at level=0 */ + return GL_FALSE; + } + + /* grow the image size until we hit level = 0 */ + while (level > 0) { + if (width > 1) + width <<= 1; + if (height > 1) + height <<= 1; + if (depth > 1) + depth <<= 1; + level--; + } + } + + *width0 = width; + *height0 = height; + *depth0 = depth; + + return GL_TRUE; +} + + +/** + * Try to allocate a pipe_resource object for the given st_texture_object. + * + * We use the given st_texture_image as a clue to determine the size of the + * mipmap image at level=0. + * + * \return GL_TRUE for success, GL_FALSE if out of memory. + */ +static GLboolean +guess_and_alloc_texture(struct st_context *st, + struct st_texture_object *stObj, + const struct st_texture_image *stImage) +{ + GLuint lastLevel, width, height, depth; + GLuint bindings; + GLuint ptWidth, ptHeight, ptDepth, ptLayers; + enum pipe_format fmt; + + DBG("%s\n", __FUNCTION__); + + assert(!stObj->pt); + + if (!guess_base_level_size(stObj->base.Target, + stImage->base.Width2, + stImage->base.Height2, + stImage->base.Depth2, + stImage->base.Level, + &width, &height, &depth)) { + /* we can't determine the image size at level=0 */ + stObj->width0 = stObj->height0 = stObj->depth0 = 0; + /* this is not an out of memory error */ + return GL_TRUE; + } + + /* At this point, (width x height x depth) is the expected size of + * the level=0 mipmap image. + */ + + /* Guess a reasonable value for lastLevel. With OpenGL we have no + * idea how many mipmap levels will be in a texture until we start + * to render with it. Make an educated guess here but be prepared + * to re-allocating a texture buffer with space for more (or fewer) + * mipmap levels later. + */ + if ((stObj->base.Sampler.MinFilter == GL_NEAREST || + stObj->base.Sampler.MinFilter == GL_LINEAR || + stImage->base._BaseFormat == GL_DEPTH_COMPONENT || + stImage->base._BaseFormat == GL_DEPTH_STENCIL_EXT) && + !stObj->base.GenerateMipmap && + stImage->base.Level == 0) { + /* only alloc space for a single mipmap level */ + lastLevel = 0; + } + else { + /* alloc space for a full mipmap */ + GLuint l2width = util_logbase2(width); + GLuint l2height = util_logbase2(height); + GLuint l2depth = util_logbase2(depth); + lastLevel = MAX2(MAX2(l2width, l2height), l2depth); + } + + /* Save the level=0 dimensions */ + stObj->width0 = width; + stObj->height0 = height; + stObj->depth0 = depth; + + fmt = st_mesa_format_to_pipe_format(stImage->base.TexFormat); + + bindings = default_bindings(st, fmt); + + st_gl_texture_dims_to_pipe_dims(stObj->base.Target, + width, height, depth, + &ptWidth, &ptHeight, &ptDepth, &ptLayers); + + stObj->pt = st_texture_create(st, + gl_target_to_pipe(stObj->base.Target), + fmt, + lastLevel, + ptWidth, + ptHeight, + ptDepth, + ptLayers, + bindings); + + DBG("%s returning %d\n", __FUNCTION__, (stObj->pt != NULL)); + + return stObj->pt != NULL; +} + + +/** + * Adjust pixel unpack params and image dimensions to strip off the + * texture border. + * Gallium doesn't support texture borders. They've seldem been used + * and seldom been implemented correctly anyway. + * \param unpackNew returns the new pixel unpack parameters + */ +static void +strip_texture_border(GLint border, + GLint *width, GLint *height, GLint *depth, + const struct gl_pixelstore_attrib *unpack, + struct gl_pixelstore_attrib *unpackNew) +{ + assert(border > 0); /* sanity check */ + + *unpackNew = *unpack; + + if (unpackNew->RowLength == 0) + unpackNew->RowLength = *width; + + if (depth && unpackNew->ImageHeight == 0) + unpackNew->ImageHeight = *height; + + unpackNew->SkipPixels += border; + if (height) + unpackNew->SkipRows += border; + if (depth) + unpackNew->SkipImages += border; + + assert(*width >= 3); + *width = *width - 2 * border; + if (height && *height >= 3) + *height = *height - 2 * border; + if (depth && *depth >= 3) + *depth = *depth - 2 * border; +} + + +/** + * Do glTexImage1/2/3D(). + */ +static void +st_TexImage(struct gl_context * ctx, + GLint dims, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint depth, + GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, + GLsizei imageSize, GLboolean compressed_src) +{ + struct st_context *st = st_context(ctx); + struct st_texture_object *stObj = st_texture_object(texObj); + struct st_texture_image *stImage = st_texture_image(texImage); + GLuint dstRowStride = 0; + struct gl_pixelstore_attrib unpackNB; + enum pipe_transfer_usage transfer_usage = 0; + + DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(target), level, width, height, depth, border); + + /* switch to "normal" */ + if (stObj->surface_based) { + gl_format texFormat; + + _mesa_clear_texture_object(ctx, texObj); + pipe_resource_reference(&stObj->pt, NULL); + + /* oops, need to init this image again */ + texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, + internalFormat, format, type); + + _mesa_init_teximage_fields(ctx, target, texImage, + width, height, depth, border, + internalFormat, texFormat); + + stObj->surface_based = GL_FALSE; + } + + /* gallium does not support texture borders, strip it off */ + if (border) { + strip_texture_border(border, &width, &height, &depth, unpack, &unpackNB); + unpack = &unpackNB; + texImage->Width = width; + texImage->Height = height; + texImage->Depth = depth; + texImage->Border = 0; + border = 0; + } + else { + assert(texImage->Width == width); + assert(texImage->Height == height); + assert(texImage->Depth == depth); + } + + stImage->base.Face = _mesa_tex_target_to_face(target); + stImage->base.Level = level; + + _mesa_set_fetch_functions(texImage, dims); + + /* Release the reference to a potentially orphaned buffer. + * Release any old malloced memory. + */ + if (stImage->pt) { + pipe_resource_reference(&stImage->pt, NULL); + assert(!texImage->Data); + } + else if (texImage->Data) { + _mesa_align_free(texImage->Data); + } + + /* + * See if the new image is somehow incompatible with the existing + * mipmap. If so, free the old mipmap. + */ + if (stObj->pt) { + if (level > (GLint) stObj->pt->last_level || + !st_texture_match_image(stObj->pt, &stImage->base, + stImage->base.Face, stImage->base.Level)) { + DBG("release it\n"); + pipe_resource_reference(&stObj->pt, NULL); + assert(!stObj->pt); + pipe_sampler_view_reference(&stObj->sampler_view, NULL); + } + } + + if (width == 0 || height == 0 || depth == 0) { + /* stop after freeing old image */ + return; + } + + if (!stObj->pt) { + if (!guess_and_alloc_texture(st, stObj, stImage)) { + /* Probably out of memory. + * Try flushing any pending rendering, then retry. + */ + st_finish(st); + if (!guess_and_alloc_texture(st, stObj, stImage)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + return; + } + } + } + + assert(!stImage->pt); + + /* Check if this texture image can live inside the texture object's buffer. + * If so, store the image there. Otherwise the image will temporarily live + * in its own buffer. + */ + if (stObj->pt && + st_texture_match_image(stObj->pt, &stImage->base, + stImage->base.Face, stImage->base.Level)) { + + pipe_resource_reference(&stImage->pt, stObj->pt); + assert(stImage->pt); + } + + if (!stImage->pt) + DBG("XXX: Image did not fit into texture - storing in local memory!\n"); + + /* Pixel data may come from regular user memory or a PBO. For the later, + * do bounds checking and map the PBO to read pixels data from it. + * + * XXX we should try to use a GPU-accelerated path to copy the image data + * from the PBO to the texture. + */ + if (compressed_src) { + pixels = _mesa_validate_pbo_compressed_teximage(ctx, imageSize, pixels, + unpack, + "glCompressedTexImage"); + } + else { + pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1, + format, type, + pixels, unpack, "glTexImage"); + } + + /* for a 1D array upload the image as a series of layer with height = 1 */ + if (target == GL_TEXTURE_1D_ARRAY) { + depth = height; + height = 1; + } + + /* + * Prepare to store the texture data. Either map the gallium texture buffer + * memory or malloc space for it. + */ + if (stImage->pt) { + if (!pixels) { + /* We've allocated texture resource, but have no pixel data - all done. */ + goto done; + } + + /* Store the image in the gallium transfer object */ + if (format == GL_DEPTH_COMPONENT && + util_format_is_depth_and_stencil(stImage->pt->format)) + transfer_usage = PIPE_TRANSFER_READ_WRITE; + else + transfer_usage = PIPE_TRANSFER_WRITE; + + texImage->Data = st_texture_image_map(st, stImage, 0, + transfer_usage, 0, 0, width, height); + if(stImage->transfer) + dstRowStride = stImage->transfer->stride; + } + else { + /* Allocate regular memory and store the image there temporarily. */ + GLuint imageSize = _mesa_format_image_size(texImage->TexFormat, + width, height, depth); + dstRowStride = _mesa_format_row_stride(texImage->TexFormat, width); + + texImage->Data = _mesa_align_malloc(imageSize, 16); + } + + if (!texImage->Data) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + return; + } + + if (!pixels) { + /* We've allocated texture memory, but have no pixel data - all done. */ + goto done; + } + + DBG("Upload image %dx%dx%d row_len %x pitch %x\n", + width, height, depth, width, dstRowStride); + + /* Copy user texture image into the texture buffer. + */ + if (compressed_src) { + const GLuint srcRowStride = + _mesa_format_row_stride(texImage->TexFormat, width); + if (dstRowStride == srcRowStride) { + memcpy(texImage->Data, pixels, imageSize); + } + else { + char *dst = texImage->Data; + const char *src = pixels; + GLuint i, bw, bh, lines; + _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh); + lines = (height + bh - 1) / bh; + + for (i = 0; i < lines; ++i) { + memcpy(dst, src, srcRowStride); + dst += dstRowStride; + src += srcRowStride; + } + } + } + else { + const GLuint srcImageStride = + _mesa_image_image_stride(unpack, width, height, format, type); + GLint i; + const GLubyte *src = (const GLubyte *) pixels; + + for (i = 0; i < depth; i++) { + if (!_mesa_texstore(ctx, dims, + texImage->_BaseFormat, + texImage->TexFormat, + texImage->Data, + 0, 0, 0, /* dstX/Y/Zoffset */ + dstRowStride, + texImage->ImageOffsets, + width, height, 1, + format, type, src, unpack)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + } + + if (stImage->pt && i + 1 < depth) { + /* unmap this slice */ + st_texture_image_unmap(st, stImage); + /* map next slice of 3D texture */ + texImage->Data = st_texture_image_map(st, stImage, i + 1, + transfer_usage, 0, 0, + width, height); + src += srcImageStride; + } + } + } + +done: + _mesa_unmap_teximage_pbo(ctx, unpack); + + if (stImage->pt && texImage->Data) { + st_texture_image_unmap(st, stImage); + texImage->Data = NULL; + } +} + + +static void +st_TexImage3D(struct gl_context * ctx, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint depth, + GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 3, target, level, internalFormat, width, height, depth, + border, format, type, pixels, unpack, texObj, texImage, + 0, GL_FALSE); +} + + +static void +st_TexImage2D(struct gl_context * ctx, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border, + format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE); +} + + +static void +st_TexImage1D(struct gl_context * ctx, + GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *unpack, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 1, target, level, internalFormat, width, 1, 1, border, + format, type, pixels, unpack, texObj, texImage, 0, GL_FALSE); +} + + +static void +st_CompressedTexImage2D(struct gl_context *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLsizei imageSize, const GLvoid *data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexImage(ctx, 2, target, level, internalFormat, width, height, 1, border, + 0, 0, data, &ctx->Unpack, texObj, texImage, imageSize, GL_TRUE); +} + + + +/** + * glGetTexImage() helper: decompress a compressed texture by rendering + * a textured quad. Store the results in the user's buffer. + */ +static void +decompress_with_blit(struct gl_context * ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid *pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct st_texture_image *stImage = st_texture_image(texImage); + struct st_texture_object *stObj = st_texture_object(texObj); + struct pipe_sampler_view *src_view = + st_get_texture_sampler_view(stObj, pipe); + const GLuint width = texImage->Width; + const GLuint height = texImage->Height; + struct pipe_surface *dst_surface; + struct pipe_resource *dst_texture; + struct pipe_transfer *tex_xfer; + unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */ + PIPE_BIND_TRANSFER_READ); + + /* create temp / dest surface */ + if (!util_create_rgba_surface(pipe, width, height, bind, + &dst_texture, &dst_surface)) { + _mesa_problem(ctx, "util_create_rgba_surface() failed " + "in decompress_with_blit()"); + return; + } + + /* Disable conditional rendering. */ + if (st->render_condition) { + pipe->render_condition(pipe, NULL, 0); + } + + /* blit/render/decompress */ + util_blit_pixels_tex(st->blit, + src_view, /* pipe_resource (src) */ + 0, 0, /* src x0, y0 */ + width, height, /* src x1, y1 */ + dst_surface, /* pipe_surface (dst) */ + 0, 0, /* dst x0, y0 */ + width, height, /* dst x1, y1 */ + 0.0, /* z */ + PIPE_TEX_MIPFILTER_NEAREST); + + /* Restore conditional rendering state. */ + if (st->render_condition) { + pipe->render_condition(pipe, st->render_condition, + st->condition_mode); + } + + /* map the dst_surface so we can read from it */ + tex_xfer = pipe_get_transfer(pipe, + dst_texture, 0, 0, + PIPE_TRANSFER_READ, + 0, 0, width, height); + + pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); + + /* copy/pack data into user buffer */ + if (st_equal_formats(stImage->pt->format, format, type)) { + /* memcpy */ + const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); + ubyte *map = pipe_transfer_map(pipe, tex_xfer); + GLuint row; + for (row = 0; row < height; row++) { + GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, + height, format, type, row, 0); + memcpy(dest, map, bytesPerRow); + map += tex_xfer->stride; + } + pipe_transfer_unmap(pipe, tex_xfer); + } + else { + /* format translation via floats */ + GLuint row; + enum pipe_format pformat = util_format_linear(dst_texture->format); + for (row = 0; row < height; row++) { + const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ + GLfloat rgba[4 * MAX_WIDTH]; + GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, + height, format, type, row, 0); + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback format translation\n", __FUNCTION__); + + /* get float[4] rgba row from surface */ + pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1, + pformat, rgba); + + _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, + type, dest, &ctx->Pack, transferOps); + } + } + + _mesa_unmap_pbo_dest(ctx, &ctx->Pack); + + pipe->transfer_destroy(pipe, tex_xfer); + + /* destroy the temp / dest surface */ + util_destroy_rgba_surface(dst_texture, dst_surface); +} + + + +/** + * Need to map texture image into memory before copying image data, + * then unmap it. + */ +static void +st_get_tex_image(struct gl_context * ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid * pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage, GLboolean compressed_dst) +{ + struct st_context *st = st_context(ctx); + struct st_texture_image *stImage = st_texture_image(texImage); + const GLuint dstImageStride = + _mesa_image_image_stride(&ctx->Pack, texImage->Width, texImage->Height, + format, type); + GLuint depth, i; + GLubyte *dest; + + if (stImage->pt && + util_format_is_s3tc(stImage->pt->format) && + !compressed_dst) { + /* Need to decompress the texture. + * We'll do this by rendering a textured quad. + * Note that we only expect RGBA formats (no Z/depth formats). + */ + decompress_with_blit(ctx, target, level, format, type, pixels, + texObj, texImage); + return; + } + + /* Map */ + if (stImage->pt) { + /* Image is stored in hardware format in a buffer managed by the + * kernel. Need to explicitly map and unmap it. + */ + texImage->Data = st_texture_image_map(st, stImage, 0, + PIPE_TRANSFER_READ, 0, 0, + stImage->base.Width, + stImage->base.Height); + /* compute stride in texels from stride in bytes */ + texImage->RowStride = stImage->transfer->stride + * util_format_get_blockwidth(stImage->pt->format) + / util_format_get_blocksize(stImage->pt->format); + } + else { + /* Otherwise, the image should actually be stored in + * texImage->Data. This is pretty confusing for + * everybody, I'd much prefer to separate the two functions of + * texImage->Data - storage for texture images in main memory + * and access (ie mappings) of images. In other words, we'd + * create a new texImage->Map field and leave Data simply for + * storage. + */ + assert(texImage->Data); + } + + depth = texImage->Depth; + texImage->Depth = 1; + + dest = (GLubyte *) pixels; + + _mesa_set_fetch_functions(texImage, get_texture_dims(target)); + + for (i = 0; i < depth; i++) { + if (compressed_dst) { + _mesa_get_compressed_teximage(ctx, target, level, dest, + texObj, texImage); + } + else { + _mesa_get_teximage(ctx, target, level, format, type, dest, + texObj, texImage); + } + + if (stImage->pt && i + 1 < depth) { + /* unmap this slice */ + st_texture_image_unmap(st, stImage); + /* map next slice of 3D texture */ + texImage->Data = st_texture_image_map(st, stImage, i + 1, + PIPE_TRANSFER_READ, 0, 0, + stImage->base.Width, + stImage->base.Height); + dest += dstImageStride; + } + } + + texImage->Depth = depth; + + /* Unmap */ + if (stImage->pt) { + st_texture_image_unmap(st, stImage); + texImage->Data = NULL; + } +} + + +static void +st_GetTexImage(struct gl_context * ctx, GLenum target, GLint level, + GLenum format, GLenum type, GLvoid * pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_get_tex_image(ctx, target, level, format, type, pixels, texObj, texImage, + GL_FALSE); +} + + +static void +st_GetCompressedTexImage(struct gl_context *ctx, GLenum target, GLint level, + GLvoid *pixels, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_get_tex_image(ctx, target, level, 0, 0, pixels, texObj, texImage, + GL_TRUE); +} + + + +static void +st_TexSubimage(struct gl_context *ctx, GLint dims, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint width, GLint height, GLint depth, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + struct st_context *st = st_context(ctx); + struct st_texture_image *stImage = st_texture_image(texImage); + GLuint dstRowStride; + const GLuint srcImageStride = + _mesa_image_image_stride(packing, width, height, format, type); + GLint i; + const GLubyte *src; + /* init to silence warning only: */ + enum pipe_transfer_usage transfer_usage = PIPE_TRANSFER_WRITE; + + DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(target), + level, xoffset, yoffset, width, height); + + pixels = + _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format, + type, pixels, packing, "glTexSubImage2D"); + if (!pixels) + return; + + /* for a 1D array upload the image as a series of layer with height = 1 */ + if (target == GL_TEXTURE_1D_ARRAY) { + depth = height; + height = 1; + } + + /* Map buffer if necessary. Need to lock to prevent other contexts + * from uploading the buffer under us. + */ + if (stImage->pt) { + if (format == GL_DEPTH_COMPONENT && + util_format_is_depth_and_stencil(stImage->pt->format)) + transfer_usage = PIPE_TRANSFER_READ_WRITE; + else + transfer_usage = PIPE_TRANSFER_WRITE; + + texImage->Data = st_texture_image_map(st, stImage, zoffset, + transfer_usage, + xoffset, yoffset, + width, height); + } + + if (!texImage->Data) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); + goto done; + } + + src = (const GLubyte *) pixels; + dstRowStride = stImage->transfer->stride; + + for (i = 0; i < depth; i++) { + if (!_mesa_texstore(ctx, dims, texImage->_BaseFormat, + texImage->TexFormat, + texImage->Data, + 0, 0, 0, + dstRowStride, + texImage->ImageOffsets, + width, height, 1, + format, type, src, packing)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); + } + + if (stImage->pt && i + 1 < depth) { + /* unmap this slice */ + st_texture_image_unmap(st, stImage); + /* map next slice of 3D texture */ + texImage->Data = st_texture_image_map(st, stImage, + zoffset + i + 1, + transfer_usage, + xoffset, yoffset, + width, height); + src += srcImageStride; + } + } + +done: + _mesa_unmap_teximage_pbo(ctx, packing); + + if (stImage->pt && texImage->Data) { + st_texture_image_unmap(st, stImage); + texImage->Data = NULL; + } +} + + + +static void +st_TexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexSubimage(ctx, 3, target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type, + pixels, packing, texObj, texImage); +} + + +static void +st_TexSubImage2D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexSubimage(ctx, 2, target, level, xoffset, yoffset, 0, + width, height, 1, format, type, + pixels, packing, texObj, texImage); +} + + +static void +st_TexSubImage1D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLsizei width, GLenum format, GLenum type, + const GLvoid * pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + st_TexSubimage(ctx, 1, target, level, xoffset, 0, 0, width, 1, 1, + format, type, pixels, packing, texObj, texImage); +} + + +static void +st_CompressedTexSubImage1D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLsizei width, + GLenum format, + GLsizei imageSize, const GLvoid *data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + assert(0); +} + + +static void +st_CompressedTexSubImage2D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLint height, + GLenum format, + GLsizei imageSize, const GLvoid *data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + struct st_context *st = st_context(ctx); + struct st_texture_image *stImage = st_texture_image(texImage); + int srcBlockStride; + int dstBlockStride; + int y; + enum pipe_format pformat; + + if (stImage->pt) { + pformat = stImage->pt->format; + + texImage->Data = st_texture_image_map(st, stImage, 0, + PIPE_TRANSFER_WRITE, + xoffset, yoffset, + width, height); + + srcBlockStride = util_format_get_stride(pformat, width); + dstBlockStride = stImage->transfer->stride; + } else { + assert(stImage->pt); + /* TODO find good values for block and strides */ + /* TODO also adjust texImage->data for yoffset/xoffset */ + return; + } + + if (!texImage->Data) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexSubImage"); + return; + } + + assert(xoffset % util_format_get_blockwidth(pformat) == 0); + assert(yoffset % util_format_get_blockheight(pformat) == 0); + + for (y = 0; y < height; y += util_format_get_blockheight(pformat)) { + /* don't need to adjust for xoffset and yoffset as st_texture_image_map does that */ + const char *src = (const char*)data + srcBlockStride * util_format_get_nblocksy(pformat, y); + char *dst = (char*)texImage->Data + dstBlockStride * util_format_get_nblocksy(pformat, y); + memcpy(dst, src, util_format_get_stride(pformat, width)); + } + + if (stImage->pt) { + st_texture_image_unmap(st, stImage); + texImage->Data = NULL; + } +} + + +static void +st_CompressedTexSubImage3D(struct gl_context *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLint height, GLint depth, + GLenum format, + GLsizei imageSize, const GLvoid *data, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) +{ + assert(0); +} + + + +/** + * Do a CopyTexSubImage operation using a read transfer from the source, + * a write transfer to the destination and get_tile()/put_tile() to access + * the pixels/texels. + * + * Note: srcY=0=TOP of renderbuffer + */ +static void +fallback_copy_texsubimage(struct gl_context *ctx, GLenum target, GLint level, + struct st_renderbuffer *strb, + struct st_texture_image *stImage, + GLenum baseFormat, + GLint destX, GLint destY, GLint destZ, + GLint srcX, GLint srcY, + GLsizei width, GLsizei height) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_transfer *src_trans; + GLvoid *texDest; + enum pipe_transfer_usage transfer_usage; + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback processing\n", __FUNCTION__); + + assert(width <= MAX_WIDTH); + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + srcY = strb->Base.Height - srcY - height; + } + + src_trans = pipe_get_transfer(pipe, + strb->texture, + strb->rtt_level, + strb->rtt_face + strb->rtt_slice, + PIPE_TRANSFER_READ, + srcX, srcY, + width, height); + + if ((baseFormat == GL_DEPTH_COMPONENT || + baseFormat == GL_DEPTH_STENCIL) && + util_format_is_depth_and_stencil(stImage->pt->format)) + transfer_usage = PIPE_TRANSFER_READ_WRITE; + else + transfer_usage = PIPE_TRANSFER_WRITE; + + /* XXX this used to ignore destZ param */ + texDest = st_texture_image_map(st, stImage, destZ, transfer_usage, + destX, destY, width, height); + + if (baseFormat == GL_DEPTH_COMPONENT || + baseFormat == GL_DEPTH_STENCIL) { + const GLboolean scaleOrBias = (ctx->Pixel.DepthScale != 1.0F || + ctx->Pixel.DepthBias != 0.0F); + GLint row, yStep; + + /* determine bottom-to-top vs. top-to-bottom order for src buffer */ + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + srcY = height - 1; + yStep = -1; + } + else { + srcY = 0; + yStep = 1; + } + + /* To avoid a large temp memory allocation, do copy row by row */ + for (row = 0; row < height; row++, srcY += yStep) { + uint data[MAX_WIDTH]; + pipe_get_tile_z(pipe, src_trans, 0, srcY, width, 1, data); + if (scaleOrBias) { + _mesa_scale_and_bias_depth_uint(ctx, width, data); + } + pipe_put_tile_z(pipe, stImage->transfer, 0, row, width, 1, data); + } + } + else { + /* RGBA format */ + GLfloat *tempSrc = + (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); + + if (tempSrc && texDest) { + const GLint dims = 2; + const GLint dstRowStride = stImage->transfer->stride; + struct gl_texture_image *texImage = &stImage->base; + struct gl_pixelstore_attrib unpack = ctx->DefaultPacking; + + if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { + unpack.Invert = GL_TRUE; + } + + /* get float/RGBA image from framebuffer */ + /* XXX this usually involves a lot of int/float conversion. + * try to avoid that someday. + */ + pipe_get_tile_rgba_format(pipe, src_trans, 0, 0, width, height, + util_format_linear(strb->texture->format), + tempSrc); + + /* Store into texture memory. + * Note that this does some special things such as pixel transfer + * ops and format conversion. In particular, if the dest tex format + * is actually RGBA but the user created the texture as GL_RGB we + * need to fill-in/override the alpha channel with 1.0. + */ + _mesa_texstore(ctx, dims, + texImage->_BaseFormat, + texImage->TexFormat, + texDest, + 0, 0, 0, + dstRowStride, + texImage->ImageOffsets, + width, height, 1, + GL_RGBA, GL_FLOAT, tempSrc, /* src */ + &unpack); + } + else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage"); + } + + if (tempSrc) + free(tempSrc); + } + + st_texture_image_unmap(st, stImage); + pipe->transfer_destroy(pipe, src_trans); +} + + + +/** + * If the format of the src renderbuffer and the format of the dest + * texture are compatible (in terms of blitting), return a TGSI writemask + * to be used during the blit. + * If the src/dest are incompatible, return 0. + */ +static unsigned +compatible_src_dst_formats(struct gl_context *ctx, + const struct gl_renderbuffer *src, + const struct gl_texture_image *dst) +{ + /* Get logical base formats for the src and dest. + * That is, use the user-requested formats and not the actual, device- + * chosen formats. + * For example, the user may have requested an A8 texture but the + * driver may actually be using an RGBA texture format. When we + * copy/blit to that texture, we only want to copy the Alpha channel + * and not the RGB channels. + * + * Similarly, when the src FBO was created an RGB format may have been + * requested but the driver actually chose an RGBA format. In that case, + * we don't want to copy the undefined Alpha channel to the dest texture + * (it should be 1.0). + */ + const GLenum srcFormat = _mesa_base_fbo_format(ctx, src->InternalFormat); + const GLenum dstFormat = _mesa_base_tex_format(ctx, dst->InternalFormat); + + /** + * XXX when we have red-only and red/green renderbuffers we'll need + * to add more cases here (or implement a general-purpose routine that + * queries the existance of the R,G,B,A channels in the src and dest). + */ + if (srcFormat == dstFormat) { + /* This is the same as matching_base_formats, which should + * always pass, as it did previously. + */ + return TGSI_WRITEMASK_XYZW; + } + else if (srcFormat == GL_RGB && dstFormat == GL_RGBA) { + /* Make sure that A in the dest is 1. The actual src format + * may be RGBA and have undefined A values. + */ + return TGSI_WRITEMASK_XYZ; + } + else if (srcFormat == GL_RGBA && dstFormat == GL_RGB) { + /* Make sure that A in the dest is 1. The actual dst format + * may be RGBA and will need A=1 to provide proper alpha values + * when sampled later. + */ + return TGSI_WRITEMASK_XYZ; + } + else { + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s failed for src %s, dst %s\n", + __FUNCTION__, + _mesa_lookup_enum_by_nr(srcFormat), + _mesa_lookup_enum_by_nr(dstFormat)); + + /* Otherwise fail. + */ + return 0; + } +} + + + +/** + * Do a CopyTex[Sub]Image1/2/3D() using a hardware (blit) path if possible. + * Note that the region to copy has already been clipped so we know we + * won't read from outside the source renderbuffer's bounds. + * + * Note: srcY=0=Bottom of renderbuffer (GL convention) + */ +static void +st_copy_texsubimage(struct gl_context *ctx, + GLenum target, GLint level, + GLint destX, GLint destY, GLint destZ, + GLint srcX, GLint srcY, + GLsizei width, GLsizei height) +{ + struct gl_texture_unit *texUnit = + &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + struct gl_texture_object *texObj = + _mesa_select_tex_object(ctx, texUnit, target); + struct gl_texture_image *texImage = + _mesa_select_tex_image(ctx, texObj, target, level); + struct st_texture_image *stImage = st_texture_image(texImage); + const GLenum texBaseFormat = texImage->_BaseFormat; + struct gl_framebuffer *fb = ctx->ReadBuffer; + struct st_renderbuffer *strb; + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + enum pipe_format dest_format, src_format; + GLboolean use_fallback = GL_TRUE; + GLboolean matching_base_formats; + GLuint format_writemask, sample_count; + struct pipe_surface *dest_surface = NULL; + GLboolean do_flip = (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP); + + /* make sure finalize_textures has been called? + */ + if (0) st_validate_state(st); + + /* determine if copying depth or color data */ + if (texBaseFormat == GL_DEPTH_COMPONENT || + texBaseFormat == GL_DEPTH_STENCIL) { + strb = st_renderbuffer(fb->_DepthBuffer); + if (strb->Base.Wrapped) { + strb = st_renderbuffer(strb->Base.Wrapped); + } + } + else { + /* texBaseFormat == GL_RGB, GL_RGBA, GL_ALPHA, etc */ + strb = st_renderbuffer(fb->_ColorReadBuffer); + } + + if (!strb || !strb->surface || !stImage->pt) { + debug_printf("%s: null strb or stImage\n", __FUNCTION__); + return; + } + + sample_count = strb->surface->texture->nr_samples; + /* I believe this would be legal, presumably would need to do a resolve + for color, and for depth/stencil spec says to just use one of the + depth/stencil samples per pixel? Need some transfer clarifications. */ + assert(sample_count < 2); + + assert(strb); + assert(strb->surface); + assert(stImage->pt); + + src_format = strb->surface->format; + dest_format = stImage->pt->format; + + /* + * Determine if the src framebuffer and dest texture have the same + * base format. We need this to detect a case such as the framebuffer + * being GL_RGBA but the texture being GL_RGB. If the actual hardware + * texture format stores RGBA we need to set A=1 (overriding the + * framebuffer's alpha values). We can't do that with the blit or + * textured-quad paths. + */ + matching_base_formats = + (_mesa_get_format_base_format(strb->Base.Format) == + _mesa_get_format_base_format(texImage->TexFormat)); + format_writemask = compatible_src_dst_formats(ctx, &strb->Base, texImage); + + if (ctx->_ImageTransferState == 0x0) { + + if (matching_base_formats && + src_format == dest_format && + !do_flip) + { + /* use surface_copy() / blit */ + struct pipe_box src_box; + u_box_2d_zslice(srcX, srcY, strb->surface->u.tex.first_layer, + width, height, &src_box); + + /* for resource_copy_region(), y=0=top, always */ + pipe->resource_copy_region(pipe, + /* dest */ + stImage->pt, + stImage->base.Level, + destX, destY, destZ + stImage->base.Face, + /* src */ + strb->texture, + strb->surface->u.tex.level, + &src_box); + use_fallback = GL_FALSE; + } + else if (format_writemask && + texBaseFormat != GL_DEPTH_COMPONENT && + texBaseFormat != GL_DEPTH_STENCIL && + screen->is_format_supported(screen, src_format, + PIPE_TEXTURE_2D, sample_count, + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, dest_format, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET)) { + /* draw textured quad to do the copy */ + GLint srcY0, srcY1; + struct pipe_surface surf_tmpl; + memset(&surf_tmpl, 0, sizeof(surf_tmpl)); + surf_tmpl.format = util_format_linear(stImage->pt->format); + surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; + surf_tmpl.u.tex.level = stImage->base.Level; + surf_tmpl.u.tex.first_layer = stImage->base.Face + destZ; + surf_tmpl.u.tex.last_layer = stImage->base.Face + destZ; + + dest_surface = pipe->create_surface(pipe, stImage->pt, + &surf_tmpl); + + if (do_flip) { + srcY1 = strb->Base.Height - srcY - height; + srcY0 = srcY1 + height; + } + else { + srcY0 = srcY; + srcY1 = srcY0 + height; + } + + /* Disable conditional rendering. */ + if (st->render_condition) { + pipe->render_condition(pipe, NULL, 0); + } + + util_blit_pixels_writemask(st->blit, + strb->texture, + strb->surface->u.tex.level, + srcX, srcY0, + srcX + width, srcY1, + strb->surface->u.tex.first_layer, + dest_surface, + destX, destY, + destX + width, destY + height, + 0.0, PIPE_TEX_MIPFILTER_NEAREST, + format_writemask); + + /* Restore conditional rendering state. */ + if (st->render_condition) { + pipe->render_condition(pipe, st->render_condition, + st->condition_mode); + } + + use_fallback = GL_FALSE; + } + + if (dest_surface) + pipe_surface_reference(&dest_surface, NULL); + } + + if (use_fallback) { + /* software fallback */ + fallback_copy_texsubimage(ctx, target, level, + strb, stImage, texBaseFormat, + destX, destY, destZ, + srcX, srcY, width, height); + } +} + + + +static void +st_CopyTexSubImage1D(struct gl_context * ctx, GLenum target, GLint level, + GLint xoffset, GLint x, GLint y, GLsizei width) +{ + const GLint yoffset = 0, zoffset = 0; + const GLsizei height = 1; + st_copy_texsubimage(ctx, target, level, + xoffset, yoffset, zoffset, /* destX,Y,Z */ + x, y, width, height); /* src X, Y, size */ +} + + +static void +st_CopyTexSubImage2D(struct gl_context * ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + const GLint zoffset = 0; + st_copy_texsubimage(ctx, target, level, + xoffset, yoffset, zoffset, /* destX,Y,Z */ + x, y, width, height); /* src X, Y, size */ +} + + +static void +st_CopyTexSubImage3D(struct gl_context * ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLint x, GLint y, GLsizei width, GLsizei height) +{ + st_copy_texsubimage(ctx, target, level, + xoffset, yoffset, zoffset, /* destX,Y,Z */ + x, y, width, height); /* src X, Y, size */ +} + + +/** + * Copy image data from stImage into the texture object 'stObj' at level + * 'dstLevel'. + */ +static void +copy_image_data_to_texture(struct st_context *st, + struct st_texture_object *stObj, + GLuint dstLevel, + struct st_texture_image *stImage) +{ + /* debug checks */ + { + const struct gl_texture_image *dstImage = + stObj->base.Image[stImage->base.Face][dstLevel]; + assert(dstImage); + assert(dstImage->Width == stImage->base.Width); + assert(dstImage->Height == stImage->base.Height); + assert(dstImage->Depth == stImage->base.Depth); + } + + if (stImage->pt) { + /* Copy potentially with the blitter: + */ + st_texture_image_copy(st->pipe, + stObj->pt, dstLevel, /* dest texture, level */ + stImage->pt, stImage->base.Level, /* src texture, level */ + stImage->base.Face); + + pipe_resource_reference(&stImage->pt, NULL); + } + else if (stImage->base.Data) { + st_texture_image_data(st, + stObj->pt, + stImage->base.Face, + dstLevel, + stImage->base.Data, + stImage->base.RowStride * + util_format_get_blocksize(stObj->pt->format), + stImage->base.RowStride * + stImage->base.Height * + util_format_get_blocksize(stObj->pt->format)); + _mesa_align_free(stImage->base.Data); + stImage->base.Data = NULL; + } + + pipe_resource_reference(&stImage->pt, stObj->pt); +} + + +/** + * Called during state validation. When this function is finished, + * the texture object should be ready for rendering. + * \return GL_TRUE for success, GL_FALSE for failure (out of mem) + */ +GLboolean +st_finalize_texture(struct gl_context *ctx, + struct pipe_context *pipe, + struct gl_texture_object *tObj) +{ + struct st_context *st = st_context(ctx); + struct st_texture_object *stObj = st_texture_object(tObj); + const GLuint nr_faces = (stObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; + GLuint face; + struct st_texture_image *firstImage; + enum pipe_format firstImageFormat; + GLuint ptWidth, ptHeight, ptDepth, ptLayers; + + if (stObj->base._Complete) { + /* The texture is complete and we know exactly how many mipmap levels + * are present/needed. This is conditional because we may be called + * from the st_generate_mipmap() function when the texture object is + * incomplete. In that case, we'll have set stObj->lastLevel before + * we get here. + */ + if (stObj->base.Sampler.MinFilter == GL_LINEAR || + stObj->base.Sampler.MinFilter == GL_NEAREST) + stObj->lastLevel = stObj->base.BaseLevel; + else + stObj->lastLevel = stObj->base._MaxLevel; + } + + firstImage = st_texture_image(stObj->base.Image[0][stObj->base.BaseLevel]); + assert(firstImage); + + /* If both firstImage and stObj point to a texture which can contain + * all active images, favour firstImage. Note that because of the + * completeness requirement, we know that the image dimensions + * will match. + */ + if (firstImage->pt && + firstImage->pt != stObj->pt && + (!stObj->pt || firstImage->pt->last_level >= stObj->pt->last_level)) { + pipe_resource_reference(&stObj->pt, firstImage->pt); + pipe_sampler_view_reference(&stObj->sampler_view, NULL); + } + + /* Find gallium format for the Mesa texture */ + firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat); + + /* Find size of level=0 Gallium mipmap image, plus number of texture layers */ + { + GLuint width, height, depth; + if (!guess_base_level_size(stObj->base.Target, + firstImage->base.Width2, + firstImage->base.Height2, + firstImage->base.Depth2, + stObj->base.BaseLevel, + &width, &height, &depth)) { + width = stObj->width0; + height = stObj->height0; + depth = stObj->depth0; + } + /* convert GL dims to Gallium dims */ + st_gl_texture_dims_to_pipe_dims(stObj->base.Target, width, height, depth, + &ptWidth, &ptHeight, &ptDepth, &ptLayers); + } + + /* If we already have a gallium texture, check that it matches the texture + * object's format, target, size, num_levels, etc. + */ + if (stObj->pt) { + if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) || + !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) || + stObj->pt->last_level < stObj->lastLevel || + stObj->pt->width0 != ptWidth || + stObj->pt->height0 != ptHeight || + stObj->pt->depth0 != ptDepth || + stObj->pt->array_size != ptLayers) + { + /* The gallium texture does not match the Mesa texture so delete the + * gallium texture now. We'll make a new one below. + */ + pipe_resource_reference(&stObj->pt, NULL); + pipe_sampler_view_reference(&stObj->sampler_view, NULL); + st->dirty.st |= ST_NEW_FRAMEBUFFER; + } + } + + /* May need to create a new gallium texture: + */ + if (!stObj->pt) { + GLuint bindings = default_bindings(st, firstImageFormat); + + stObj->pt = st_texture_create(st, + gl_target_to_pipe(stObj->base.Target), + firstImageFormat, + stObj->lastLevel, + ptWidth, + ptHeight, + ptDepth, + ptLayers, + bindings); + + if (!stObj->pt) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); + return GL_FALSE; + } + } + + /* Pull in any images not in the object's texture: + */ + for (face = 0; face < nr_faces; face++) { + GLuint level; + for (level = stObj->base.BaseLevel; level <= stObj->lastLevel; level++) { + struct st_texture_image *stImage = + st_texture_image(stObj->base.Image[face][level]); + + /* Need to import images in main memory or held in other textures. + */ + if (stImage && stObj->pt != stImage->pt) { + if (level == 0 || (stImage->base.Width == u_minify(stObj->width0, level) && + stImage->base.Height == u_minify(stObj->height0, level) && + stImage->base.Depth == u_minify(stObj->depth0, level))) { + /* src image fits expected dest mipmap level size */ + copy_image_data_to_texture(st, stObj, level, stImage); + } + } + } + } + + return GL_TRUE; +} + + +/** + * Returns pointer to a default/dummy texture. + * This is typically used when the current shader has tex/sample instructions + * but the user has not provided a (any) texture(s). + */ +struct gl_texture_object * +st_get_default_texture(struct st_context *st) +{ + if (!st->default_texture) { + static const GLenum target = GL_TEXTURE_2D; + GLubyte pixels[16][16][4]; + struct gl_texture_object *texObj; + struct gl_texture_image *texImg; + GLuint i, j; + + /* The ARB_fragment_program spec says (0,0,0,1) should be returned + * when attempting to sample incomplete textures. + */ + for (i = 0; i < 16; i++) { + for (j = 0; j < 16; j++) { + pixels[i][j][0] = 0; + pixels[i][j][1] = 0; + pixels[i][j][2] = 0; + pixels[i][j][3] = 255; + } + } + + texObj = st->ctx->Driver.NewTextureObject(st->ctx, 0, target); + + texImg = _mesa_get_tex_image(st->ctx, texObj, target, 0); + + _mesa_init_teximage_fields(st->ctx, target, texImg, + 16, 16, 1, 0, /* w, h, d, border */ + GL_RGBA, MESA_FORMAT_RGBA8888); + + st_TexImage(st->ctx, 2, target, + 0, GL_RGBA, /* level, intformat */ + 16, 16, 1, 0, /* w, h, d, border */ + GL_RGBA, GL_UNSIGNED_BYTE, pixels, + &st->ctx->DefaultPacking, + texObj, texImg, + 0, 0); + + texObj->Sampler.MinFilter = GL_NEAREST; + texObj->Sampler.MagFilter = GL_NEAREST; + texObj->_Complete = GL_TRUE; + + st->default_texture = texObj; + } + return st->default_texture; +} + + +void +st_init_texture_functions(struct dd_function_table *functions) +{ + functions->ChooseTextureFormat = st_ChooseTextureFormat; + functions->TexImage1D = st_TexImage1D; + functions->TexImage2D = st_TexImage2D; + functions->TexImage3D = st_TexImage3D; + functions->TexSubImage1D = st_TexSubImage1D; + functions->TexSubImage2D = st_TexSubImage2D; + functions->TexSubImage3D = st_TexSubImage3D; + functions->CompressedTexSubImage1D = st_CompressedTexSubImage1D; + functions->CompressedTexSubImage2D = st_CompressedTexSubImage2D; + functions->CompressedTexSubImage3D = st_CompressedTexSubImage3D; + functions->CopyTexSubImage1D = st_CopyTexSubImage1D; + functions->CopyTexSubImage2D = st_CopyTexSubImage2D; + functions->CopyTexSubImage3D = st_CopyTexSubImage3D; + functions->GenerateMipmap = st_generate_mipmap; + + functions->GetTexImage = st_GetTexImage; + + /* compressed texture functions */ + functions->CompressedTexImage2D = st_CompressedTexImage2D; + functions->GetCompressedTexImage = st_GetCompressedTexImage; + + functions->NewTextureObject = st_NewTextureObject; + functions->NewTextureImage = st_NewTextureImage; + functions->DeleteTexture = st_DeleteTextureObject; + functions->FreeTextureImageBuffer = st_FreeTextureImageBuffer; + functions->MapTextureImage = st_MapTextureImage; + functions->UnmapTextureImage = st_UnmapTextureImage; + + functions->TextureMemCpy = do_memcpy; + + /* XXX Temporary until we can query pipe's texture sizes */ + functions->TestProxyTexImage = _mesa_test_proxy_teximage; +} diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c index b6a78daf6..6d4bc544d 100644 --- a/mesalib/src/mesa/state_tracker/st_context.c +++ b/mesalib/src/mesa/state_tracker/st_context.c @@ -1,303 +1,303 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-#include "main/imports.h"
-#include "main/context.h"
-#include "main/samplerobj.h"
-#include "main/shaderobj.h"
-#include "program/prog_cache.h"
-#include "vbo/vbo.h"
-#include "glapi/glapi.h"
-#include "st_context.h"
-#include "st_debug.h"
-#include "st_cb_accum.h"
-#include "st_cb_bitmap.h"
-#include "st_cb_blit.h"
-#include "st_cb_bufferobjects.h"
-#include "st_cb_clear.h"
-#include "st_cb_condrender.h"
-#include "st_cb_drawpixels.h"
-#include "st_cb_rasterpos.h"
-#include "st_cb_drawtex.h"
-#include "st_cb_eglimage.h"
-#include "st_cb_fbo.h"
-#include "st_cb_feedback.h"
-#include "st_cb_program.h"
-#include "st_cb_queryobj.h"
-#include "st_cb_readpixels.h"
-#include "st_cb_texture.h"
-#include "st_cb_xformfb.h"
-#include "st_cb_flush.h"
-#include "st_cb_syncobj.h"
-#include "st_cb_strings.h"
-#include "st_cb_texturebarrier.h"
-#include "st_cb_viewport.h"
-#include "st_atom.h"
-#include "st_draw.h"
-#include "st_extensions.h"
-#include "st_gen_mipmap.h"
-#include "st_program.h"
-#include "pipe/p_context.h"
-#include "util/u_inlines.h"
-#include "cso_cache/cso_context.h"
-
-
-DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE)
-
-
-/**
- * Called via ctx->Driver.UpdateState()
- */
-void st_invalidate_state(struct gl_context * ctx, GLuint new_state)
-{
- struct st_context *st = st_context(ctx);
-
- st->dirty.mesa |= new_state;
- st->dirty.st |= ST_NEW_MESA;
-
- /* This is the only core Mesa module we depend upon.
- * No longer use swrast, swsetup, tnl.
- */
- _vbo_InvalidateState(ctx, new_state);
-}
-
-
-/**
- * Check for multisample env var override.
- */
-int
-st_get_msaa(void)
-{
- const char *msaa = _mesa_getenv("__GL_FSAA_MODE");
- if (msaa)
- return atoi(msaa);
- return 0;
-}
-
-
-static struct st_context *
-st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe )
-{
- uint i;
- struct st_context *st = ST_CALLOC_STRUCT( st_context );
-
- ctx->st = st;
-
- st->ctx = ctx;
- st->pipe = pipe;
-
- /* XXX: this is one-off, per-screen init: */
- st_debug_init();
-
- /* state tracker needs the VBO module */
- _vbo_CreateContext(ctx);
-
- st->dirty.mesa = ~0;
- st->dirty.st = ~0;
-
- st->cso_context = cso_create_context(pipe);
-
- st_init_atoms( st );
- st_init_bitmap(st);
- st_init_clear(st);
- st_init_draw( st );
- st_init_generate_mipmap(st);
- st_init_blit(st);
-
- if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES))
- st->internal_target = PIPE_TEXTURE_2D;
- else
- st->internal_target = PIPE_TEXTURE_RECT;
-
- for (i = 0; i < 3; i++) {
- memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element));
- st->velems_util_draw[i].src_offset = i * 4 * sizeof(float);
- st->velems_util_draw[i].instance_divisor = 0;
- st->velems_util_draw[i].vertex_buffer_index = 0;
- st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
- }
-
- /* we want all vertex data to be placed in buffer objects */
- vbo_use_buffer_objects(ctx);
-
- /* Need these flags:
- */
- st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
-
- st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE;
-
- st->pixel_xfer.cache = _mesa_new_program_cache();
-
- st->force_msaa = st_get_msaa();
-
- /* GL limits and extensions */
- st_init_limits(st);
- st_init_extensions(st);
-
- return st;
-}
-
-
-struct st_context *st_create_context(gl_api api, struct pipe_context *pipe,
- const struct gl_config *visual,
- struct st_context *share)
-{
- struct gl_context *ctx;
- struct gl_context *shareCtx = share ? share->ctx : NULL;
- struct dd_function_table funcs;
-
- /* Sanity checks */
- assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX);
- assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT);
- assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY);
-
- memset(&funcs, 0, sizeof(funcs));
- st_init_driver_functions(&funcs);
-
- ctx = _mesa_create_context(api, visual, shareCtx, &funcs, NULL);
- if (!ctx) {
- return NULL;
- }
-
- /* XXX: need a capability bit in gallium to query if the pipe
- * driver prefers DP4 or MUL/MAD for vertex transformation.
- */
- if (debug_get_option_mesa_mvp_dp4())
- _mesa_set_mvp_with_dp4( ctx, GL_TRUE );
-
- return st_create_context_priv(ctx, pipe);
-}
-
-
-static void st_destroy_context_priv( struct st_context *st )
-{
- uint i;
-
- st_destroy_atoms( st );
- st_destroy_draw( st );
- st_destroy_generate_mipmap(st);
- st_destroy_blit(st);
- st_destroy_clear(st);
- st_destroy_bitmap(st);
- st_destroy_drawpix(st);
- st_destroy_drawtex(st);
-
- /* Unreference any user vertex buffers. */
- for (i = 0; i < st->num_user_attribs; i++) {
- pipe_resource_reference(&st->user_attrib[i].buffer, NULL);
- }
-
- for (i = 0; i < Elements(st->state.sampler_views); i++) {
- pipe_sampler_view_reference(&st->state.sampler_views[i], NULL);
- }
-
- if (st->default_texture) {
- st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture);
- st->default_texture = NULL;
- }
-
- free( st );
-}
-
-
-void st_destroy_context( struct st_context *st )
-{
- struct pipe_context *pipe = st->pipe;
- struct cso_context *cso = st->cso_context;
- struct gl_context *ctx = st->ctx;
- GLuint i;
-
- /* need to unbind and destroy CSO objects before anything else */
- cso_release_all(st->cso_context);
-
- st_reference_fragprog(st, &st->fp, NULL);
- st_reference_vertprog(st, &st->vp, NULL);
-
- /* release framebuffer surfaces */
- for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
- pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL);
- }
- pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL);
-
- pipe->set_index_buffer(pipe, NULL);
-
- for (i = 0; i < PIPE_SHADER_TYPES; i++) {
- pipe->set_constant_buffer(pipe, i, 0, NULL);
- }
-
- _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache);
-
- _vbo_DestroyContext(st->ctx);
-
- st_destroy_program_variants(st);
-
- _mesa_free_context_data(ctx);
-
- st_destroy_context_priv(st);
-
- cso_destroy_context(cso);
-
- pipe->destroy( pipe );
-
- free(ctx);
-}
-
-
-void st_init_driver_functions(struct dd_function_table *functions)
-{
- _mesa_init_shader_object_functions(functions);
- _mesa_init_sampler_object_functions(functions);
-
- st_init_accum_functions(functions);
- st_init_blit_functions(functions);
- st_init_bufferobject_functions(functions);
- st_init_clear_functions(functions);
- st_init_bitmap_functions(functions);
- st_init_drawpixels_functions(functions);
- st_init_rasterpos_functions(functions);
-
- st_init_drawtex_functions(functions);
-
- st_init_eglimage_functions(functions);
-
- st_init_fbo_functions(functions);
- st_init_feedback_functions(functions);
- st_init_program_functions(functions);
- st_init_query_functions(functions);
- st_init_cond_render_functions(functions);
- st_init_readpixels_functions(functions);
- st_init_texture_functions(functions);
- st_init_texture_barrier_functions(functions);
- st_init_flush_functions(functions);
- st_init_string_functions(functions);
- st_init_viewport_functions(functions);
-
- st_init_xformfb_functions(functions);
- st_init_syncobj_functions(functions);
-
- functions->UpdateState = st_invalidate_state;
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + +#include "main/imports.h" +#include "main/context.h" +#include "main/samplerobj.h" +#include "main/shaderobj.h" +#include "program/prog_cache.h" +#include "vbo/vbo.h" +#include "glapi/glapi.h" +#include "st_context.h" +#include "st_debug.h" +#include "st_cb_accum.h" +#include "st_cb_bitmap.h" +#include "st_cb_blit.h" +#include "st_cb_bufferobjects.h" +#include "st_cb_clear.h" +#include "st_cb_condrender.h" +#include "st_cb_drawpixels.h" +#include "st_cb_rasterpos.h" +#include "st_cb_drawtex.h" +#include "st_cb_eglimage.h" +#include "st_cb_fbo.h" +#include "st_cb_feedback.h" +#include "st_cb_program.h" +#include "st_cb_queryobj.h" +#include "st_cb_readpixels.h" +#include "st_cb_texture.h" +#include "st_cb_xformfb.h" +#include "st_cb_flush.h" +#include "st_cb_syncobj.h" +#include "st_cb_strings.h" +#include "st_cb_texturebarrier.h" +#include "st_cb_viewport.h" +#include "st_atom.h" +#include "st_draw.h" +#include "st_extensions.h" +#include "st_gen_mipmap.h" +#include "st_program.h" +#include "pipe/p_context.h" +#include "util/u_inlines.h" +#include "cso_cache/cso_context.h" + + +DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE) + + +/** + * Called via ctx->Driver.UpdateState() + */ +void st_invalidate_state(struct gl_context * ctx, GLuint new_state) +{ + struct st_context *st = st_context(ctx); + + st->dirty.mesa |= new_state; + st->dirty.st |= ST_NEW_MESA; + + /* This is the only core Mesa module we depend upon. + * No longer use swrast, swsetup, tnl. + */ + _vbo_InvalidateState(ctx, new_state); +} + + +/** + * Check for multisample env var override. + */ +int +st_get_msaa(void) +{ + const char *msaa = _mesa_getenv("__GL_FSAA_MODE"); + if (msaa) + return atoi(msaa); + return 0; +} + + +static struct st_context * +st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe ) +{ + uint i; + struct st_context *st = ST_CALLOC_STRUCT( st_context ); + + ctx->st = st; + + st->ctx = ctx; + st->pipe = pipe; + + /* XXX: this is one-off, per-screen init: */ + st_debug_init(); + + /* state tracker needs the VBO module */ + _vbo_CreateContext(ctx); + + st->dirty.mesa = ~0; + st->dirty.st = ~0; + + st->cso_context = cso_create_context(pipe); + + st_init_atoms( st ); + st_init_bitmap(st); + st_init_clear(st); + st_init_draw( st ); + st_init_generate_mipmap(st); + st_init_blit(st); + + if(pipe->screen->get_param(pipe->screen, PIPE_CAP_NPOT_TEXTURES)) + st->internal_target = PIPE_TEXTURE_2D; + else + st->internal_target = PIPE_TEXTURE_RECT; + + for (i = 0; i < 3; i++) { + memset(&st->velems_util_draw[i], 0, sizeof(struct pipe_vertex_element)); + st->velems_util_draw[i].src_offset = i * 4 * sizeof(float); + st->velems_util_draw[i].instance_divisor = 0; + st->velems_util_draw[i].vertex_buffer_index = 0; + st->velems_util_draw[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT; + } + + /* we want all vertex data to be placed in buffer objects */ + vbo_use_buffer_objects(ctx); + + /* Need these flags: + */ + st->ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; + + st->ctx->VertexProgram._MaintainTnlProgram = GL_TRUE; + + st->pixel_xfer.cache = _mesa_new_program_cache(); + + st->force_msaa = st_get_msaa(); + + /* GL limits and extensions */ + st_init_limits(st); + st_init_extensions(st); + + return st; +} + + +struct st_context *st_create_context(gl_api api, struct pipe_context *pipe, + const struct gl_config *visual, + struct st_context *share) +{ + struct gl_context *ctx; + struct gl_context *shareCtx = share ? share->ctx : NULL; + struct dd_function_table funcs; + + /* Sanity checks */ + assert(MESA_SHADER_VERTEX == PIPE_SHADER_VERTEX); + assert(MESA_SHADER_FRAGMENT == PIPE_SHADER_FRAGMENT); + assert(MESA_SHADER_GEOMETRY == PIPE_SHADER_GEOMETRY); + + memset(&funcs, 0, sizeof(funcs)); + st_init_driver_functions(&funcs); + + ctx = _mesa_create_context(api, visual, shareCtx, &funcs, NULL); + if (!ctx) { + return NULL; + } + + /* XXX: need a capability bit in gallium to query if the pipe + * driver prefers DP4 or MUL/MAD for vertex transformation. + */ + if (debug_get_option_mesa_mvp_dp4()) + _mesa_set_mvp_with_dp4( ctx, GL_TRUE ); + + return st_create_context_priv(ctx, pipe); +} + + +static void st_destroy_context_priv( struct st_context *st ) +{ + uint i; + + st_destroy_atoms( st ); + st_destroy_draw( st ); + st_destroy_generate_mipmap(st); + st_destroy_blit(st); + st_destroy_clear(st); + st_destroy_bitmap(st); + st_destroy_drawpix(st); + st_destroy_drawtex(st); + + /* Unreference any user vertex buffers. */ + for (i = 0; i < st->num_user_attribs; i++) { + pipe_resource_reference(&st->user_attrib[i].buffer, NULL); + } + + for (i = 0; i < Elements(st->state.sampler_views); i++) { + pipe_sampler_view_reference(&st->state.sampler_views[i], NULL); + } + + if (st->default_texture) { + st->ctx->Driver.DeleteTexture(st->ctx, st->default_texture); + st->default_texture = NULL; + } + + free( st ); +} + + +void st_destroy_context( struct st_context *st ) +{ + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + struct gl_context *ctx = st->ctx; + GLuint i; + + /* need to unbind and destroy CSO objects before anything else */ + cso_release_all(st->cso_context); + + st_reference_fragprog(st, &st->fp, NULL); + st_reference_vertprog(st, &st->vp, NULL); + + /* release framebuffer surfaces */ + for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { + pipe_surface_reference(&st->state.framebuffer.cbufs[i], NULL); + } + pipe_surface_reference(&st->state.framebuffer.zsbuf, NULL); + + pipe->set_index_buffer(pipe, NULL); + + for (i = 0; i < PIPE_SHADER_TYPES; i++) { + pipe->set_constant_buffer(pipe, i, 0, NULL); + } + + _mesa_delete_program_cache(st->ctx, st->pixel_xfer.cache); + + _vbo_DestroyContext(st->ctx); + + st_destroy_program_variants(st); + + _mesa_free_context_data(ctx); + + st_destroy_context_priv(st); + + cso_destroy_context(cso); + + pipe->destroy( pipe ); + + free(ctx); +} + + +void st_init_driver_functions(struct dd_function_table *functions) +{ + _mesa_init_shader_object_functions(functions); + _mesa_init_sampler_object_functions(functions); + + st_init_accum_functions(functions); + st_init_blit_functions(functions); + st_init_bufferobject_functions(functions); + st_init_clear_functions(functions); + st_init_bitmap_functions(functions); + st_init_drawpixels_functions(functions); + st_init_rasterpos_functions(functions); + + st_init_drawtex_functions(functions); + + st_init_eglimage_functions(functions); + + st_init_fbo_functions(functions); + st_init_feedback_functions(functions); + st_init_program_functions(functions); + st_init_query_functions(functions); + st_init_cond_render_functions(functions); + st_init_readpixels_functions(functions); + st_init_texture_functions(functions); + st_init_texture_barrier_functions(functions); + st_init_flush_functions(functions); + st_init_string_functions(functions); + st_init_viewport_functions(functions); + + st_init_xformfb_functions(functions); + st_init_syncobj_functions(functions); + + functions->UpdateState = st_invalidate_state; +} diff --git a/mesalib/src/mesa/state_tracker/st_context.h b/mesalib/src/mesa/state_tracker/st_context.h index 0073ebe02..0a3220221 100644 --- a/mesalib/src/mesa/state_tracker/st_context.h +++ b/mesalib/src/mesa/state_tracker/st_context.h @@ -1,288 +1,288 @@ -/**************************************************************************
- *
- * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-#ifndef ST_CONTEXT_H
-#define ST_CONTEXT_H
-
-#include "main/mtypes.h"
-#include "pipe/p_state.h"
-#include "state_tracker/st_api.h"
-
-struct bitmap_cache;
-struct blit_state;
-struct dd_function_table;
-struct draw_context;
-struct draw_stage;
-struct gen_mipmap_state;
-struct st_context;
-struct st_fragment_program;
-
-
-#define ST_NEW_MESA 0x1 /* Mesa state has changed */
-#define ST_NEW_FRAGMENT_PROGRAM 0x2
-#define ST_NEW_VERTEX_PROGRAM 0x4
-#define ST_NEW_FRAMEBUFFER 0x8
-#define ST_NEW_EDGEFLAGS_DATA 0x10
-#define ST_NEW_GEOMETRY_PROGRAM 0x20
-
-
-struct st_state_flags {
- GLuint mesa;
- GLuint st;
-};
-
-struct st_tracked_state {
- const char *name;
- struct st_state_flags dirty;
- void (*update)( struct st_context *st );
-};
-
-
-
-struct st_context
-{
- struct st_context_iface iface;
-
- struct gl_context *ctx;
-
- struct pipe_context *pipe;
-
- struct draw_context *draw; /**< For selection/feedback/rastpos only */
- struct draw_stage *feedback_stage; /**< For GL_FEEDBACK rendermode */
- struct draw_stage *selection_stage; /**< For GL_SELECT rendermode */
- struct draw_stage *rastpos_stage; /**< For glRasterPos */
-
-
- /* On old libGL's for linux we need to invalidate the drawables
- * on glViewpport calls, this is set via a option.
- */
- boolean invalidate_on_gl_viewport;
-
- /* Some state is contained in constant objects.
- * Other state is just parameter values.
- */
- struct {
- struct pipe_blend_state blend;
- struct pipe_depth_stencil_alpha_state depth_stencil;
- struct pipe_rasterizer_state rasterizer;
- struct pipe_sampler_state samplers[PIPE_MAX_SAMPLERS];
- struct pipe_sampler_state vertex_samplers[PIPE_MAX_VERTEX_SAMPLERS];
- struct pipe_clip_state clip;
- struct {
- void *ptr;
- unsigned size;
- } constants[PIPE_SHADER_TYPES];
- struct pipe_framebuffer_state framebuffer;
- struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
- struct pipe_sampler_view *sampler_vertex_views[PIPE_MAX_VERTEX_SAMPLERS];
- struct pipe_scissor_state scissor;
- struct pipe_viewport_state viewport;
- unsigned sample_mask;
-
- GLuint num_samplers;
- GLuint num_vertex_samplers;
- GLuint num_textures;
- GLuint num_vertex_textures;
-
- GLuint poly_stipple[32]; /**< In OpenGL's bottom-to-top order */
- } state;
-
- char vendor[100];
- char renderer[100];
-
- struct st_state_flags dirty;
-
- GLboolean missing_textures;
- GLboolean vertdata_edgeflags;
-
- /** Mapping from VERT_RESULT_x to post-transformed vertex slot */
- const GLuint *vertex_result_to_slot;
-
- struct st_vertex_program *vp; /**< Currently bound vertex program */
- struct st_fragment_program *fp; /**< Currently bound fragment program */
- struct st_geometry_program *gp; /**< Currently bound geometry program */
-
- struct st_vp_variant *vp_variant;
- struct st_fp_variant *fp_variant;
- struct st_gp_variant *gp_variant;
-
- struct gl_texture_object *default_texture;
-
- struct {
- struct gl_program_cache *cache;
- struct st_fragment_program *program; /**< cur pixel transfer prog */
- GLuint xfer_prog_sn; /**< pixel xfer program serial no. */
- GLuint user_prog_sn; /**< user fragment program serial no. */
- struct st_fragment_program *combined_prog;
- GLuint combined_prog_sn;
- struct pipe_resource *pixelmap_texture;
- struct pipe_sampler_view *pixelmap_sampler_view;
- boolean pixelmap_enabled; /**< use the pixelmap texture? */
- } pixel_xfer;
-
- /** for glBitmap */
- struct {
- struct pipe_rasterizer_state rasterizer;
- struct pipe_sampler_state samplers[2];
- enum pipe_format tex_format;
- void *vs;
- float vertices[4][3][4]; /**< vertex pos + color + texcoord */
- struct pipe_resource *vbuf;
- unsigned vbuf_slot; /* next free slot in vbuf */
- struct bitmap_cache *cache;
- } bitmap;
-
- /** for glDraw/CopyPixels */
- struct {
- struct gl_fragment_program *shaders[4];
- void *vert_shaders[2]; /**< ureg shaders */
- } drawpix;
-
- /** for glClear */
- struct {
- struct pipe_rasterizer_state raster;
- struct pipe_viewport_state viewport;
- struct pipe_clip_state clip;
- void *vs;
- void *fs;
- float vertices[4][2][4]; /**< vertex pos + color */
- struct pipe_resource *vbuf;
- unsigned vbuf_slot;
- boolean enable_ds_separate;
- } clear;
-
- /** used for anything using util_draw_vertex_buffer */
- struct pipe_vertex_element velems_util_draw[3];
-
- void *passthrough_fs; /**< simple pass-through frag shader */
-
- enum pipe_texture_target internal_target;
- struct gen_mipmap_state *gen_mipmap;
- struct blit_state *blit;
-
- struct cso_context *cso_context;
-
- int force_msaa;
- void *winsys_drawable_handle;
-
- /* User vertex buffers. */
- struct {
- struct pipe_resource *buffer;
-
- /** Element size */
- GLuint element_size;
-
- /** Attribute stride */
- GLsizei stride;
- } user_attrib[PIPE_MAX_ATTRIBS];
- unsigned num_user_attribs;
-
- /* Active render condition. */
- struct pipe_query *render_condition;
- unsigned condition_mode;
-
- int32_t draw_stamp;
- int32_t read_stamp;
-};
-
-
-/* Need this so that we can implement Mesa callbacks in this module.
- */
-static INLINE struct st_context *st_context(struct gl_context *ctx)
-{
- return ctx->st;
-}
-
-
-/**
- * Wrapper for struct gl_framebuffer.
- * This is an opaque type to the outside world.
- */
-struct st_framebuffer
-{
- struct gl_framebuffer Base;
- void *Private;
-
- struct st_framebuffer_iface *iface;
- enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
- unsigned num_statts;
- int32_t stamp;
- int32_t iface_stamp;
-};
-
-
-extern void st_init_driver_functions(struct dd_function_table *functions);
-
-void st_invalidate_state(struct gl_context * ctx, GLuint new_state);
-
-
-
-#define Y_0_TOP 1
-#define Y_0_BOTTOM 2
-
-static INLINE GLuint
-st_fb_orientation(const struct gl_framebuffer *fb)
-{
- if (fb && fb->Name == 0) {
- /* Drawing into a window (on-screen buffer).
- *
- * Negate Y scale to flip image vertically.
- * The NDC Y coords prior to viewport transformation are in the range
- * [y=-1=bottom, y=1=top]
- * Hardware window coords are in the range [y=0=top, y=H-1=bottom] where
- * H is the window height.
- * Use the viewport transformation to invert Y.
- */
- return Y_0_TOP;
- }
- else {
- /* Drawing into user-created FBO (very likely a texture).
- *
- * For textures, T=0=Bottom, so by extension Y=0=Bottom for rendering.
- */
- return Y_0_BOTTOM;
- }
-}
-
-
-/** clear-alloc a struct-sized object, with casting */
-#define ST_CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T))
-
-
-extern int
-st_get_msaa(void);
-
-extern struct st_context *
-st_create_context(gl_api api, struct pipe_context *pipe,
- const struct gl_config *visual,
- struct st_context *share);
-
-extern void
-st_destroy_context(struct st_context *st);
-
-
-#endif
+/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + +#ifndef ST_CONTEXT_H +#define ST_CONTEXT_H + +#include "main/mtypes.h" +#include "pipe/p_state.h" +#include "state_tracker/st_api.h" + +struct bitmap_cache; +struct blit_state; +struct dd_function_table; +struct draw_context; +struct draw_stage; +struct gen_mipmap_state; +struct st_context; +struct st_fragment_program; + + +#define ST_NEW_MESA 0x1 /* Mesa state has changed */ +#define ST_NEW_FRAGMENT_PROGRAM 0x2 +#define ST_NEW_VERTEX_PROGRAM 0x4 +#define ST_NEW_FRAMEBUFFER 0x8 +#define ST_NEW_EDGEFLAGS_DATA 0x10 +#define ST_NEW_GEOMETRY_PROGRAM 0x20 + + +struct st_state_flags { + GLuint mesa; + GLuint st; +}; + +struct st_tracked_state { + const char *name; + struct st_state_flags dirty; + void (*update)( struct st_context *st ); +}; + + + +struct st_context +{ + struct st_context_iface iface; + + struct gl_context *ctx; + + struct pipe_context *pipe; + + struct draw_context *draw; /**< For selection/feedback/rastpos only */ + struct draw_stage *feedback_stage; /**< For GL_FEEDBACK rendermode */ + struct draw_stage *selection_stage; /**< For GL_SELECT rendermode */ + struct draw_stage *rastpos_stage; /**< For glRasterPos */ + + + /* On old libGL's for linux we need to invalidate the drawables + * on glViewpport calls, this is set via a option. + */ + boolean invalidate_on_gl_viewport; + + /* Some state is contained in constant objects. + * Other state is just parameter values. + */ + struct { + struct pipe_blend_state blend; + struct pipe_depth_stencil_alpha_state depth_stencil; + struct pipe_rasterizer_state rasterizer; + struct pipe_sampler_state samplers[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_state vertex_samplers[PIPE_MAX_VERTEX_SAMPLERS]; + struct pipe_clip_state clip; + struct { + void *ptr; + unsigned size; + } constants[PIPE_SHADER_TYPES]; + struct pipe_framebuffer_state framebuffer; + struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; + struct pipe_sampler_view *sampler_vertex_views[PIPE_MAX_VERTEX_SAMPLERS]; + struct pipe_scissor_state scissor; + struct pipe_viewport_state viewport; + unsigned sample_mask; + + GLuint num_samplers; + GLuint num_vertex_samplers; + GLuint num_textures; + GLuint num_vertex_textures; + + GLuint poly_stipple[32]; /**< In OpenGL's bottom-to-top order */ + } state; + + char vendor[100]; + char renderer[100]; + + struct st_state_flags dirty; + + GLboolean missing_textures; + GLboolean vertdata_edgeflags; + + /** Mapping from VERT_RESULT_x to post-transformed vertex slot */ + const GLuint *vertex_result_to_slot; + + struct st_vertex_program *vp; /**< Currently bound vertex program */ + struct st_fragment_program *fp; /**< Currently bound fragment program */ + struct st_geometry_program *gp; /**< Currently bound geometry program */ + + struct st_vp_variant *vp_variant; + struct st_fp_variant *fp_variant; + struct st_gp_variant *gp_variant; + + struct gl_texture_object *default_texture; + + struct { + struct gl_program_cache *cache; + struct st_fragment_program *program; /**< cur pixel transfer prog */ + GLuint xfer_prog_sn; /**< pixel xfer program serial no. */ + GLuint user_prog_sn; /**< user fragment program serial no. */ + struct st_fragment_program *combined_prog; + GLuint combined_prog_sn; + struct pipe_resource *pixelmap_texture; + struct pipe_sampler_view *pixelmap_sampler_view; + boolean pixelmap_enabled; /**< use the pixelmap texture? */ + } pixel_xfer; + + /** for glBitmap */ + struct { + struct pipe_rasterizer_state rasterizer; + struct pipe_sampler_state samplers[2]; + enum pipe_format tex_format; + void *vs; + float vertices[4][3][4]; /**< vertex pos + color + texcoord */ + struct pipe_resource *vbuf; + unsigned vbuf_slot; /* next free slot in vbuf */ + struct bitmap_cache *cache; + } bitmap; + + /** for glDraw/CopyPixels */ + struct { + struct gl_fragment_program *shaders[4]; + void *vert_shaders[2]; /**< ureg shaders */ + } drawpix; + + /** for glClear */ + struct { + struct pipe_rasterizer_state raster; + struct pipe_viewport_state viewport; + struct pipe_clip_state clip; + void *vs; + void *fs; + float vertices[4][2][4]; /**< vertex pos + color */ + struct pipe_resource *vbuf; + unsigned vbuf_slot; + boolean enable_ds_separate; + } clear; + + /** used for anything using util_draw_vertex_buffer */ + struct pipe_vertex_element velems_util_draw[3]; + + void *passthrough_fs; /**< simple pass-through frag shader */ + + enum pipe_texture_target internal_target; + struct gen_mipmap_state *gen_mipmap; + struct blit_state *blit; + + struct cso_context *cso_context; + + int force_msaa; + void *winsys_drawable_handle; + + /* User vertex buffers. */ + struct { + struct pipe_resource *buffer; + + /** Element size */ + GLuint element_size; + + /** Attribute stride */ + GLsizei stride; + } user_attrib[PIPE_MAX_ATTRIBS]; + unsigned num_user_attribs; + + /* Active render condition. */ + struct pipe_query *render_condition; + unsigned condition_mode; + + int32_t draw_stamp; + int32_t read_stamp; +}; + + +/* Need this so that we can implement Mesa callbacks in this module. + */ +static INLINE struct st_context *st_context(struct gl_context *ctx) +{ + return ctx->st; +} + + +/** + * Wrapper for struct gl_framebuffer. + * This is an opaque type to the outside world. + */ +struct st_framebuffer +{ + struct gl_framebuffer Base; + void *Private; + + struct st_framebuffer_iface *iface; + enum st_attachment_type statts[ST_ATTACHMENT_COUNT]; + unsigned num_statts; + int32_t stamp; + int32_t iface_stamp; +}; + + +extern void st_init_driver_functions(struct dd_function_table *functions); + +void st_invalidate_state(struct gl_context * ctx, GLuint new_state); + + + +#define Y_0_TOP 1 +#define Y_0_BOTTOM 2 + +static INLINE GLuint +st_fb_orientation(const struct gl_framebuffer *fb) +{ + if (fb && fb->Name == 0) { + /* Drawing into a window (on-screen buffer). + * + * Negate Y scale to flip image vertically. + * The NDC Y coords prior to viewport transformation are in the range + * [y=-1=bottom, y=1=top] + * Hardware window coords are in the range [y=0=top, y=H-1=bottom] where + * H is the window height. + * Use the viewport transformation to invert Y. + */ + return Y_0_TOP; + } + else { + /* Drawing into user-created FBO (very likely a texture). + * + * For textures, T=0=Bottom, so by extension Y=0=Bottom for rendering. + */ + return Y_0_BOTTOM; + } +} + + +/** clear-alloc a struct-sized object, with casting */ +#define ST_CALLOC_STRUCT(T) (struct T *) calloc(1, sizeof(struct T)) + + +extern int +st_get_msaa(void); + +extern struct st_context * +st_create_context(gl_api api, struct pipe_context *pipe, + const struct gl_config *visual, + struct st_context *share); + +extern void +st_destroy_context(struct st_context *st); + + +#endif diff --git a/mesalib/src/mesa/state_tracker/st_draw.c b/mesalib/src/mesa/state_tracker/st_draw.c index 33e265f49..39a947df7 100644 --- a/mesalib/src/mesa/state_tracker/st_draw.c +++ b/mesalib/src/mesa/state_tracker/st_draw.c @@ -1,830 +1,830 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-/*
- * This file implements the st_draw_vbo() function which is called from
- * Mesa's VBO module. All point/line/triangle rendering is done through
- * this function whether the user called glBegin/End, glDrawArrays,
- * glDrawElements, glEvalMesh, or glCalList, etc.
- *
- * We basically convert the VBO's vertex attribute/array information into
- * Gallium vertex state, bind the vertex buffer objects and call
- * pipe->draw_vbo().
- *
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- */
-
-
-#include "main/imports.h"
-#include "main/image.h"
-#include "main/bufferobj.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-#include "program/prog_uniform.h"
-
-#include "vbo/vbo.h"
-
-#include "st_context.h"
-#include "st_atom.h"
-#include "st_cb_bufferobjects.h"
-#include "st_draw.h"
-#include "st_program.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "util/u_inlines.h"
-#include "util/u_format.h"
-#include "util/u_prim.h"
-#include "util/u_draw_quad.h"
-#include "draw/draw_context.h"
-#include "cso_cache/cso_context.h"
-
-
-static GLuint double_types[4] = {
- PIPE_FORMAT_R64_FLOAT,
- PIPE_FORMAT_R64G64_FLOAT,
- PIPE_FORMAT_R64G64B64_FLOAT,
- PIPE_FORMAT_R64G64B64A64_FLOAT
-};
-
-static GLuint float_types[4] = {
- PIPE_FORMAT_R32_FLOAT,
- PIPE_FORMAT_R32G32_FLOAT,
- PIPE_FORMAT_R32G32B32_FLOAT,
- PIPE_FORMAT_R32G32B32A32_FLOAT
-};
-
-static GLuint half_float_types[4] = {
- PIPE_FORMAT_R16_FLOAT,
- PIPE_FORMAT_R16G16_FLOAT,
- PIPE_FORMAT_R16G16B16_FLOAT,
- PIPE_FORMAT_R16G16B16A16_FLOAT
-};
-
-static GLuint uint_types_norm[4] = {
- PIPE_FORMAT_R32_UNORM,
- PIPE_FORMAT_R32G32_UNORM,
- PIPE_FORMAT_R32G32B32_UNORM,
- PIPE_FORMAT_R32G32B32A32_UNORM
-};
-
-static GLuint uint_types_scale[4] = {
- PIPE_FORMAT_R32_USCALED,
- PIPE_FORMAT_R32G32_USCALED,
- PIPE_FORMAT_R32G32B32_USCALED,
- PIPE_FORMAT_R32G32B32A32_USCALED
-};
-
-static GLuint int_types_norm[4] = {
- PIPE_FORMAT_R32_SNORM,
- PIPE_FORMAT_R32G32_SNORM,
- PIPE_FORMAT_R32G32B32_SNORM,
- PIPE_FORMAT_R32G32B32A32_SNORM
-};
-
-static GLuint int_types_scale[4] = {
- PIPE_FORMAT_R32_SSCALED,
- PIPE_FORMAT_R32G32_SSCALED,
- PIPE_FORMAT_R32G32B32_SSCALED,
- PIPE_FORMAT_R32G32B32A32_SSCALED
-};
-
-static GLuint ushort_types_norm[4] = {
- PIPE_FORMAT_R16_UNORM,
- PIPE_FORMAT_R16G16_UNORM,
- PIPE_FORMAT_R16G16B16_UNORM,
- PIPE_FORMAT_R16G16B16A16_UNORM
-};
-
-static GLuint ushort_types_scale[4] = {
- PIPE_FORMAT_R16_USCALED,
- PIPE_FORMAT_R16G16_USCALED,
- PIPE_FORMAT_R16G16B16_USCALED,
- PIPE_FORMAT_R16G16B16A16_USCALED
-};
-
-static GLuint short_types_norm[4] = {
- PIPE_FORMAT_R16_SNORM,
- PIPE_FORMAT_R16G16_SNORM,
- PIPE_FORMAT_R16G16B16_SNORM,
- PIPE_FORMAT_R16G16B16A16_SNORM
-};
-
-static GLuint short_types_scale[4] = {
- PIPE_FORMAT_R16_SSCALED,
- PIPE_FORMAT_R16G16_SSCALED,
- PIPE_FORMAT_R16G16B16_SSCALED,
- PIPE_FORMAT_R16G16B16A16_SSCALED
-};
-
-static GLuint ubyte_types_norm[4] = {
- PIPE_FORMAT_R8_UNORM,
- PIPE_FORMAT_R8G8_UNORM,
- PIPE_FORMAT_R8G8B8_UNORM,
- PIPE_FORMAT_R8G8B8A8_UNORM
-};
-
-static GLuint ubyte_types_scale[4] = {
- PIPE_FORMAT_R8_USCALED,
- PIPE_FORMAT_R8G8_USCALED,
- PIPE_FORMAT_R8G8B8_USCALED,
- PIPE_FORMAT_R8G8B8A8_USCALED
-};
-
-static GLuint byte_types_norm[4] = {
- PIPE_FORMAT_R8_SNORM,
- PIPE_FORMAT_R8G8_SNORM,
- PIPE_FORMAT_R8G8B8_SNORM,
- PIPE_FORMAT_R8G8B8A8_SNORM
-};
-
-static GLuint byte_types_scale[4] = {
- PIPE_FORMAT_R8_SSCALED,
- PIPE_FORMAT_R8G8_SSCALED,
- PIPE_FORMAT_R8G8B8_SSCALED,
- PIPE_FORMAT_R8G8B8A8_SSCALED
-};
-
-static GLuint fixed_types[4] = {
- PIPE_FORMAT_R32_FIXED,
- PIPE_FORMAT_R32G32_FIXED,
- PIPE_FORMAT_R32G32B32_FIXED,
- PIPE_FORMAT_R32G32B32A32_FIXED
-};
-
-
-
-/**
- * Return a PIPE_FORMAT_x for the given GL datatype and size.
- */
-enum pipe_format
-st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
- GLboolean normalized)
-{
- assert((type >= GL_BYTE && type <= GL_DOUBLE) ||
- type == GL_FIXED || type == GL_HALF_FLOAT ||
- type == GL_INT_2_10_10_10_REV ||
- type == GL_UNSIGNED_INT_2_10_10_10_REV);
- assert(size >= 1);
- assert(size <= 4);
- assert(format == GL_RGBA || format == GL_BGRA);
-
- if (type == GL_INT_2_10_10_10_REV ||
- type == GL_UNSIGNED_INT_2_10_10_10_REV) {
- assert(size == 4);
-
- if (format == GL_BGRA) {
- if (type == GL_INT_2_10_10_10_REV) {
- if (normalized)
- return PIPE_FORMAT_B10G10R10A2_SNORM;
- else
- return PIPE_FORMAT_B10G10R10A2_SSCALED;
- } else {
- if (normalized)
- return PIPE_FORMAT_B10G10R10A2_UNORM;
- else
- return PIPE_FORMAT_B10G10R10A2_USCALED;
- }
- } else {
- if (type == GL_INT_2_10_10_10_REV) {
- if (normalized)
- return PIPE_FORMAT_R10G10B10A2_SNORM;
- else
- return PIPE_FORMAT_R10G10B10A2_SSCALED;
- } else {
- if (normalized)
- return PIPE_FORMAT_R10G10B10A2_UNORM;
- else
- return PIPE_FORMAT_R10G10B10A2_USCALED;
- }
- }
- }
-
- if (format == GL_BGRA) {
- /* this is an odd-ball case */
- assert(type == GL_UNSIGNED_BYTE);
- assert(normalized);
- return PIPE_FORMAT_B8G8R8A8_UNORM;
- }
-
- if (normalized) {
- switch (type) {
- case GL_DOUBLE: return double_types[size-1];
- case GL_FLOAT: return float_types[size-1];
- case GL_HALF_FLOAT: return half_float_types[size-1];
- case GL_INT: return int_types_norm[size-1];
- case GL_SHORT: return short_types_norm[size-1];
- case GL_BYTE: return byte_types_norm[size-1];
- case GL_UNSIGNED_INT: return uint_types_norm[size-1];
- case GL_UNSIGNED_SHORT: return ushort_types_norm[size-1];
- case GL_UNSIGNED_BYTE: return ubyte_types_norm[size-1];
- case GL_FIXED: return fixed_types[size-1];
- default: assert(0); return 0;
- }
- }
- else {
- switch (type) {
- case GL_DOUBLE: return double_types[size-1];
- case GL_FLOAT: return float_types[size-1];
- case GL_HALF_FLOAT: return half_float_types[size-1];
- case GL_INT: return int_types_scale[size-1];
- case GL_SHORT: return short_types_scale[size-1];
- case GL_BYTE: return byte_types_scale[size-1];
- case GL_UNSIGNED_INT: return uint_types_scale[size-1];
- case GL_UNSIGNED_SHORT: return ushort_types_scale[size-1];
- case GL_UNSIGNED_BYTE: return ubyte_types_scale[size-1];
- case GL_FIXED: return fixed_types[size-1];
- default: assert(0); return 0;
- }
- }
- return PIPE_FORMAT_NONE; /* silence compiler warning */
-}
-
-
-/**
- * This is very similar to vbo_all_varyings_in_vbos() but we test
- * the stride. See bug 38626.
- */
-static GLboolean
-all_varyings_in_vbos(const struct gl_client_array *arrays[])
-{
- GLuint i;
-
- for (i = 0; i < VERT_ATTRIB_MAX; i++)
- if (arrays[i]->StrideB && !_mesa_is_bufferobj(arrays[i]->BufferObj))
- return GL_FALSE;
-
- return GL_TRUE;
-}
-
-
-/**
- * Examine the active arrays to determine if we have interleaved
- * vertex arrays all living in one VBO, or all living in user space.
- */
-static GLboolean
-is_interleaved_arrays(const struct st_vertex_program *vp,
- const struct st_vp_variant *vpv,
- const struct gl_client_array **arrays)
-{
- GLuint attr;
- const struct gl_buffer_object *firstBufObj = NULL;
- GLint firstStride = -1;
- const GLubyte *firstPtr = NULL;
- GLboolean userSpaceBuffer = GL_FALSE;
-
- for (attr = 0; attr < vpv->num_inputs; attr++) {
- const GLuint mesaAttr = vp->index_to_input[attr];
- const struct gl_client_array *array = arrays[mesaAttr];
- const struct gl_buffer_object *bufObj = array->BufferObj;
- const GLsizei stride = array->StrideB; /* in bytes */
-
- if (attr == 0) {
- /* save info about the first array */
- firstStride = stride;
- firstPtr = array->Ptr;
- firstBufObj = bufObj;
- userSpaceBuffer = !bufObj || !bufObj->Name;
- }
- else {
- /* check if other arrays interleave with the first, in same buffer */
- if (stride != firstStride)
- return GL_FALSE; /* strides don't match */
-
- if (bufObj != firstBufObj)
- return GL_FALSE; /* arrays in different VBOs */
-
- if (abs(array->Ptr - firstPtr) > firstStride)
- return GL_FALSE; /* arrays start too far apart */
-
- if ((!bufObj || !_mesa_is_bufferobj(bufObj)) != userSpaceBuffer)
- return GL_FALSE; /* mix of VBO and user-space arrays */
- }
- }
-
- return GL_TRUE;
-}
-
-
-/**
- * Set up for drawing interleaved arrays that all live in one VBO
- * or all live in user space.
- * \param vbuffer returns vertex buffer info
- * \param velements returns vertex element info
- */
-static void
-setup_interleaved_attribs(struct gl_context *ctx,
- const struct st_vertex_program *vp,
- const struct st_vp_variant *vpv,
- const struct gl_client_array **arrays,
- struct pipe_vertex_buffer *vbuffer,
- struct pipe_vertex_element velements[],
- unsigned max_index,
- unsigned num_instances)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- GLuint attr;
- const GLubyte *low_addr = NULL;
-
- /* Find the lowest address of the arrays we're drawing */
- if (vpv->num_inputs) {
- low_addr = arrays[vp->index_to_input[0]]->Ptr;
-
- for (attr = 1; attr < vpv->num_inputs; attr++) {
- const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr;
- low_addr = MIN2(low_addr, start);
- }
- }
-
- for (attr = 0; attr < vpv->num_inputs; attr++) {
- const GLuint mesaAttr = vp->index_to_input[attr];
- const struct gl_client_array *array = arrays[mesaAttr];
- struct gl_buffer_object *bufobj = array->BufferObj;
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
- unsigned src_offset = (unsigned) (array->Ptr - low_addr);
- GLuint element_size = array->_ElementSize;
- GLsizei stride = array->StrideB;
-
- assert(element_size == array->Size * _mesa_sizeof_type(array->Type));
-
- if (attr == 0) {
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
- vbuffer->buffer = NULL;
- pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
- vbuffer->buffer_offset = pointer_to_offset(low_addr);
- }
- else {
- uint divisor = array->InstanceDivisor;
- uint last_index = divisor ? num_instances / divisor : max_index;
- uint bytes = src_offset + stride * last_index + element_size;
-
- vbuffer->buffer = pipe_user_buffer_create(pipe->screen,
- (void*) low_addr,
- bytes,
- PIPE_BIND_VERTEX_BUFFER);
- vbuffer->buffer_offset = 0;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_attrib[0].buffer, vbuffer->buffer);
- st->user_attrib[0].element_size = element_size;
- st->user_attrib[0].stride = stride;
- st->num_user_attribs = 1;
- }
- vbuffer->stride = stride; /* in bytes */
- }
-
- velements[attr].src_offset = src_offset;
- velements[attr].instance_divisor = array->InstanceDivisor;
- velements[attr].vertex_buffer_index = 0;
- velements[attr].src_format = st_pipe_vertex_format(array->Type,
- array->Size,
- array->Format,
- array->Normalized);
- assert(velements[attr].src_format);
- }
-}
-
-
-/**
- * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each
- * vertex attribute.
- * \param vbuffer returns vertex buffer info
- * \param velements returns vertex element info
- */
-static void
-setup_non_interleaved_attribs(struct gl_context *ctx,
- const struct st_vertex_program *vp,
- const struct st_vp_variant *vpv,
- const struct gl_client_array **arrays,
- struct pipe_vertex_buffer vbuffer[],
- struct pipe_vertex_element velements[],
- unsigned max_index,
- unsigned num_instances)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- GLuint attr;
-
- for (attr = 0; attr < vpv->num_inputs; attr++) {
- const GLuint mesaAttr = vp->index_to_input[attr];
- const struct gl_client_array *array = arrays[mesaAttr];
- struct gl_buffer_object *bufobj = array->BufferObj;
- GLuint element_size = array->_ElementSize;
- GLsizei stride = array->StrideB;
-
- assert(element_size == array->Size * _mesa_sizeof_type(array->Type));
-
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
- /* Attribute data is in a VBO.
- * Recall that for VBOs, the gl_client_array->Ptr field is
- * really an offset from the start of the VBO, not a pointer.
- */
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
- assert(stobj->buffer);
-
- vbuffer[attr].buffer = NULL;
- pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer);
- vbuffer[attr].buffer_offset = pointer_to_offset(array->Ptr);
- }
- else {
- /* wrap user data */
- uint bytes;
- void *ptr;
-
- if (array->Ptr) {
- uint divisor = array->InstanceDivisor;
- uint last_index = divisor ? num_instances / divisor : max_index;
-
- bytes = stride * last_index + element_size;
-
- ptr = (void *) array->Ptr;
- }
- else {
- /* no array, use ctx->Current.Attrib[] value */
- bytes = element_size = sizeof(ctx->Current.Attrib[0]);
- ptr = (void *) ctx->Current.Attrib[mesaAttr];
- stride = 0;
- }
-
- assert(ptr);
- assert(bytes);
-
- vbuffer[attr].buffer =
- pipe_user_buffer_create(pipe->screen, ptr, bytes,
- PIPE_BIND_VERTEX_BUFFER);
-
- vbuffer[attr].buffer_offset = 0;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_attrib[attr].buffer, vbuffer[attr].buffer);
- st->user_attrib[attr].element_size = element_size;
- st->user_attrib[attr].stride = stride;
- st->num_user_attribs = MAX2(st->num_user_attribs, attr + 1);
- }
-
- /* common-case setup */
- vbuffer[attr].stride = stride; /* in bytes */
-
- velements[attr].src_offset = 0;
- velements[attr].instance_divisor = array->InstanceDivisor;
- velements[attr].vertex_buffer_index = attr;
- velements[attr].src_format = st_pipe_vertex_format(array->Type,
- array->Size,
- array->Format,
- array->Normalized);
- assert(velements[attr].src_format);
- }
-}
-
-
-static void
-setup_index_buffer(struct gl_context *ctx,
- const struct _mesa_index_buffer *ib,
- struct pipe_index_buffer *ibuffer)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
-
- memset(ibuffer, 0, sizeof(*ibuffer));
- if (ib) {
- struct gl_buffer_object *bufobj = ib->obj;
-
- switch (ib->type) {
- case GL_UNSIGNED_INT:
- ibuffer->index_size = 4;
- break;
- case GL_UNSIGNED_SHORT:
- ibuffer->index_size = 2;
- break;
- case GL_UNSIGNED_BYTE:
- ibuffer->index_size = 1;
- break;
- default:
- assert(0);
- return;
- }
-
- /* get/create the index buffer object */
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
- /* elements/indexes are in a real VBO */
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
- pipe_resource_reference(&ibuffer->buffer, stobj->buffer);
- ibuffer->offset = pointer_to_offset(ib->ptr);
- }
- else {
- /* element/indicies are in user space memory */
- ibuffer->buffer =
- pipe_user_buffer_create(pipe->screen, (void *) ib->ptr,
- ib->count * ibuffer->index_size,
- PIPE_BIND_INDEX_BUFFER);
- }
- }
-}
-
-
-/**
- * Prior to drawing, check that any uniforms referenced by the
- * current shader have been set. If a uniform has not been set,
- * issue a warning.
- */
-static void
-check_uniforms(struct gl_context *ctx)
-{
- struct gl_shader_program *shProg[3] = {
- ctx->Shader.CurrentVertexProgram,
- ctx->Shader.CurrentGeometryProgram,
- ctx->Shader.CurrentFragmentProgram,
- };
- unsigned j;
-
- for (j = 0; j < 3; j++) {
- unsigned i;
-
- if (shProg[j] == NULL || !shProg[j]->LinkStatus)
- continue;
-
- for (i = 0; i < shProg[j]->Uniforms->NumUniforms; i++) {
- const struct gl_uniform *u = &shProg[j]->Uniforms->Uniforms[i];
- if (!u->Initialized) {
- _mesa_warning(ctx,
- "Using shader with uninitialized uniform: %s",
- u->Name);
- }
- }
- }
-}
-
-
-/**
- * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to
- * the corresponding Gallium type.
- */
-static unsigned
-translate_prim(const struct gl_context *ctx, unsigned prim)
-{
- /* GL prims should match Gallium prims, spot-check a few */
- assert(GL_POINTS == PIPE_PRIM_POINTS);
- assert(GL_QUADS == PIPE_PRIM_QUADS);
- assert(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
-
- /* Avoid quadstrips if it's easy to do so:
- * Note: it's important to do the correct trimming if we change the
- * prim type! We do that wherever this function is called.
- */
- if (prim == GL_QUAD_STRIP &&
- ctx->Light.ShadeModel != GL_FLAT &&
- ctx->Polygon.FrontMode == GL_FILL &&
- ctx->Polygon.BackMode == GL_FILL)
- prim = GL_TRIANGLE_STRIP;
-
- return prim;
-}
-
-
-static void
-st_validate_varrays(struct gl_context *ctx,
- const struct gl_client_array **arrays,
- unsigned max_index,
- unsigned num_instances)
-{
- struct st_context *st = st_context(ctx);
- const struct st_vertex_program *vp;
- const struct st_vp_variant *vpv;
- struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
- struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
- unsigned num_vbuffers, num_velements;
- GLuint attr;
- unsigned i;
-
- /* must get these after state validation! */
- vp = st->vp;
- vpv = st->vp_variant;
-
- memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs);
-
- /* Unreference any user vertex buffers. */
- for (i = 0; i < st->num_user_attribs; i++) {
- pipe_resource_reference(&st->user_attrib[i].buffer, NULL);
- }
- st->num_user_attribs = 0;
-
- /*
- * Setup the vbuffer[] and velements[] arrays.
- */
- if (is_interleaved_arrays(vp, vpv, arrays)) {
- setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements,
- max_index, num_instances);
-
- num_vbuffers = 1;
- num_velements = vpv->num_inputs;
- if (num_velements == 0)
- num_vbuffers = 0;
- }
- else {
- setup_non_interleaved_attribs(ctx, vp, vpv, arrays,
- vbuffer, velements, max_index,
- num_instances);
- num_vbuffers = vpv->num_inputs;
- num_velements = vpv->num_inputs;
- }
-
- cso_set_vertex_buffers(st->cso_context, num_vbuffers, vbuffer);
- cso_set_vertex_elements(st->cso_context, num_velements, velements);
-
- /* unreference buffers (frees wrapped user-space buffer objects)
- * This is OK, because the pipe driver should reference buffers by itself
- * in set_vertex_buffers. */
- for (attr = 0; attr < num_vbuffers; attr++) {
- pipe_resource_reference(&vbuffer[attr].buffer, NULL);
- assert(!vbuffer[attr].buffer);
- }
-}
-
-
-/**
- * This function gets plugged into the VBO module and is called when
- * we have something to render.
- * Basically, translate the information into the format expected by gallium.
- */
-void
-st_draw_vbo(struct gl_context *ctx,
- const struct gl_client_array **arrays,
- const struct _mesa_prim *prims,
- GLuint nr_prims,
- const struct _mesa_index_buffer *ib,
- GLboolean index_bounds_valid,
- GLuint min_index,
- GLuint max_index)
-{
- struct st_context *st = st_context(ctx);
- struct pipe_context *pipe = st->pipe;
- struct pipe_index_buffer ibuffer;
- struct pipe_draw_info info;
- unsigned i, num_instances = 1;
- GLboolean new_array =
- st->dirty.st &&
- (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) != 0;
-
- /* Mesa core state should have been validated already */
- assert(ctx->NewState == 0x0);
-
- if (ib) {
- /* Gallium probably doesn't want this in some cases. */
- if (!index_bounds_valid)
- if (!all_varyings_in_vbos(arrays))
- vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
-
- for (i = 0; i < nr_prims; i++) {
- num_instances = MAX2(num_instances, prims[i].num_instances);
- }
- }
- else {
- /* Get min/max index for non-indexed drawing. */
- min_index = ~0;
- max_index = 0;
-
- for (i = 0; i < nr_prims; i++) {
- min_index = MIN2(min_index, prims[i].start);
- max_index = MAX2(max_index, prims[i].start + prims[i].count - 1);
- num_instances = MAX2(num_instances, prims[i].num_instances);
- }
- }
-
- /* Validate state. */
- if (st->dirty.st) {
- GLboolean vertDataEdgeFlags;
-
- /* sanity check for pointer arithmetic below */
- assert(sizeof(arrays[0]->Ptr[0]) == 1);
-
- vertDataEdgeFlags = arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj &&
- arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj->Name;
- if (vertDataEdgeFlags != st->vertdata_edgeflags) {
- st->vertdata_edgeflags = vertDataEdgeFlags;
- st->dirty.st |= ST_NEW_EDGEFLAGS_DATA;
- }
-
- st_validate_state(st);
-
- if (new_array) {
- st_validate_varrays(ctx, arrays, max_index, num_instances);
- }
-
-#if 0
- if (MESA_VERBOSE & VERBOSE_GLSL) {
- check_uniforms(ctx);
- }
-#else
- (void) check_uniforms;
-#endif
- }
-
- /* Notify the driver that the content of user buffers may have been
- * changed. */
- assert(max_index >= min_index);
- if (!new_array && st->num_user_attribs) {
- for (i = 0; i < st->num_user_attribs; i++) {
- if (st->user_attrib[i].buffer) {
- unsigned element_size = st->user_attrib[i].element_size;
- unsigned stride = st->user_attrib[i].stride;
- unsigned min_offset = min_index * stride;
- unsigned max_offset = max_index * stride + element_size;
-
- assert(max_offset > min_offset);
-
- pipe->redefine_user_buffer(pipe, st->user_attrib[i].buffer,
- min_offset,
- max_offset - min_offset);
- }
- }
- }
-
- setup_index_buffer(ctx, ib, &ibuffer);
- pipe->set_index_buffer(pipe, &ibuffer);
-
- util_draw_init_info(&info);
- if (ib) {
- info.indexed = TRUE;
- if (min_index != ~0 && max_index != ~0) {
- info.min_index = min_index;
- info.max_index = max_index;
- }
- }
-
- info.primitive_restart = ctx->Array.PrimitiveRestart;
- info.restart_index = ctx->Array.RestartIndex;
-
- /* do actual drawing */
- for (i = 0; i < nr_prims; i++) {
- info.mode = translate_prim( ctx, prims[i].mode );
- info.start = prims[i].start;
- info.count = prims[i].count;
- info.instance_count = prims[i].num_instances;
- info.index_bias = prims[i].basevertex;
- if (!ib) {
- info.min_index = info.start;
- info.max_index = info.start + info.count - 1;
- }
-
- if (u_trim_pipe_prim(info.mode, &info.count))
- pipe->draw_vbo(pipe, &info);
- }
-
- pipe_resource_reference(&ibuffer.buffer, NULL);
-}
-
-
-void
-st_init_draw(struct st_context *st)
-{
- struct gl_context *ctx = st->ctx;
-
- vbo_set_draw_func(ctx, st_draw_vbo);
-
-#if FEATURE_feedback || FEATURE_rastpos
- st->draw = draw_create(st->pipe); /* for selection/feedback */
-
- /* Disable draw options that might convert points/lines to tris, etc.
- * as that would foul-up feedback/selection mode.
- */
- draw_wide_line_threshold(st->draw, 1000.0f);
- draw_wide_point_threshold(st->draw, 1000.0f);
- draw_enable_line_stipple(st->draw, FALSE);
- draw_enable_point_sprites(st->draw, FALSE);
-#endif
-}
-
-
-void
-st_destroy_draw(struct st_context *st)
-{
-#if FEATURE_feedback || FEATURE_rastpos
- draw_destroy(st->draw);
-#endif
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + +/* + * This file implements the st_draw_vbo() function which is called from + * Mesa's VBO module. All point/line/triangle rendering is done through + * this function whether the user called glBegin/End, glDrawArrays, + * glDrawElements, glEvalMesh, or glCalList, etc. + * + * We basically convert the VBO's vertex attribute/array information into + * Gallium vertex state, bind the vertex buffer objects and call + * pipe->draw_vbo(). + * + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#include "main/imports.h" +#include "main/image.h" +#include "main/bufferobj.h" +#include "main/macros.h" +#include "main/mfeatures.h" +#include "program/prog_uniform.h" + +#include "vbo/vbo.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_cb_bufferobjects.h" +#include "st_draw.h" +#include "st_program.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "util/u_prim.h" +#include "util/u_draw_quad.h" +#include "draw/draw_context.h" +#include "cso_cache/cso_context.h" + + +static GLuint double_types[4] = { + PIPE_FORMAT_R64_FLOAT, + PIPE_FORMAT_R64G64_FLOAT, + PIPE_FORMAT_R64G64B64_FLOAT, + PIPE_FORMAT_R64G64B64A64_FLOAT +}; + +static GLuint float_types[4] = { + PIPE_FORMAT_R32_FLOAT, + PIPE_FORMAT_R32G32_FLOAT, + PIPE_FORMAT_R32G32B32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT +}; + +static GLuint half_float_types[4] = { + PIPE_FORMAT_R16_FLOAT, + PIPE_FORMAT_R16G16_FLOAT, + PIPE_FORMAT_R16G16B16_FLOAT, + PIPE_FORMAT_R16G16B16A16_FLOAT +}; + +static GLuint uint_types_norm[4] = { + PIPE_FORMAT_R32_UNORM, + PIPE_FORMAT_R32G32_UNORM, + PIPE_FORMAT_R32G32B32_UNORM, + PIPE_FORMAT_R32G32B32A32_UNORM +}; + +static GLuint uint_types_scale[4] = { + PIPE_FORMAT_R32_USCALED, + PIPE_FORMAT_R32G32_USCALED, + PIPE_FORMAT_R32G32B32_USCALED, + PIPE_FORMAT_R32G32B32A32_USCALED +}; + +static GLuint int_types_norm[4] = { + PIPE_FORMAT_R32_SNORM, + PIPE_FORMAT_R32G32_SNORM, + PIPE_FORMAT_R32G32B32_SNORM, + PIPE_FORMAT_R32G32B32A32_SNORM +}; + +static GLuint int_types_scale[4] = { + PIPE_FORMAT_R32_SSCALED, + PIPE_FORMAT_R32G32_SSCALED, + PIPE_FORMAT_R32G32B32_SSCALED, + PIPE_FORMAT_R32G32B32A32_SSCALED +}; + +static GLuint ushort_types_norm[4] = { + PIPE_FORMAT_R16_UNORM, + PIPE_FORMAT_R16G16_UNORM, + PIPE_FORMAT_R16G16B16_UNORM, + PIPE_FORMAT_R16G16B16A16_UNORM +}; + +static GLuint ushort_types_scale[4] = { + PIPE_FORMAT_R16_USCALED, + PIPE_FORMAT_R16G16_USCALED, + PIPE_FORMAT_R16G16B16_USCALED, + PIPE_FORMAT_R16G16B16A16_USCALED +}; + +static GLuint short_types_norm[4] = { + PIPE_FORMAT_R16_SNORM, + PIPE_FORMAT_R16G16_SNORM, + PIPE_FORMAT_R16G16B16_SNORM, + PIPE_FORMAT_R16G16B16A16_SNORM +}; + +static GLuint short_types_scale[4] = { + PIPE_FORMAT_R16_SSCALED, + PIPE_FORMAT_R16G16_SSCALED, + PIPE_FORMAT_R16G16B16_SSCALED, + PIPE_FORMAT_R16G16B16A16_SSCALED +}; + +static GLuint ubyte_types_norm[4] = { + PIPE_FORMAT_R8_UNORM, + PIPE_FORMAT_R8G8_UNORM, + PIPE_FORMAT_R8G8B8_UNORM, + PIPE_FORMAT_R8G8B8A8_UNORM +}; + +static GLuint ubyte_types_scale[4] = { + PIPE_FORMAT_R8_USCALED, + PIPE_FORMAT_R8G8_USCALED, + PIPE_FORMAT_R8G8B8_USCALED, + PIPE_FORMAT_R8G8B8A8_USCALED +}; + +static GLuint byte_types_norm[4] = { + PIPE_FORMAT_R8_SNORM, + PIPE_FORMAT_R8G8_SNORM, + PIPE_FORMAT_R8G8B8_SNORM, + PIPE_FORMAT_R8G8B8A8_SNORM +}; + +static GLuint byte_types_scale[4] = { + PIPE_FORMAT_R8_SSCALED, + PIPE_FORMAT_R8G8_SSCALED, + PIPE_FORMAT_R8G8B8_SSCALED, + PIPE_FORMAT_R8G8B8A8_SSCALED +}; + +static GLuint fixed_types[4] = { + PIPE_FORMAT_R32_FIXED, + PIPE_FORMAT_R32G32_FIXED, + PIPE_FORMAT_R32G32B32_FIXED, + PIPE_FORMAT_R32G32B32A32_FIXED +}; + + + +/** + * Return a PIPE_FORMAT_x for the given GL datatype and size. + */ +enum pipe_format +st_pipe_vertex_format(GLenum type, GLuint size, GLenum format, + GLboolean normalized) +{ + assert((type >= GL_BYTE && type <= GL_DOUBLE) || + type == GL_FIXED || type == GL_HALF_FLOAT || + type == GL_INT_2_10_10_10_REV || + type == GL_UNSIGNED_INT_2_10_10_10_REV); + assert(size >= 1); + assert(size <= 4); + assert(format == GL_RGBA || format == GL_BGRA); + + if (type == GL_INT_2_10_10_10_REV || + type == GL_UNSIGNED_INT_2_10_10_10_REV) { + assert(size == 4); + + if (format == GL_BGRA) { + if (type == GL_INT_2_10_10_10_REV) { + if (normalized) + return PIPE_FORMAT_B10G10R10A2_SNORM; + else + return PIPE_FORMAT_B10G10R10A2_SSCALED; + } else { + if (normalized) + return PIPE_FORMAT_B10G10R10A2_UNORM; + else + return PIPE_FORMAT_B10G10R10A2_USCALED; + } + } else { + if (type == GL_INT_2_10_10_10_REV) { + if (normalized) + return PIPE_FORMAT_R10G10B10A2_SNORM; + else + return PIPE_FORMAT_R10G10B10A2_SSCALED; + } else { + if (normalized) + return PIPE_FORMAT_R10G10B10A2_UNORM; + else + return PIPE_FORMAT_R10G10B10A2_USCALED; + } + } + } + + if (format == GL_BGRA) { + /* this is an odd-ball case */ + assert(type == GL_UNSIGNED_BYTE); + assert(normalized); + return PIPE_FORMAT_B8G8R8A8_UNORM; + } + + if (normalized) { + switch (type) { + case GL_DOUBLE: return double_types[size-1]; + case GL_FLOAT: return float_types[size-1]; + case GL_HALF_FLOAT: return half_float_types[size-1]; + case GL_INT: return int_types_norm[size-1]; + case GL_SHORT: return short_types_norm[size-1]; + case GL_BYTE: return byte_types_norm[size-1]; + case GL_UNSIGNED_INT: return uint_types_norm[size-1]; + case GL_UNSIGNED_SHORT: return ushort_types_norm[size-1]; + case GL_UNSIGNED_BYTE: return ubyte_types_norm[size-1]; + case GL_FIXED: return fixed_types[size-1]; + default: assert(0); return 0; + } + } + else { + switch (type) { + case GL_DOUBLE: return double_types[size-1]; + case GL_FLOAT: return float_types[size-1]; + case GL_HALF_FLOAT: return half_float_types[size-1]; + case GL_INT: return int_types_scale[size-1]; + case GL_SHORT: return short_types_scale[size-1]; + case GL_BYTE: return byte_types_scale[size-1]; + case GL_UNSIGNED_INT: return uint_types_scale[size-1]; + case GL_UNSIGNED_SHORT: return ushort_types_scale[size-1]; + case GL_UNSIGNED_BYTE: return ubyte_types_scale[size-1]; + case GL_FIXED: return fixed_types[size-1]; + default: assert(0); return 0; + } + } + return PIPE_FORMAT_NONE; /* silence compiler warning */ +} + + +/** + * This is very similar to vbo_all_varyings_in_vbos() but we test + * the stride. See bug 38626. + */ +static GLboolean +all_varyings_in_vbos(const struct gl_client_array *arrays[]) +{ + GLuint i; + + for (i = 0; i < VERT_ATTRIB_MAX; i++) + if (arrays[i]->StrideB && !_mesa_is_bufferobj(arrays[i]->BufferObj)) + return GL_FALSE; + + return GL_TRUE; +} + + +/** + * Examine the active arrays to determine if we have interleaved + * vertex arrays all living in one VBO, or all living in user space. + */ +static GLboolean +is_interleaved_arrays(const struct st_vertex_program *vp, + const struct st_vp_variant *vpv, + const struct gl_client_array **arrays) +{ + GLuint attr; + const struct gl_buffer_object *firstBufObj = NULL; + GLint firstStride = -1; + const GLubyte *firstPtr = NULL; + GLboolean userSpaceBuffer = GL_FALSE; + + for (attr = 0; attr < vpv->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const struct gl_client_array *array = arrays[mesaAttr]; + const struct gl_buffer_object *bufObj = array->BufferObj; + const GLsizei stride = array->StrideB; /* in bytes */ + + if (attr == 0) { + /* save info about the first array */ + firstStride = stride; + firstPtr = array->Ptr; + firstBufObj = bufObj; + userSpaceBuffer = !bufObj || !bufObj->Name; + } + else { + /* check if other arrays interleave with the first, in same buffer */ + if (stride != firstStride) + return GL_FALSE; /* strides don't match */ + + if (bufObj != firstBufObj) + return GL_FALSE; /* arrays in different VBOs */ + + if (abs(array->Ptr - firstPtr) > firstStride) + return GL_FALSE; /* arrays start too far apart */ + + if ((!bufObj || !_mesa_is_bufferobj(bufObj)) != userSpaceBuffer) + return GL_FALSE; /* mix of VBO and user-space arrays */ + } + } + + return GL_TRUE; +} + + +/** + * Set up for drawing interleaved arrays that all live in one VBO + * or all live in user space. + * \param vbuffer returns vertex buffer info + * \param velements returns vertex element info + */ +static void +setup_interleaved_attribs(struct gl_context *ctx, + const struct st_vertex_program *vp, + const struct st_vp_variant *vpv, + const struct gl_client_array **arrays, + struct pipe_vertex_buffer *vbuffer, + struct pipe_vertex_element velements[], + unsigned max_index, + unsigned num_instances) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLuint attr; + const GLubyte *low_addr = NULL; + + /* Find the lowest address of the arrays we're drawing */ + if (vpv->num_inputs) { + low_addr = arrays[vp->index_to_input[0]]->Ptr; + + for (attr = 1; attr < vpv->num_inputs; attr++) { + const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr; + low_addr = MIN2(low_addr, start); + } + } + + for (attr = 0; attr < vpv->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const struct gl_client_array *array = arrays[mesaAttr]; + struct gl_buffer_object *bufobj = array->BufferObj; + struct st_buffer_object *stobj = st_buffer_object(bufobj); + unsigned src_offset = (unsigned) (array->Ptr - low_addr); + GLuint element_size = array->_ElementSize; + GLsizei stride = array->StrideB; + + assert(element_size == array->Size * _mesa_sizeof_type(array->Type)); + + if (attr == 0) { + if (bufobj && _mesa_is_bufferobj(bufobj)) { + vbuffer->buffer = NULL; + pipe_resource_reference(&vbuffer->buffer, stobj->buffer); + vbuffer->buffer_offset = pointer_to_offset(low_addr); + } + else { + uint divisor = array->InstanceDivisor; + uint last_index = divisor ? num_instances / divisor : max_index; + uint bytes = src_offset + stride * last_index + element_size; + + vbuffer->buffer = pipe_user_buffer_create(pipe->screen, + (void*) low_addr, + bytes, + PIPE_BIND_VERTEX_BUFFER); + vbuffer->buffer_offset = 0; + + /* Track user vertex buffers. */ + pipe_resource_reference(&st->user_attrib[0].buffer, vbuffer->buffer); + st->user_attrib[0].element_size = element_size; + st->user_attrib[0].stride = stride; + st->num_user_attribs = 1; + } + vbuffer->stride = stride; /* in bytes */ + } + + velements[attr].src_offset = src_offset; + velements[attr].instance_divisor = array->InstanceDivisor; + velements[attr].vertex_buffer_index = 0; + velements[attr].src_format = st_pipe_vertex_format(array->Type, + array->Size, + array->Format, + array->Normalized); + assert(velements[attr].src_format); + } +} + + +/** + * Set up a separate pipe_vertex_buffer and pipe_vertex_element for each + * vertex attribute. + * \param vbuffer returns vertex buffer info + * \param velements returns vertex element info + */ +static void +setup_non_interleaved_attribs(struct gl_context *ctx, + const struct st_vertex_program *vp, + const struct st_vp_variant *vpv, + const struct gl_client_array **arrays, + struct pipe_vertex_buffer vbuffer[], + struct pipe_vertex_element velements[], + unsigned max_index, + unsigned num_instances) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLuint attr; + + for (attr = 0; attr < vpv->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const struct gl_client_array *array = arrays[mesaAttr]; + struct gl_buffer_object *bufobj = array->BufferObj; + GLuint element_size = array->_ElementSize; + GLsizei stride = array->StrideB; + + assert(element_size == array->Size * _mesa_sizeof_type(array->Type)); + + if (bufobj && _mesa_is_bufferobj(bufobj)) { + /* Attribute data is in a VBO. + * Recall that for VBOs, the gl_client_array->Ptr field is + * really an offset from the start of the VBO, not a pointer. + */ + struct st_buffer_object *stobj = st_buffer_object(bufobj); + assert(stobj->buffer); + + vbuffer[attr].buffer = NULL; + pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer); + vbuffer[attr].buffer_offset = pointer_to_offset(array->Ptr); + } + else { + /* wrap user data */ + uint bytes; + void *ptr; + + if (array->Ptr) { + uint divisor = array->InstanceDivisor; + uint last_index = divisor ? num_instances / divisor : max_index; + + bytes = stride * last_index + element_size; + + ptr = (void *) array->Ptr; + } + else { + /* no array, use ctx->Current.Attrib[] value */ + bytes = element_size = sizeof(ctx->Current.Attrib[0]); + ptr = (void *) ctx->Current.Attrib[mesaAttr]; + stride = 0; + } + + assert(ptr); + assert(bytes); + + vbuffer[attr].buffer = + pipe_user_buffer_create(pipe->screen, ptr, bytes, + PIPE_BIND_VERTEX_BUFFER); + + vbuffer[attr].buffer_offset = 0; + + /* Track user vertex buffers. */ + pipe_resource_reference(&st->user_attrib[attr].buffer, vbuffer[attr].buffer); + st->user_attrib[attr].element_size = element_size; + st->user_attrib[attr].stride = stride; + st->num_user_attribs = MAX2(st->num_user_attribs, attr + 1); + } + + /* common-case setup */ + vbuffer[attr].stride = stride; /* in bytes */ + + velements[attr].src_offset = 0; + velements[attr].instance_divisor = array->InstanceDivisor; + velements[attr].vertex_buffer_index = attr; + velements[attr].src_format = st_pipe_vertex_format(array->Type, + array->Size, + array->Format, + array->Normalized); + assert(velements[attr].src_format); + } +} + + +static void +setup_index_buffer(struct gl_context *ctx, + const struct _mesa_index_buffer *ib, + struct pipe_index_buffer *ibuffer) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + + memset(ibuffer, 0, sizeof(*ibuffer)); + if (ib) { + struct gl_buffer_object *bufobj = ib->obj; + + switch (ib->type) { + case GL_UNSIGNED_INT: + ibuffer->index_size = 4; + break; + case GL_UNSIGNED_SHORT: + ibuffer->index_size = 2; + break; + case GL_UNSIGNED_BYTE: + ibuffer->index_size = 1; + break; + default: + assert(0); + return; + } + + /* get/create the index buffer object */ + if (bufobj && _mesa_is_bufferobj(bufobj)) { + /* elements/indexes are in a real VBO */ + struct st_buffer_object *stobj = st_buffer_object(bufobj); + pipe_resource_reference(&ibuffer->buffer, stobj->buffer); + ibuffer->offset = pointer_to_offset(ib->ptr); + } + else { + /* element/indicies are in user space memory */ + ibuffer->buffer = + pipe_user_buffer_create(pipe->screen, (void *) ib->ptr, + ib->count * ibuffer->index_size, + PIPE_BIND_INDEX_BUFFER); + } + } +} + + +/** + * Prior to drawing, check that any uniforms referenced by the + * current shader have been set. If a uniform has not been set, + * issue a warning. + */ +static void +check_uniforms(struct gl_context *ctx) +{ + struct gl_shader_program *shProg[3] = { + ctx->Shader.CurrentVertexProgram, + ctx->Shader.CurrentGeometryProgram, + ctx->Shader.CurrentFragmentProgram, + }; + unsigned j; + + for (j = 0; j < 3; j++) { + unsigned i; + + if (shProg[j] == NULL || !shProg[j]->LinkStatus) + continue; + + for (i = 0; i < shProg[j]->Uniforms->NumUniforms; i++) { + const struct gl_uniform *u = &shProg[j]->Uniforms->Uniforms[i]; + if (!u->Initialized) { + _mesa_warning(ctx, + "Using shader with uninitialized uniform: %s", + u->Name); + } + } + } +} + + +/** + * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to + * the corresponding Gallium type. + */ +static unsigned +translate_prim(const struct gl_context *ctx, unsigned prim) +{ + /* GL prims should match Gallium prims, spot-check a few */ + assert(GL_POINTS == PIPE_PRIM_POINTS); + assert(GL_QUADS == PIPE_PRIM_QUADS); + assert(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY); + + /* Avoid quadstrips if it's easy to do so: + * Note: it's important to do the correct trimming if we change the + * prim type! We do that wherever this function is called. + */ + if (prim == GL_QUAD_STRIP && + ctx->Light.ShadeModel != GL_FLAT && + ctx->Polygon.FrontMode == GL_FILL && + ctx->Polygon.BackMode == GL_FILL) + prim = GL_TRIANGLE_STRIP; + + return prim; +} + + +static void +st_validate_varrays(struct gl_context *ctx, + const struct gl_client_array **arrays, + unsigned max_index, + unsigned num_instances) +{ + struct st_context *st = st_context(ctx); + const struct st_vertex_program *vp; + const struct st_vp_variant *vpv; + struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS]; + struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; + unsigned num_vbuffers, num_velements; + GLuint attr; + unsigned i; + + /* must get these after state validation! */ + vp = st->vp; + vpv = st->vp_variant; + + memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs); + + /* Unreference any user vertex buffers. */ + for (i = 0; i < st->num_user_attribs; i++) { + pipe_resource_reference(&st->user_attrib[i].buffer, NULL); + } + st->num_user_attribs = 0; + + /* + * Setup the vbuffer[] and velements[] arrays. + */ + if (is_interleaved_arrays(vp, vpv, arrays)) { + setup_interleaved_attribs(ctx, vp, vpv, arrays, vbuffer, velements, + max_index, num_instances); + + num_vbuffers = 1; + num_velements = vpv->num_inputs; + if (num_velements == 0) + num_vbuffers = 0; + } + else { + setup_non_interleaved_attribs(ctx, vp, vpv, arrays, + vbuffer, velements, max_index, + num_instances); + num_vbuffers = vpv->num_inputs; + num_velements = vpv->num_inputs; + } + + cso_set_vertex_buffers(st->cso_context, num_vbuffers, vbuffer); + cso_set_vertex_elements(st->cso_context, num_velements, velements); + + /* unreference buffers (frees wrapped user-space buffer objects) + * This is OK, because the pipe driver should reference buffers by itself + * in set_vertex_buffers. */ + for (attr = 0; attr < num_vbuffers; attr++) { + pipe_resource_reference(&vbuffer[attr].buffer, NULL); + assert(!vbuffer[attr].buffer); + } +} + + +/** + * This function gets plugged into the VBO module and is called when + * we have something to render. + * Basically, translate the information into the format expected by gallium. + */ +void +st_draw_vbo(struct gl_context *ctx, + const struct gl_client_array **arrays, + const struct _mesa_prim *prims, + GLuint nr_prims, + const struct _mesa_index_buffer *ib, + GLboolean index_bounds_valid, + GLuint min_index, + GLuint max_index) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_index_buffer ibuffer; + struct pipe_draw_info info; + unsigned i, num_instances = 1; + GLboolean new_array = + st->dirty.st && + (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) != 0; + + /* Mesa core state should have been validated already */ + assert(ctx->NewState == 0x0); + + if (ib) { + /* Gallium probably doesn't want this in some cases. */ + if (!index_bounds_valid) + if (!all_varyings_in_vbos(arrays)) + vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); + + for (i = 0; i < nr_prims; i++) { + num_instances = MAX2(num_instances, prims[i].num_instances); + } + } + else { + /* Get min/max index for non-indexed drawing. */ + min_index = ~0; + max_index = 0; + + for (i = 0; i < nr_prims; i++) { + min_index = MIN2(min_index, prims[i].start); + max_index = MAX2(max_index, prims[i].start + prims[i].count - 1); + num_instances = MAX2(num_instances, prims[i].num_instances); + } + } + + /* Validate state. */ + if (st->dirty.st) { + GLboolean vertDataEdgeFlags; + + /* sanity check for pointer arithmetic below */ + assert(sizeof(arrays[0]->Ptr[0]) == 1); + + vertDataEdgeFlags = arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj && + arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj->Name; + if (vertDataEdgeFlags != st->vertdata_edgeflags) { + st->vertdata_edgeflags = vertDataEdgeFlags; + st->dirty.st |= ST_NEW_EDGEFLAGS_DATA; + } + + st_validate_state(st); + + if (new_array) { + st_validate_varrays(ctx, arrays, max_index, num_instances); + } + +#if 0 + if (MESA_VERBOSE & VERBOSE_GLSL) { + check_uniforms(ctx); + } +#else + (void) check_uniforms; +#endif + } + + /* Notify the driver that the content of user buffers may have been + * changed. */ + assert(max_index >= min_index); + if (!new_array && st->num_user_attribs) { + for (i = 0; i < st->num_user_attribs; i++) { + if (st->user_attrib[i].buffer) { + unsigned element_size = st->user_attrib[i].element_size; + unsigned stride = st->user_attrib[i].stride; + unsigned min_offset = min_index * stride; + unsigned max_offset = max_index * stride + element_size; + + assert(max_offset > min_offset); + + pipe->redefine_user_buffer(pipe, st->user_attrib[i].buffer, + min_offset, + max_offset - min_offset); + } + } + } + + setup_index_buffer(ctx, ib, &ibuffer); + pipe->set_index_buffer(pipe, &ibuffer); + + util_draw_init_info(&info); + if (ib) { + info.indexed = TRUE; + if (min_index != ~0 && max_index != ~0) { + info.min_index = min_index; + info.max_index = max_index; + } + } + + info.primitive_restart = ctx->Array.PrimitiveRestart; + info.restart_index = ctx->Array.RestartIndex; + + /* do actual drawing */ + for (i = 0; i < nr_prims; i++) { + info.mode = translate_prim( ctx, prims[i].mode ); + info.start = prims[i].start; + info.count = prims[i].count; + info.instance_count = prims[i].num_instances; + info.index_bias = prims[i].basevertex; + if (!ib) { + info.min_index = info.start; + info.max_index = info.start + info.count - 1; + } + + if (u_trim_pipe_prim(info.mode, &info.count)) + pipe->draw_vbo(pipe, &info); + } + + pipe_resource_reference(&ibuffer.buffer, NULL); +} + + +void +st_init_draw(struct st_context *st) +{ + struct gl_context *ctx = st->ctx; + + vbo_set_draw_func(ctx, st_draw_vbo); + +#if FEATURE_feedback || FEATURE_rastpos + st->draw = draw_create(st->pipe); /* for selection/feedback */ + + /* Disable draw options that might convert points/lines to tris, etc. + * as that would foul-up feedback/selection mode. + */ + draw_wide_line_threshold(st->draw, 1000.0f); + draw_wide_point_threshold(st->draw, 1000.0f); + draw_enable_line_stipple(st->draw, FALSE); + draw_enable_point_sprites(st->draw, FALSE); +#endif +} + + +void +st_destroy_draw(struct st_context *st) +{ +#if FEATURE_feedback || FEATURE_rastpos + draw_destroy(st->draw); +#endif +} diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c index 8af144bbb..0ad9e1286 100644 --- a/mesalib/src/mesa/state_tracker/st_extensions.c +++ b/mesalib/src/mesa/state_tracker/st_extensions.c @@ -1,681 +1,681 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * Copyright (c) 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.
- *
- **************************************************************************/
-
-#include "main/imports.h"
-#include "main/context.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_screen.h"
-
-#include "st_context.h"
-#include "st_extensions.h"
-
-
-static int _min(int a, int b)
-{
- return (a < b) ? a : b;
-}
-
-static float _maxf(float a, float b)
-{
- return (a > b) ? a : b;
-}
-
-static int _clamp(int a, int min, int max)
-{
- if (a < min)
- return min;
- else if (a > max)
- return max;
- else
- return a;
-}
-
-
-/**
- * Query driver to get implementation limits.
- * Note that we have to limit/clamp against Mesa's internal limits too.
- */
-void st_init_limits(struct st_context *st)
-{
- struct pipe_screen *screen = st->pipe->screen;
- struct gl_constants *c = &st->ctx->Const;
- gl_shader_type sh;
-
- c->MaxTextureLevels
- = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS),
- MAX_TEXTURE_LEVELS);
-
- c->Max3DTextureLevels
- = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_3D_LEVELS),
- MAX_3D_TEXTURE_LEVELS);
-
- c->MaxCubeTextureLevels
- = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS),
- MAX_CUBE_TEXTURE_LEVELS);
-
- c->MaxTextureRectSize
- = _min(1 << (c->MaxTextureLevels - 1), MAX_TEXTURE_RECT_SIZE);
-
- c->MaxArrayTextureLayers
- = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS);
-
- c->MaxTextureImageUnits
- = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS),
- MAX_TEXTURE_IMAGE_UNITS);
-
- c->MaxVertexTextureImageUnits
- = _min(screen->get_param(screen, PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS),
- MAX_VERTEX_TEXTURE_IMAGE_UNITS);
-
- c->MaxCombinedTextureImageUnits
- = _min(screen->get_param(screen, PIPE_CAP_MAX_COMBINED_SAMPLERS),
- MAX_COMBINED_TEXTURE_IMAGE_UNITS);
-
- c->MaxTextureCoordUnits
- = _min(c->MaxTextureImageUnits, MAX_TEXTURE_COORD_UNITS);
-
- c->MaxTextureUnits = _min(c->MaxTextureImageUnits, c->MaxTextureCoordUnits);
-
- c->MaxDrawBuffers
- = _clamp(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS),
- 1, MAX_DRAW_BUFFERS);
-
- c->MaxLineWidth
- = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH));
- c->MaxLineWidthAA
- = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH_AA));
-
- c->MaxPointSize
- = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH));
- c->MaxPointSizeAA
- = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH_AA));
- /* called after _mesa_create_context/_mesa_init_point, fix default user
- * settable max point size up
- */
- st->ctx->Point.MaxSize = MAX2(c->MaxPointSize, c->MaxPointSizeAA);
- /* these are not queryable. Note that GL basically mandates a 1.0 minimum
- * for non-aa sizes, but we can go down to 0.0 for aa points.
- */
- c->MinPointSize = 1.0f;
- c->MinPointSizeAA = 0.0f;
-
- c->MaxTextureMaxAnisotropy
- = _maxf(2.0f, screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_ANISOTROPY));
-
- c->MaxTextureLodBias
- = screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_LOD_BIAS);
-
- c->MaxDrawBuffers
- = CLAMP(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS),
- 1, MAX_DRAW_BUFFERS);
-
- /* Quads always follow GL provoking rules. */
- c->QuadsFollowProvokingVertexConvention = GL_FALSE;
-
- for (sh = 0; sh < MESA_SHADER_TYPES; ++sh) {
- struct gl_shader_compiler_options *options =
- &st->ctx->ShaderCompilerOptions[sh];
- struct gl_program_constants *pc;
-
- switch (sh) {
- case PIPE_SHADER_FRAGMENT:
- pc = &c->FragmentProgram;
- break;
- case PIPE_SHADER_VERTEX:
- pc = &c->VertexProgram;
- break;
- case PIPE_SHADER_GEOMETRY:
- pc = &c->GeometryProgram;
- break;
- default:
- assert(0);
- continue;
- }
-
- pc->MaxNativeInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS);
- pc->MaxNativeAluInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS);
- pc->MaxNativeTexInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS);
- pc->MaxNativeTexIndirections = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS);
- pc->MaxNativeAttribs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INPUTS);
- pc->MaxNativeTemps = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEMPS);
- pc->MaxNativeAddressRegs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ADDRS);
- pc->MaxNativeParameters = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONSTS);
- pc->MaxUniformComponents = 4 * MIN2(pc->MaxNativeParameters, MAX_UNIFORMS);
- /* raise MaxParameters if native support is higher */
- pc->MaxParameters = MAX2(pc->MaxParameters, pc->MaxNativeParameters);
-
- /* Gallium doesn't really care about local vs. env parameters so use the
- * same limits.
- */
- pc->MaxLocalParams = pc->MaxParameters;
- pc->MaxEnvParams = pc->MaxParameters;
-
- options->EmitNoNoise = TRUE;
-
- /* TODO: make these more fine-grained if anyone needs it */
- options->MaxIfDepth = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
- options->EmitNoLoops = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH);
- options->EmitNoFunctions = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES);
- options->EmitNoMainReturn = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES);
-
- options->EmitNoCont = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED);
-
- options->EmitNoIndirectInput = !screen->get_shader_param(screen, sh,
- PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR);
- options->EmitNoIndirectOutput = !screen->get_shader_param(screen, sh,
- PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR);
- options->EmitNoIndirectTemp = !screen->get_shader_param(screen, sh,
- PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR);
- options->EmitNoIndirectUniform = !screen->get_shader_param(screen, sh,
- PIPE_SHADER_CAP_INDIRECT_CONST_ADDR);
-
- if (options->EmitNoLoops)
- options->MaxUnrollIterations = MIN2(screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS), 65536);
- }
-
- /* PIPE_CAP_MAX_FS_INPUTS specifies the number of COLORn + GENERICn inputs
- * and is set in MaxNativeAttribs. It's always 2 colors + N generic
- * attributes. The GLSL compiler never uses COLORn for varyings, so we
- * subtract the 2 colors to get the maximum number of varyings (generic
- * attributes) supported by a driver. */
- c->MaxVarying = screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_INPUTS) - 2;
- c->MaxVarying = MIN2(c->MaxVarying, MAX_VARYING);
-
- /* XXX we'll need a better query here someday */
- if (screen->get_param(screen, PIPE_CAP_GLSL)) {
- c->MinProgramTexelOffset = screen->get_param(screen, PIPE_CAP_MIN_TEXEL_OFFSET);
- c->MaxProgramTexelOffset = screen->get_param(screen, PIPE_CAP_MAX_TEXEL_OFFSET);
-
- c->GLSLVersion = 120;
- c->UniformBooleanTrue = ~0;
- }
-}
-
-
-static GLboolean st_get_s3tc_override(void)
-{
- const char *override = _mesa_getenv("force_s3tc_enable");
- if (override && !strcmp(override, "true"))
- return GL_TRUE;
- return GL_FALSE;
-}
-
-
-/**
- * Use pipe_screen::get_param() to query PIPE_CAP_ values to determine
- * which GL extensions are supported.
- * Quite a few extensions are always supported because they are standard
- * features or can be built on top of other gallium features.
- * Some fine tuning may still be needed.
- */
-void st_init_extensions(struct st_context *st)
-{
- struct pipe_screen *screen = st->pipe->screen;
- struct gl_context *ctx = st->ctx;
- int i;
-
- /*
- * Extensions that are supported by all Gallium drivers:
- */
- ctx->Extensions.ARB_copy_buffer = GL_TRUE;
- ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE;
- ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
- ctx->Extensions.ARB_fragment_program = GL_TRUE;
- ctx->Extensions.ARB_half_float_pixel = GL_TRUE;
- ctx->Extensions.ARB_map_buffer_range = GL_TRUE;
- ctx->Extensions.ARB_multisample = GL_TRUE;
- ctx->Extensions.ARB_sampler_objects = GL_TRUE;
- ctx->Extensions.ARB_texture_border_clamp = GL_TRUE; /* XXX temp */
- ctx->Extensions.ARB_texture_compression = GL_TRUE;
- ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
- ctx->Extensions.ARB_texture_env_combine = GL_TRUE;
- ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
- ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
- ctx->Extensions.ARB_vertex_array_object = GL_TRUE;
- ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;
- ctx->Extensions.ARB_vertex_program = GL_TRUE;
- ctx->Extensions.ARB_window_pos = GL_TRUE;
-
- ctx->Extensions.EXT_blend_color = GL_TRUE;
- ctx->Extensions.EXT_blend_func_separate = GL_TRUE;
- ctx->Extensions.EXT_blend_logic_op = GL_TRUE;
- ctx->Extensions.EXT_blend_minmax = GL_TRUE;
- ctx->Extensions.EXT_blend_subtract = GL_TRUE;
- ctx->Extensions.EXT_framebuffer_blit = GL_TRUE;
- ctx->Extensions.EXT_framebuffer_object = GL_TRUE;
- ctx->Extensions.EXT_framebuffer_multisample = GL_TRUE;
- ctx->Extensions.EXT_fog_coord = GL_TRUE;
- ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE;
- ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE;
- ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE;
- ctx->Extensions.EXT_point_parameters = GL_TRUE;
- ctx->Extensions.EXT_provoking_vertex = GL_TRUE;
- ctx->Extensions.EXT_secondary_color = GL_TRUE;
- ctx->Extensions.EXT_stencil_wrap = GL_TRUE;
- ctx->Extensions.EXT_texture_env_add = GL_TRUE;
- ctx->Extensions.EXT_texture_env_combine = GL_TRUE;
- ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE;
- ctx->Extensions.EXT_texture_lod_bias = GL_TRUE;
- ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
- if (ctx->API == API_OPENGLES || ctx->API == API_OPENGLES2)
- ctx->Extensions.EXT_texture_format_BGRA8888 = GL_TRUE;
-
- ctx->Extensions.APPLE_vertex_array_object = GL_TRUE;
-
- ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE;
-
- ctx->Extensions.MESA_pack_invert = GL_TRUE;
-
- ctx->Extensions.NV_blend_square = GL_TRUE;
- ctx->Extensions.NV_texgen_reflection = GL_TRUE;
- ctx->Extensions.NV_texture_env_combine4 = GL_TRUE;
- ctx->Extensions.NV_texture_rectangle = GL_TRUE;
-#if 0
- /* possibly could support the following two */
- ctx->Extensions.NV_vertex_program = GL_TRUE;
- ctx->Extensions.NV_vertex_program1_1 = GL_TRUE;
-#endif
-
-#if FEATURE_OES_EGL_image
- ctx->Extensions.OES_EGL_image = GL_TRUE;
-#endif
-#if FEATURE_OES_draw_texture
- ctx->Extensions.OES_draw_texture = GL_TRUE;
-#endif
-
- ctx->Extensions.SGIS_generate_mipmap = GL_TRUE;
-
- /*
- * Extensions that depend on the driver/hardware:
- */
- if (screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS) > 0) {
- ctx->Extensions.ARB_draw_buffers = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_TEXTURE_SWIZZLE) > 0) {
- ctx->Extensions.EXT_texture_swizzle = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_GLSL)) {
- ctx->Extensions.ARB_fragment_shader = GL_TRUE;
- ctx->Extensions.ARB_vertex_shader = GL_TRUE;
- ctx->Extensions.ARB_shader_objects = GL_TRUE;
- ctx->Extensions.ARB_shading_language_100 = GL_TRUE;
- ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE;
- ctx->Extensions.EXT_separate_shader_objects = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_REPEAT) > 0) {
- ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_BLEND_EQUATION_SEPARATE)) {
- ctx->Extensions.EXT_blend_equation_separate = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_CLAMP) > 0) {
- ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE;
- ctx->Extensions.ATI_texture_mirror_once = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) {
- ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS) > 1) {
- ctx->Extensions.ARB_multitexture = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) {
- ctx->Extensions.ATI_separate_stencil = GL_TRUE;
- ctx->Extensions.EXT_stencil_two_side = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_ANISOTROPIC_FILTER)) {
- ctx->Extensions.EXT_texture_filter_anisotropic = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_POINT_SPRITE)) {
- ctx->Extensions.ARB_point_sprite = GL_TRUE;
- /* GL_NV_point_sprite is not supported by gallium because we don't
- * support the GL_POINT_SPRITE_R_MODE_NV option.
- */
- }
-
- if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY)) {
- ctx->Extensions.ARB_occlusion_query = GL_TRUE;
- ctx->Extensions.ARB_occlusion_query2 = GL_TRUE;
- }
- if (screen->get_param(screen, PIPE_CAP_TIMER_QUERY)) {
- ctx->Extensions.EXT_timer_query = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_TEXTURE_SHADOW_MAP)) {
- ctx->Extensions.ARB_depth_texture = GL_TRUE;
- ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE;
- ctx->Extensions.ARB_shadow = GL_TRUE;
- ctx->Extensions.EXT_shadow_funcs = GL_TRUE;
- /*ctx->Extensions.ARB_shadow_ambient = GL_TRUE;*/
- }
-
- /* GL_EXT_packed_depth_stencil requires both the ability to render to
- * a depth/stencil buffer and texture from depth/stencil source.
- */
- if (screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_DEPTH_STENCIL) &&
- screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE;
- }
- else if (screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_DEPTH_STENCIL) &&
- screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE;
- }
-
- /* float support - assume nothing exclusively supports 64-bit floats */
- if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW |
- PIPE_BIND_RENDER_TARGET) &&
- screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW |
- PIPE_BIND_RENDER_TARGET)) {
- ctx->Extensions.ARB_texture_float = GL_TRUE;
- }
-
- /* sRGB support */
- if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) ||
- screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.EXT_texture_sRGB = GL_TRUE;
- ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE;
- if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET) ||
- screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET)) {
- ctx->Extensions.EXT_framebuffer_sRGB = GL_TRUE;
- ctx->Const.sRGBCapable = GL_TRUE;
- }
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.ARB_texture_rg = GL_TRUE;
- }
-
- /* s3tc support */
- if (screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) &&
- (ctx->Mesa_DXTn || st_get_s3tc_override())) {
- ctx->Extensions.EXT_texture_compression_s3tc = GL_TRUE;
- ctx->Extensions.S3_s3tc = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_SNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_SNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)
- ) {
- ctx->Extensions.ARB_texture_compression_rgtc = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_LATC1_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, PIPE_FORMAT_LATC1_SNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, PIPE_FORMAT_LATC2_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, PIPE_FORMAT_LATC2_SNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.EXT_texture_compression_latc = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_LATC2_UNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.EXT_texture_snorm = GL_TRUE;
- }
-
- /* ycbcr support */
- if (screen->is_format_supported(screen, PIPE_FORMAT_UYVY,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW) ||
- screen->is_format_supported(screen, PIPE_FORMAT_YUYV,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.MESA_ycbcr_texture = GL_TRUE;
- }
-
- /* GL_EXT_texture_array */
- if (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS) > 1) {
- ctx->Extensions.EXT_texture_array = GL_TRUE;
- ctx->Extensions.MESA_texture_array = GL_TRUE;
- }
-
- /* GL_ARB_framebuffer_object */
- if (ctx->Extensions.EXT_packed_depth_stencil) {
- /* we support always support GL_EXT_framebuffer_blit */
- ctx->Extensions.ARB_framebuffer_object = GL_TRUE;
- }
-
- if (st->pipe->render_condition) {
- ctx->Extensions.NV_conditional_render = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_ENABLE)) {
- ctx->Extensions.EXT_draw_buffers2 = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_FUNC)) {
- ctx->Extensions.ARB_draw_buffers_blend = GL_TRUE;
- }
-
- /* GL_ARB_half_float_vertex */
- if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER)) {
- ctx->Extensions.ARB_half_float_vertex = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_FIXED,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER)) {
- ctx->Extensions.ARB_ES2_compatibility = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_UNORM,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER) &&
- screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_UNORM,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER) &&
- screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_SNORM,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER) &&
- screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_SNORM,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER) &&
- screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_USCALED,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER) &&
- screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_USCALED,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER) &&
- screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_SSCALED,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER) &&
- screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_SSCALED,
- PIPE_BUFFER, 0,
- PIPE_BIND_VERTEX_BUFFER)) {
- 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 0 /* XXX re-enable when GLSL compiler again supports geometry shaders */
- ctx->Extensions.ARB_geometry_shader4 = GL_TRUE;
-#endif
- }
-
- if (screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) {
- ctx->Extensions.NV_primitive_restart = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_DEPTH_CLAMP)) {
- ctx->Extensions.ARB_depth_clamp = GL_TRUE;
- }
-
- /* This extension does not actually require support of floating point
- * render targets, just clamping controls.
- * Advertise this extension if either fragment color clamping is supported
- * or no render targets having color values outside of the range [0, 1]
- * are supported, in which case the fragment color clamping has no effect
- * on rendering.
- */
- if (screen->get_param(screen, PIPE_CAP_FRAGMENT_COLOR_CLAMP_CONTROL) ||
- (!screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET) &&
- !screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_SNORM,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET) &&
- !screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET) &&
- !screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET) &&
- !screen->is_format_supported(screen, PIPE_FORMAT_R11G11B10_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET) &&
- !screen->is_format_supported(screen, PIPE_FORMAT_R9G9B9E5_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET))) {
- ctx->Extensions.ARB_color_buffer_float = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) {
- ctx->Extensions.ARB_shader_stencil_export = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_TGSI_INSTANCEID)) {
- ctx->Extensions.ARB_draw_instanced = GL_TRUE;
- }
- if (screen->get_param(screen, PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR)) {
- ctx->Extensions.ARB_instanced_arrays = GL_TRUE;
- }
-
- if (screen->fence_finish) {
- ctx->Extensions.ARB_sync = GL_TRUE;
- }
-
- if (st->pipe->texture_barrier) {
- ctx->Extensions.NV_texture_barrier = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_R9G9B9E5_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.EXT_texture_shared_exponent = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_R11G11B10_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_RENDER_TARGET |
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.EXT_packed_float = GL_TRUE;
- }
-
- /* Maximum sample count. */
- for (i = 16; i > 0; --i) {
- if (screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_UNORM,
- PIPE_TEXTURE_2D, i,
- PIPE_BIND_RENDER_TARGET)) {
- ctx->Const.MaxSamples = i;
- break;
- }
- }
-
- if (screen->get_param(screen, PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE)) {
- ctx->Extensions.ARB_seamless_cube_map = GL_TRUE;
- ctx->Extensions.AMD_seamless_cubemap_per_texture = GL_TRUE;
- }
- else if (screen->get_param(screen, PIPE_CAP_SEAMLESS_CUBE_MAP)) {
- ctx->Extensions.ARB_seamless_cube_map = GL_TRUE;
- }
-
- if (screen->get_param(screen, PIPE_CAP_SM3)) {
- ctx->Extensions.ARB_shader_texture_lod = GL_TRUE;
- }
-
- if (screen->is_format_supported(screen, PIPE_FORMAT_Z32_FLOAT,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_DEPTH_STENCIL |
- PIPE_BIND_SAMPLER_VIEW) &&
- screen->is_format_supported(screen, PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED,
- PIPE_TEXTURE_2D, 0,
- PIPE_BIND_DEPTH_STENCIL |
- PIPE_BIND_SAMPLER_VIEW)) {
- ctx->Extensions.ARB_depth_buffer_float = GL_TRUE;
- }
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (c) 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. + * + **************************************************************************/ + +#include "main/imports.h" +#include "main/context.h" +#include "main/macros.h" +#include "main/mfeatures.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" + +#include "st_context.h" +#include "st_extensions.h" + + +static int _min(int a, int b) +{ + return (a < b) ? a : b; +} + +static float _maxf(float a, float b) +{ + return (a > b) ? a : b; +} + +static int _clamp(int a, int min, int max) +{ + if (a < min) + return min; + else if (a > max) + return max; + else + return a; +} + + +/** + * Query driver to get implementation limits. + * Note that we have to limit/clamp against Mesa's internal limits too. + */ +void st_init_limits(struct st_context *st) +{ + struct pipe_screen *screen = st->pipe->screen; + struct gl_constants *c = &st->ctx->Const; + gl_shader_type sh; + + c->MaxTextureLevels + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS), + MAX_TEXTURE_LEVELS); + + c->Max3DTextureLevels + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_3D_LEVELS), + MAX_3D_TEXTURE_LEVELS); + + c->MaxCubeTextureLevels + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS), + MAX_CUBE_TEXTURE_LEVELS); + + c->MaxTextureRectSize + = _min(1 << (c->MaxTextureLevels - 1), MAX_TEXTURE_RECT_SIZE); + + c->MaxArrayTextureLayers + = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS); + + c->MaxTextureImageUnits + = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS), + MAX_TEXTURE_IMAGE_UNITS); + + c->MaxVertexTextureImageUnits + = _min(screen->get_param(screen, PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS), + MAX_VERTEX_TEXTURE_IMAGE_UNITS); + + c->MaxCombinedTextureImageUnits + = _min(screen->get_param(screen, PIPE_CAP_MAX_COMBINED_SAMPLERS), + MAX_COMBINED_TEXTURE_IMAGE_UNITS); + + c->MaxTextureCoordUnits + = _min(c->MaxTextureImageUnits, MAX_TEXTURE_COORD_UNITS); + + c->MaxTextureUnits = _min(c->MaxTextureImageUnits, c->MaxTextureCoordUnits); + + c->MaxDrawBuffers + = _clamp(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS), + 1, MAX_DRAW_BUFFERS); + + c->MaxLineWidth + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH)); + c->MaxLineWidthAA + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_LINE_WIDTH_AA)); + + c->MaxPointSize + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH)); + c->MaxPointSizeAA + = _maxf(1.0f, screen->get_paramf(screen, PIPE_CAP_MAX_POINT_WIDTH_AA)); + /* called after _mesa_create_context/_mesa_init_point, fix default user + * settable max point size up + */ + st->ctx->Point.MaxSize = MAX2(c->MaxPointSize, c->MaxPointSizeAA); + /* these are not queryable. Note that GL basically mandates a 1.0 minimum + * for non-aa sizes, but we can go down to 0.0 for aa points. + */ + c->MinPointSize = 1.0f; + c->MinPointSizeAA = 0.0f; + + c->MaxTextureMaxAnisotropy + = _maxf(2.0f, screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_ANISOTROPY)); + + c->MaxTextureLodBias + = screen->get_paramf(screen, PIPE_CAP_MAX_TEXTURE_LOD_BIAS); + + c->MaxDrawBuffers + = CLAMP(screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS), + 1, MAX_DRAW_BUFFERS); + + /* Quads always follow GL provoking rules. */ + c->QuadsFollowProvokingVertexConvention = GL_FALSE; + + for (sh = 0; sh < MESA_SHADER_TYPES; ++sh) { + struct gl_shader_compiler_options *options = + &st->ctx->ShaderCompilerOptions[sh]; + struct gl_program_constants *pc; + + switch (sh) { + case PIPE_SHADER_FRAGMENT: + pc = &c->FragmentProgram; + break; + case PIPE_SHADER_VERTEX: + pc = &c->VertexProgram; + break; + case PIPE_SHADER_GEOMETRY: + pc = &c->GeometryProgram; + break; + default: + assert(0); + continue; + } + + pc->MaxNativeInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS); + pc->MaxNativeAluInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS); + pc->MaxNativeTexInstructions = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS); + pc->MaxNativeTexIndirections = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS); + pc->MaxNativeAttribs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INPUTS); + pc->MaxNativeTemps = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_TEMPS); + pc->MaxNativeAddressRegs = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_ADDRS); + pc->MaxNativeParameters = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONSTS); + pc->MaxUniformComponents = 4 * MIN2(pc->MaxNativeParameters, MAX_UNIFORMS); + /* raise MaxParameters if native support is higher */ + pc->MaxParameters = MAX2(pc->MaxParameters, pc->MaxNativeParameters); + + /* Gallium doesn't really care about local vs. env parameters so use the + * same limits. + */ + pc->MaxLocalParams = pc->MaxParameters; + pc->MaxEnvParams = pc->MaxParameters; + + options->EmitNoNoise = TRUE; + + /* TODO: make these more fine-grained if anyone needs it */ + options->MaxIfDepth = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); + options->EmitNoLoops = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH); + options->EmitNoFunctions = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES); + options->EmitNoMainReturn = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_SUBROUTINES); + + options->EmitNoCont = !screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED); + + options->EmitNoIndirectInput = !screen->get_shader_param(screen, sh, + PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR); + options->EmitNoIndirectOutput = !screen->get_shader_param(screen, sh, + PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR); + options->EmitNoIndirectTemp = !screen->get_shader_param(screen, sh, + PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR); + options->EmitNoIndirectUniform = !screen->get_shader_param(screen, sh, + PIPE_SHADER_CAP_INDIRECT_CONST_ADDR); + + if (options->EmitNoLoops) + options->MaxUnrollIterations = MIN2(screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_INSTRUCTIONS), 65536); + } + + /* PIPE_CAP_MAX_FS_INPUTS specifies the number of COLORn + GENERICn inputs + * and is set in MaxNativeAttribs. It's always 2 colors + N generic + * attributes. The GLSL compiler never uses COLORn for varyings, so we + * subtract the 2 colors to get the maximum number of varyings (generic + * attributes) supported by a driver. */ + c->MaxVarying = screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_INPUTS) - 2; + c->MaxVarying = MIN2(c->MaxVarying, MAX_VARYING); + + /* XXX we'll need a better query here someday */ + if (screen->get_param(screen, PIPE_CAP_GLSL)) { + c->MinProgramTexelOffset = screen->get_param(screen, PIPE_CAP_MIN_TEXEL_OFFSET); + c->MaxProgramTexelOffset = screen->get_param(screen, PIPE_CAP_MAX_TEXEL_OFFSET); + + c->GLSLVersion = 120; + c->UniformBooleanTrue = ~0; + } +} + + +static GLboolean st_get_s3tc_override(void) +{ + const char *override = _mesa_getenv("force_s3tc_enable"); + if (override && !strcmp(override, "true")) + return GL_TRUE; + return GL_FALSE; +} + + +/** + * Use pipe_screen::get_param() to query PIPE_CAP_ values to determine + * which GL extensions are supported. + * Quite a few extensions are always supported because they are standard + * features or can be built on top of other gallium features. + * Some fine tuning may still be needed. + */ +void st_init_extensions(struct st_context *st) +{ + struct pipe_screen *screen = st->pipe->screen; + struct gl_context *ctx = st->ctx; + int i; + + /* + * Extensions that are supported by all Gallium drivers: + */ + ctx->Extensions.ARB_copy_buffer = GL_TRUE; + ctx->Extensions.ARB_draw_elements_base_vertex = GL_TRUE; + ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE; + ctx->Extensions.ARB_fragment_program = GL_TRUE; + ctx->Extensions.ARB_half_float_pixel = GL_TRUE; + ctx->Extensions.ARB_map_buffer_range = GL_TRUE; + ctx->Extensions.ARB_multisample = GL_TRUE; + ctx->Extensions.ARB_sampler_objects = GL_TRUE; + ctx->Extensions.ARB_texture_border_clamp = GL_TRUE; /* XXX temp */ + ctx->Extensions.ARB_texture_compression = GL_TRUE; + ctx->Extensions.ARB_texture_cube_map = GL_TRUE; + ctx->Extensions.ARB_texture_env_combine = GL_TRUE; + ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE; + ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE; + ctx->Extensions.ARB_vertex_array_object = GL_TRUE; + ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE; + ctx->Extensions.ARB_vertex_program = GL_TRUE; + ctx->Extensions.ARB_window_pos = GL_TRUE; + + ctx->Extensions.EXT_blend_color = GL_TRUE; + ctx->Extensions.EXT_blend_func_separate = GL_TRUE; + ctx->Extensions.EXT_blend_logic_op = GL_TRUE; + ctx->Extensions.EXT_blend_minmax = GL_TRUE; + ctx->Extensions.EXT_blend_subtract = GL_TRUE; + ctx->Extensions.EXT_framebuffer_blit = GL_TRUE; + ctx->Extensions.EXT_framebuffer_object = GL_TRUE; + ctx->Extensions.EXT_framebuffer_multisample = GL_TRUE; + ctx->Extensions.EXT_fog_coord = GL_TRUE; + ctx->Extensions.EXT_gpu_program_parameters = GL_TRUE; + ctx->Extensions.EXT_multi_draw_arrays = GL_TRUE; + ctx->Extensions.EXT_pixel_buffer_object = GL_TRUE; + ctx->Extensions.EXT_point_parameters = GL_TRUE; + ctx->Extensions.EXT_provoking_vertex = GL_TRUE; + ctx->Extensions.EXT_secondary_color = GL_TRUE; + ctx->Extensions.EXT_stencil_wrap = GL_TRUE; + ctx->Extensions.EXT_texture_env_add = GL_TRUE; + ctx->Extensions.EXT_texture_env_combine = GL_TRUE; + ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE; + ctx->Extensions.EXT_texture_lod_bias = GL_TRUE; + ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE; + if (ctx->API == API_OPENGLES || ctx->API == API_OPENGLES2) + ctx->Extensions.EXT_texture_format_BGRA8888 = GL_TRUE; + + ctx->Extensions.APPLE_vertex_array_object = GL_TRUE; + + ctx->Extensions.ATI_texture_env_combine3 = GL_TRUE; + + ctx->Extensions.MESA_pack_invert = GL_TRUE; + + ctx->Extensions.NV_blend_square = GL_TRUE; + ctx->Extensions.NV_texgen_reflection = GL_TRUE; + ctx->Extensions.NV_texture_env_combine4 = GL_TRUE; + ctx->Extensions.NV_texture_rectangle = GL_TRUE; +#if 0 + /* possibly could support the following two */ + ctx->Extensions.NV_vertex_program = GL_TRUE; + ctx->Extensions.NV_vertex_program1_1 = GL_TRUE; +#endif + +#if FEATURE_OES_EGL_image + ctx->Extensions.OES_EGL_image = GL_TRUE; +#endif +#if FEATURE_OES_draw_texture + ctx->Extensions.OES_draw_texture = GL_TRUE; +#endif + + ctx->Extensions.SGIS_generate_mipmap = GL_TRUE; + + /* + * Extensions that depend on the driver/hardware: + */ + if (screen->get_param(screen, PIPE_CAP_MAX_RENDER_TARGETS) > 0) { + ctx->Extensions.ARB_draw_buffers = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TEXTURE_SWIZZLE) > 0) { + ctx->Extensions.EXT_texture_swizzle = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_GLSL)) { + ctx->Extensions.ARB_fragment_shader = GL_TRUE; + ctx->Extensions.ARB_vertex_shader = GL_TRUE; + ctx->Extensions.ARB_shader_objects = GL_TRUE; + ctx->Extensions.ARB_shading_language_100 = GL_TRUE; + ctx->Extensions.ARB_explicit_attrib_location = GL_TRUE; + ctx->Extensions.EXT_separate_shader_objects = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_REPEAT) > 0) { + ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_BLEND_EQUATION_SEPARATE)) { + ctx->Extensions.EXT_blend_equation_separate = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TEXTURE_MIRROR_CLAMP) > 0) { + ctx->Extensions.EXT_texture_mirror_clamp = GL_TRUE; + ctx->Extensions.ATI_texture_mirror_once = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) { + ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS) > 1) { + ctx->Extensions.ARB_multitexture = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TWO_SIDED_STENCIL)) { + ctx->Extensions.ATI_separate_stencil = GL_TRUE; + ctx->Extensions.EXT_stencil_two_side = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_ANISOTROPIC_FILTER)) { + ctx->Extensions.EXT_texture_filter_anisotropic = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_POINT_SPRITE)) { + ctx->Extensions.ARB_point_sprite = GL_TRUE; + /* GL_NV_point_sprite is not supported by gallium because we don't + * support the GL_POINT_SPRITE_R_MODE_NV option. + */ + } + + if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY)) { + ctx->Extensions.ARB_occlusion_query = GL_TRUE; + ctx->Extensions.ARB_occlusion_query2 = GL_TRUE; + } + if (screen->get_param(screen, PIPE_CAP_TIMER_QUERY)) { + ctx->Extensions.EXT_timer_query = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TEXTURE_SHADOW_MAP)) { + ctx->Extensions.ARB_depth_texture = GL_TRUE; + ctx->Extensions.ARB_fragment_program_shadow = GL_TRUE; + ctx->Extensions.ARB_shadow = GL_TRUE; + ctx->Extensions.EXT_shadow_funcs = GL_TRUE; + /*ctx->Extensions.ARB_shadow_ambient = GL_TRUE;*/ + } + + /* GL_EXT_packed_depth_stencil requires both the ability to render to + * a depth/stencil buffer and texture from depth/stencil source. + */ + if (screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_DEPTH_STENCIL) && + screen->is_format_supported(screen, PIPE_FORMAT_S8_USCALED_Z24_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; + } + else if (screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_DEPTH_STENCIL) && + screen->is_format_supported(screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.EXT_packed_depth_stencil = GL_TRUE; + } + + /* float support - assume nothing exclusively supports 64-bit floats */ + if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW | + PIPE_BIND_RENDER_TARGET) && + screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW | + PIPE_BIND_RENDER_TARGET)) { + ctx->Extensions.ARB_texture_float = GL_TRUE; + } + + /* sRGB support */ + if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) || + screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.EXT_texture_sRGB = GL_TRUE; + ctx->Extensions.EXT_texture_sRGB_decode = GL_TRUE; + if (screen->is_format_supported(screen, PIPE_FORMAT_A8B8G8R8_SRGB, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET) || + screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_SRGB, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET)) { + ctx->Extensions.EXT_framebuffer_sRGB = GL_TRUE; + ctx->Const.sRGBCapable = GL_TRUE; + } + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.ARB_texture_rg = GL_TRUE; + } + + /* s3tc support */ + if (screen->is_format_supported(screen, PIPE_FORMAT_DXT5_RGBA, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) && + (ctx->Mesa_DXTn || st_get_s3tc_override())) { + ctx->Extensions.EXT_texture_compression_s3tc = GL_TRUE; + ctx->Extensions.S3_s3tc = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, PIPE_FORMAT_RGTC1_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, PIPE_FORMAT_RGTC2_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) + ) { + ctx->Extensions.ARB_texture_compression_rgtc = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC1_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, PIPE_FORMAT_LATC1_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, PIPE_FORMAT_LATC2_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, PIPE_FORMAT_LATC2_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.EXT_texture_compression_latc = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_LATC2_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.ATI_texture_compression_3dc = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.EXT_texture_snorm = GL_TRUE; + } + + /* ycbcr support */ + if (screen->is_format_supported(screen, PIPE_FORMAT_UYVY, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW) || + screen->is_format_supported(screen, PIPE_FORMAT_YUYV, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.MESA_ycbcr_texture = GL_TRUE; + } + + /* GL_EXT_texture_array */ + if (screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_ARRAY_LAYERS) > 1) { + ctx->Extensions.EXT_texture_array = GL_TRUE; + ctx->Extensions.MESA_texture_array = GL_TRUE; + } + + /* GL_ARB_framebuffer_object */ + if (ctx->Extensions.EXT_packed_depth_stencil) { + /* we support always support GL_EXT_framebuffer_blit */ + ctx->Extensions.ARB_framebuffer_object = GL_TRUE; + } + + if (st->pipe->render_condition) { + ctx->Extensions.NV_conditional_render = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_ENABLE)) { + ctx->Extensions.EXT_draw_buffers2 = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_INDEP_BLEND_FUNC)) { + ctx->Extensions.ARB_draw_buffers_blend = GL_TRUE; + } + + /* GL_ARB_half_float_vertex */ + if (screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER)) { + ctx->Extensions.ARB_half_float_vertex = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_FIXED, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER)) { + ctx->Extensions.ARB_ES2_compatibility = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_UNORM, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER) && + screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_UNORM, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER) && + screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_SNORM, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER) && + screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_SNORM, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER) && + screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_USCALED, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER) && + screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_USCALED, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER) && + screen->is_format_supported(screen, PIPE_FORMAT_R10G10B10A2_SSCALED, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER) && + screen->is_format_supported(screen, PIPE_FORMAT_B10G10R10A2_SSCALED, + PIPE_BUFFER, 0, + PIPE_BIND_VERTEX_BUFFER)) { + 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 0 /* XXX re-enable when GLSL compiler again supports geometry shaders */ + ctx->Extensions.ARB_geometry_shader4 = GL_TRUE; +#endif + } + + if (screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) { + ctx->Extensions.NV_primitive_restart = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_DEPTH_CLAMP)) { + ctx->Extensions.ARB_depth_clamp = GL_TRUE; + } + + /* This extension does not actually require support of floating point + * render targets, just clamping controls. + * Advertise this extension if either fragment color clamping is supported + * or no render targets having color values outside of the range [0, 1] + * are supported, in which case the fragment color clamping has no effect + * on rendering. + */ + if (screen->get_param(screen, PIPE_CAP_FRAGMENT_COLOR_CLAMP_CONTROL) || + (!screen->is_format_supported(screen, PIPE_FORMAT_R8G8B8A8_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET) && + !screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET) && + !screen->is_format_supported(screen, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET) && + !screen->is_format_supported(screen, PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET) && + !screen->is_format_supported(screen, PIPE_FORMAT_R11G11B10_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET) && + !screen->is_format_supported(screen, PIPE_FORMAT_R9G9B9E5_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET))) { + ctx->Extensions.ARB_color_buffer_float = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) { + ctx->Extensions.ARB_shader_stencil_export = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_TGSI_INSTANCEID)) { + ctx->Extensions.ARB_draw_instanced = GL_TRUE; + } + if (screen->get_param(screen, PIPE_CAP_VERTEX_ELEMENT_INSTANCE_DIVISOR)) { + ctx->Extensions.ARB_instanced_arrays = GL_TRUE; + } + + if (screen->fence_finish) { + ctx->Extensions.ARB_sync = GL_TRUE; + } + + if (st->pipe->texture_barrier) { + ctx->Extensions.NV_texture_barrier = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_R9G9B9E5_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.EXT_texture_shared_exponent = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_R11G11B10_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_RENDER_TARGET | + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.EXT_packed_float = GL_TRUE; + } + + /* Maximum sample count. */ + for (i = 16; i > 0; --i) { + if (screen->is_format_supported(screen, PIPE_FORMAT_B8G8R8A8_UNORM, + PIPE_TEXTURE_2D, i, + PIPE_BIND_RENDER_TARGET)) { + ctx->Const.MaxSamples = i; + break; + } + } + + if (screen->get_param(screen, PIPE_CAP_SEAMLESS_CUBE_MAP_PER_TEXTURE)) { + ctx->Extensions.ARB_seamless_cube_map = GL_TRUE; + ctx->Extensions.AMD_seamless_cubemap_per_texture = GL_TRUE; + } + else if (screen->get_param(screen, PIPE_CAP_SEAMLESS_CUBE_MAP)) { + ctx->Extensions.ARB_seamless_cube_map = GL_TRUE; + } + + if (screen->get_param(screen, PIPE_CAP_SM3)) { + ctx->Extensions.ARB_shader_texture_lod = GL_TRUE; + } + + if (screen->is_format_supported(screen, PIPE_FORMAT_Z32_FLOAT, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_DEPTH_STENCIL | + PIPE_BIND_SAMPLER_VIEW) && + screen->is_format_supported(screen, PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_DEPTH_STENCIL | + PIPE_BIND_SAMPLER_VIEW)) { + ctx->Extensions.ARB_depth_buffer_float = GL_TRUE; + } +} diff --git a/mesalib/src/mesa/state_tracker/st_format.c b/mesalib/src/mesa/state_tracker/st_format.c index d24e5b8d0..bd4f0860c 100644 --- a/mesalib/src/mesa/state_tracker/st_format.c +++ b/mesalib/src/mesa/state_tracker/st_format.c @@ -1,1488 +1,1488 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * Copyright (c) 2008-2010 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.
- *
- **************************************************************************/
-
-
-/**
- * Mesa / Gallium format conversion and format selection code.
- * \author Brian Paul
- */
-
-#include "main/imports.h"
-#include "main/context.h"
-#include "main/texstore.h"
-#include "main/image.h"
-#include "main/macros.h"
-#include "main/mfeatures.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_screen.h"
-#include "util/u_format.h"
-#include "st_context.h"
-#include "st_format.h"
-
-
-static GLuint
-format_max_bits(enum pipe_format format)
-{
- GLuint size = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 0);
-
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 1));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 2));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 0));
- size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1));
- return size;
-}
-
-
-/**
- * Return basic GL datatype for the given gallium format.
- */
-GLenum
-st_format_datatype(enum pipe_format format)
-{
- const struct util_format_description *desc;
- int i;
-
- desc = util_format_description(format);
- assert(desc);
-
- /* Find the first non-VOID channel. */
- for (i = 0; i < 4; i++) {
- if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
- break;
- }
- }
-
- if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) {
- if (format == PIPE_FORMAT_B5G5R5A1_UNORM ||
- format == PIPE_FORMAT_B5G6R5_UNORM) {
- return GL_UNSIGNED_SHORT;
- }
- else if (format == PIPE_FORMAT_R11G11B10_FLOAT ||
- format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
- return GL_FLOAT;
- }
- else if (format == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
- format == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
- format == PIPE_FORMAT_Z24X8_UNORM ||
- format == PIPE_FORMAT_X8Z24_UNORM) {
- return GL_UNSIGNED_INT_24_8;
- }
- else if (format == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED) {
- return GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
- }
- else {
- const GLuint size = format_max_bits(format);
-
- assert(i < 4);
- if (i == 4)
- return GL_NONE;
-
- if (size == 8) {
- if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED)
- return GL_UNSIGNED_BYTE;
- else
- return GL_BYTE;
- }
- else if (size == 16) {
- if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT)
- return GL_HALF_FLOAT;
- if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED)
- return GL_UNSIGNED_SHORT;
- else
- return GL_SHORT;
- }
- else if (size <= 32) {
- if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT)
- return GL_FLOAT;
- if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED)
- return GL_UNSIGNED_INT;
- else
- return GL_INT;
- }
- else {
- assert(size == 64);
- assert(desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT);
- return GL_DOUBLE;
- }
- }
- }
- else if (format == PIPE_FORMAT_UYVY) {
- return GL_UNSIGNED_SHORT;
- }
- else if (format == PIPE_FORMAT_YUYV) {
- return GL_UNSIGNED_SHORT;
- }
- else {
- /* probably a compressed format, unsupported anyway */
- return GL_NONE;
- }
-}
-
-
-/**
- * Translate Mesa format to Gallium format.
- */
-enum pipe_format
-st_mesa_format_to_pipe_format(gl_format mesaFormat)
-{
- switch (mesaFormat) {
- case MESA_FORMAT_RGBA8888:
- return PIPE_FORMAT_A8B8G8R8_UNORM;
- case MESA_FORMAT_RGBA8888_REV:
- return PIPE_FORMAT_R8G8B8A8_UNORM;
- case MESA_FORMAT_ARGB8888:
- return PIPE_FORMAT_B8G8R8A8_UNORM;
- case MESA_FORMAT_ARGB8888_REV:
- return PIPE_FORMAT_A8R8G8B8_UNORM;
- case MESA_FORMAT_XRGB8888:
- return PIPE_FORMAT_B8G8R8X8_UNORM;
- case MESA_FORMAT_XRGB8888_REV:
- return PIPE_FORMAT_X8R8G8B8_UNORM;
- case MESA_FORMAT_ARGB1555:
- return PIPE_FORMAT_B5G5R5A1_UNORM;
- case MESA_FORMAT_ARGB4444:
- return PIPE_FORMAT_B4G4R4A4_UNORM;
- case MESA_FORMAT_RGB565:
- return PIPE_FORMAT_B5G6R5_UNORM;
- case MESA_FORMAT_RGB332:
- return PIPE_FORMAT_B2G3R3_UNORM;
- case MESA_FORMAT_ARGB2101010:
- return PIPE_FORMAT_B10G10R10A2_UNORM;
- case MESA_FORMAT_AL44:
- return PIPE_FORMAT_L4A4_UNORM;
- case MESA_FORMAT_AL88:
- return PIPE_FORMAT_L8A8_UNORM;
- case MESA_FORMAT_AL1616:
- return PIPE_FORMAT_L16A16_UNORM;
- case MESA_FORMAT_A8:
- return PIPE_FORMAT_A8_UNORM;
- case MESA_FORMAT_A16:
- return PIPE_FORMAT_A16_UNORM;
- case MESA_FORMAT_L8:
- return PIPE_FORMAT_L8_UNORM;
- case MESA_FORMAT_L16:
- return PIPE_FORMAT_L16_UNORM;
- case MESA_FORMAT_I8:
- return PIPE_FORMAT_I8_UNORM;
- case MESA_FORMAT_I16:
- return PIPE_FORMAT_I16_UNORM;
- case MESA_FORMAT_Z16:
- return PIPE_FORMAT_Z16_UNORM;
- case MESA_FORMAT_Z32:
- return PIPE_FORMAT_Z32_UNORM;
- case MESA_FORMAT_Z24_S8:
- return PIPE_FORMAT_S8_USCALED_Z24_UNORM;
- case MESA_FORMAT_S8_Z24:
- return PIPE_FORMAT_Z24_UNORM_S8_USCALED;
- case MESA_FORMAT_Z24_X8:
- return PIPE_FORMAT_X8Z24_UNORM;
- case MESA_FORMAT_X8_Z24:
- return PIPE_FORMAT_Z24X8_UNORM;
- case MESA_FORMAT_S8:
- return PIPE_FORMAT_S8_USCALED;
- case MESA_FORMAT_Z32_FLOAT:
- return PIPE_FORMAT_Z32_FLOAT;
- case MESA_FORMAT_Z32_FLOAT_X24S8:
- return PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED;
- case MESA_FORMAT_YCBCR:
- return PIPE_FORMAT_UYVY;
-#if FEATURE_texture_s3tc
- case MESA_FORMAT_RGB_DXT1:
- return PIPE_FORMAT_DXT1_RGB;
- case MESA_FORMAT_RGBA_DXT1:
- return PIPE_FORMAT_DXT1_RGBA;
- case MESA_FORMAT_RGBA_DXT3:
- return PIPE_FORMAT_DXT3_RGBA;
- case MESA_FORMAT_RGBA_DXT5:
- return PIPE_FORMAT_DXT5_RGBA;
-#if FEATURE_EXT_texture_sRGB
- case MESA_FORMAT_SRGB_DXT1:
- return PIPE_FORMAT_DXT1_SRGB;
- case MESA_FORMAT_SRGBA_DXT1:
- return PIPE_FORMAT_DXT1_SRGBA;
- case MESA_FORMAT_SRGBA_DXT3:
- return PIPE_FORMAT_DXT3_SRGBA;
- case MESA_FORMAT_SRGBA_DXT5:
- return PIPE_FORMAT_DXT5_SRGBA;
-#endif
-#endif
-#if FEATURE_EXT_texture_sRGB
- case MESA_FORMAT_SLA8:
- return PIPE_FORMAT_L8A8_SRGB;
- case MESA_FORMAT_SL8:
- return PIPE_FORMAT_L8_SRGB;
- case MESA_FORMAT_SRGB8:
- return PIPE_FORMAT_R8G8B8_SRGB;
- case MESA_FORMAT_SRGBA8:
- return PIPE_FORMAT_A8B8G8R8_SRGB;
- case MESA_FORMAT_SARGB8:
- return PIPE_FORMAT_B8G8R8A8_SRGB;
-#endif
- case MESA_FORMAT_RGBA_FLOAT32:
- return PIPE_FORMAT_R32G32B32A32_FLOAT;
- case MESA_FORMAT_RGBA_FLOAT16:
- return PIPE_FORMAT_R16G16B16A16_FLOAT;
- case MESA_FORMAT_RGB_FLOAT32:
- return PIPE_FORMAT_R32G32B32_FLOAT;
- case MESA_FORMAT_RGB_FLOAT16:
- return PIPE_FORMAT_R16G16B16_FLOAT;
- case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32:
- return PIPE_FORMAT_L32A32_FLOAT;
- case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16:
- return PIPE_FORMAT_L16A16_FLOAT;
- case MESA_FORMAT_LUMINANCE_FLOAT32:
- return PIPE_FORMAT_L32_FLOAT;
- case MESA_FORMAT_LUMINANCE_FLOAT16:
- return PIPE_FORMAT_L16_FLOAT;
- case MESA_FORMAT_ALPHA_FLOAT32:
- return PIPE_FORMAT_A32_FLOAT;
- case MESA_FORMAT_ALPHA_FLOAT16:
- return PIPE_FORMAT_A16_FLOAT;
- case MESA_FORMAT_INTENSITY_FLOAT32:
- return PIPE_FORMAT_I32_FLOAT;
- case MESA_FORMAT_INTENSITY_FLOAT16:
- return PIPE_FORMAT_I16_FLOAT;
- case MESA_FORMAT_R_FLOAT32:
- return PIPE_FORMAT_R32_FLOAT;
- case MESA_FORMAT_R_FLOAT16:
- return PIPE_FORMAT_R16_FLOAT;
- case MESA_FORMAT_RG_FLOAT32:
- return PIPE_FORMAT_R32G32_FLOAT;
- case MESA_FORMAT_RG_FLOAT16:
- return PIPE_FORMAT_R16G16_FLOAT;
-
- case MESA_FORMAT_R8:
- return PIPE_FORMAT_R8_UNORM;
- case MESA_FORMAT_R16:
- return PIPE_FORMAT_R16_UNORM;
- case MESA_FORMAT_RG88:
- return PIPE_FORMAT_R8G8_UNORM;
- case MESA_FORMAT_RG1616:
- return PIPE_FORMAT_R16G16_UNORM;
- case MESA_FORMAT_RGBA_16:
- return PIPE_FORMAT_R16G16B16A16_UNORM;
-
- /* signed int formats */
- case MESA_FORMAT_RGBA_INT8:
- return PIPE_FORMAT_R8G8B8A8_SSCALED;
- case MESA_FORMAT_RGBA_INT16:
- return PIPE_FORMAT_R16G16B16A16_SSCALED;
- case MESA_FORMAT_RGBA_INT32:
- return PIPE_FORMAT_R32G32B32A32_SSCALED;
-
- /* unsigned int formats */
- case MESA_FORMAT_RGBA_UINT8:
- return PIPE_FORMAT_R8G8B8A8_USCALED;
- case MESA_FORMAT_RGBA_UINT16:
- return PIPE_FORMAT_R16G16B16A16_USCALED;
- case MESA_FORMAT_RGBA_UINT32:
- return PIPE_FORMAT_R32G32B32A32_USCALED;
-
- case MESA_FORMAT_RED_RGTC1:
- return PIPE_FORMAT_RGTC1_UNORM;
- case MESA_FORMAT_SIGNED_RED_RGTC1:
- return PIPE_FORMAT_RGTC1_SNORM;
- case MESA_FORMAT_RG_RGTC2:
- return PIPE_FORMAT_RGTC2_UNORM;
- case MESA_FORMAT_SIGNED_RG_RGTC2:
- return PIPE_FORMAT_RGTC2_SNORM;
-
- case MESA_FORMAT_L_LATC1:
- return PIPE_FORMAT_LATC1_UNORM;
- case MESA_FORMAT_SIGNED_L_LATC1:
- return PIPE_FORMAT_LATC1_SNORM;
- case MESA_FORMAT_LA_LATC2:
- return PIPE_FORMAT_LATC2_UNORM;
- case MESA_FORMAT_SIGNED_LA_LATC2:
- return PIPE_FORMAT_LATC2_SNORM;
-
- /* signed normalized formats */
- case MESA_FORMAT_SIGNED_R8:
- return PIPE_FORMAT_R8_SNORM;
- case MESA_FORMAT_SIGNED_RG88_REV:
- return PIPE_FORMAT_R8G8_SNORM;
- case MESA_FORMAT_SIGNED_RGBA8888_REV:
- return PIPE_FORMAT_R8G8B8A8_SNORM;
-
- case MESA_FORMAT_SIGNED_A8:
- return PIPE_FORMAT_A8_SNORM;
- case MESA_FORMAT_SIGNED_L8:
- return PIPE_FORMAT_L8_SNORM;
- case MESA_FORMAT_SIGNED_AL88:
- return PIPE_FORMAT_L8A8_SNORM;
- case MESA_FORMAT_SIGNED_I8:
- return PIPE_FORMAT_I8_SNORM;
-
- case MESA_FORMAT_SIGNED_R16:
- return PIPE_FORMAT_R16_SNORM;
- case MESA_FORMAT_SIGNED_GR1616:
- return PIPE_FORMAT_R16G16_SNORM;
- case MESA_FORMAT_SIGNED_RGBA_16:
- return PIPE_FORMAT_R16G16B16A16_SNORM;
-
- case MESA_FORMAT_SIGNED_A16:
- return PIPE_FORMAT_A16_SNORM;
- case MESA_FORMAT_SIGNED_L16:
- return PIPE_FORMAT_L16_SNORM;
- case MESA_FORMAT_SIGNED_AL1616:
- return PIPE_FORMAT_L16A16_SNORM;
- case MESA_FORMAT_SIGNED_I16:
- return PIPE_FORMAT_I16_SNORM;
-
- case MESA_FORMAT_RGB9_E5_FLOAT:
- return PIPE_FORMAT_R9G9B9E5_FLOAT;
- case MESA_FORMAT_R11_G11_B10_FLOAT:
- return PIPE_FORMAT_R11G11B10_FLOAT;
-
- default:
- assert(0);
- return PIPE_FORMAT_NONE;
- }
-}
-
-
-/**
- * Translate Gallium format to Mesa format.
- */
-gl_format
-st_pipe_format_to_mesa_format(enum pipe_format format)
-{
- switch (format) {
- case PIPE_FORMAT_A8B8G8R8_UNORM:
- return MESA_FORMAT_RGBA8888;
- case PIPE_FORMAT_R8G8B8A8_UNORM:
- return MESA_FORMAT_RGBA8888_REV;
- case PIPE_FORMAT_B8G8R8A8_UNORM:
- return MESA_FORMAT_ARGB8888;
- case PIPE_FORMAT_A8R8G8B8_UNORM:
- return MESA_FORMAT_ARGB8888_REV;
- case PIPE_FORMAT_B8G8R8X8_UNORM:
- return MESA_FORMAT_XRGB8888;
- case PIPE_FORMAT_X8R8G8B8_UNORM:
- return MESA_FORMAT_XRGB8888_REV;
- case PIPE_FORMAT_B5G5R5A1_UNORM:
- return MESA_FORMAT_ARGB1555;
- case PIPE_FORMAT_B4G4R4A4_UNORM:
- return MESA_FORMAT_ARGB4444;
- case PIPE_FORMAT_B5G6R5_UNORM:
- return MESA_FORMAT_RGB565;
- case PIPE_FORMAT_B2G3R3_UNORM:
- return MESA_FORMAT_RGB332;
- case PIPE_FORMAT_B10G10R10A2_UNORM:
- return MESA_FORMAT_ARGB2101010;
- case PIPE_FORMAT_L4A4_UNORM:
- return MESA_FORMAT_AL44;
- case PIPE_FORMAT_L8A8_UNORM:
- return MESA_FORMAT_AL88;
- case PIPE_FORMAT_L16A16_UNORM:
- return MESA_FORMAT_AL1616;
- case PIPE_FORMAT_A8_UNORM:
- return MESA_FORMAT_A8;
- case PIPE_FORMAT_A16_UNORM:
- return MESA_FORMAT_A16;
- case PIPE_FORMAT_L8_UNORM:
- return MESA_FORMAT_L8;
- case PIPE_FORMAT_L16_UNORM:
- return MESA_FORMAT_L16;
- case PIPE_FORMAT_I8_UNORM:
- return MESA_FORMAT_I8;
- case PIPE_FORMAT_I16_UNORM:
- return MESA_FORMAT_I16;
- case PIPE_FORMAT_S8_USCALED:
- return MESA_FORMAT_S8;
-
- case PIPE_FORMAT_R16G16B16A16_UNORM:
- return MESA_FORMAT_RGBA_16;
-
- case PIPE_FORMAT_Z16_UNORM:
- return MESA_FORMAT_Z16;
- case PIPE_FORMAT_Z32_UNORM:
- return MESA_FORMAT_Z32;
- case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
- return MESA_FORMAT_Z24_S8;
- case PIPE_FORMAT_X8Z24_UNORM:
- return MESA_FORMAT_Z24_X8;
- case PIPE_FORMAT_Z24X8_UNORM:
- return MESA_FORMAT_X8_Z24;
- case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
- return MESA_FORMAT_S8_Z24;
- case PIPE_FORMAT_Z32_FLOAT:
- return MESA_FORMAT_Z32_FLOAT;
- case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED:
- return MESA_FORMAT_Z32_FLOAT_X24S8;
-
- case PIPE_FORMAT_UYVY:
- return MESA_FORMAT_YCBCR;
- case PIPE_FORMAT_YUYV:
- return MESA_FORMAT_YCBCR_REV;
-
-#if FEATURE_texture_s3tc
- case PIPE_FORMAT_DXT1_RGB:
- return MESA_FORMAT_RGB_DXT1;
- case PIPE_FORMAT_DXT1_RGBA:
- return MESA_FORMAT_RGBA_DXT1;
- case PIPE_FORMAT_DXT3_RGBA:
- return MESA_FORMAT_RGBA_DXT3;
- case PIPE_FORMAT_DXT5_RGBA:
- return MESA_FORMAT_RGBA_DXT5;
-#if FEATURE_EXT_texture_sRGB
- case PIPE_FORMAT_DXT1_SRGB:
- return MESA_FORMAT_SRGB_DXT1;
- case PIPE_FORMAT_DXT1_SRGBA:
- return MESA_FORMAT_SRGBA_DXT1;
- case PIPE_FORMAT_DXT3_SRGBA:
- return MESA_FORMAT_SRGBA_DXT3;
- case PIPE_FORMAT_DXT5_SRGBA:
- return MESA_FORMAT_SRGBA_DXT5;
-#endif
-#endif
-
-#if FEATURE_EXT_texture_sRGB
- case PIPE_FORMAT_L8A8_SRGB:
- return MESA_FORMAT_SLA8;
- case PIPE_FORMAT_L8_SRGB:
- return MESA_FORMAT_SL8;
- case PIPE_FORMAT_R8G8B8_SRGB:
- return MESA_FORMAT_SRGB8;
- case PIPE_FORMAT_A8B8G8R8_SRGB:
- return MESA_FORMAT_SRGBA8;
- case PIPE_FORMAT_B8G8R8A8_SRGB:
- return MESA_FORMAT_SARGB8;
-#endif
- case PIPE_FORMAT_R32G32B32A32_FLOAT:
- return MESA_FORMAT_RGBA_FLOAT32;
- case PIPE_FORMAT_R16G16B16A16_FLOAT:
- return MESA_FORMAT_RGBA_FLOAT16;
- case PIPE_FORMAT_R32G32B32_FLOAT:
- return MESA_FORMAT_RGB_FLOAT32;
- case PIPE_FORMAT_R16G16B16_FLOAT:
- return MESA_FORMAT_RGB_FLOAT16;
- case PIPE_FORMAT_L32A32_FLOAT:
- return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32;
- case PIPE_FORMAT_L16A16_FLOAT:
- return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16;
- case PIPE_FORMAT_L32_FLOAT:
- return MESA_FORMAT_LUMINANCE_FLOAT32;
- case PIPE_FORMAT_L16_FLOAT:
- return MESA_FORMAT_LUMINANCE_FLOAT16;
- case PIPE_FORMAT_A32_FLOAT:
- return MESA_FORMAT_ALPHA_FLOAT32;
- case PIPE_FORMAT_A16_FLOAT:
- return MESA_FORMAT_ALPHA_FLOAT16;
- case PIPE_FORMAT_I32_FLOAT:
- return MESA_FORMAT_INTENSITY_FLOAT32;
- case PIPE_FORMAT_I16_FLOAT:
- return MESA_FORMAT_INTENSITY_FLOAT16;
- case PIPE_FORMAT_R32_FLOAT:
- return MESA_FORMAT_R_FLOAT32;
- case PIPE_FORMAT_R16_FLOAT:
- return MESA_FORMAT_R_FLOAT16;
- case PIPE_FORMAT_R32G32_FLOAT:
- return MESA_FORMAT_RG_FLOAT32;
- case PIPE_FORMAT_R16G16_FLOAT:
- return MESA_FORMAT_RG_FLOAT16;
-
- case PIPE_FORMAT_R8_UNORM:
- return MESA_FORMAT_R8;
- case PIPE_FORMAT_R16_UNORM:
- return MESA_FORMAT_R16;
- case PIPE_FORMAT_R8G8_UNORM:
- return MESA_FORMAT_RG88;
- case PIPE_FORMAT_R16G16_UNORM:
- return MESA_FORMAT_RG1616;
-
- /* signed int formats */
- case PIPE_FORMAT_R8G8B8A8_SSCALED:
- return MESA_FORMAT_RGBA_INT8;
- case PIPE_FORMAT_R16G16B16A16_SSCALED:
- return MESA_FORMAT_RGBA_INT16;
- case PIPE_FORMAT_R32G32B32A32_SSCALED:
- return MESA_FORMAT_RGBA_INT32;
-
- /* unsigned int formats */
- case PIPE_FORMAT_R8G8B8A8_USCALED:
- return MESA_FORMAT_RGBA_UINT8;
- case PIPE_FORMAT_R16G16B16A16_USCALED:
- return MESA_FORMAT_RGBA_UINT16;
- case PIPE_FORMAT_R32G32B32A32_USCALED:
- return MESA_FORMAT_RGBA_UINT32;
-
- case PIPE_FORMAT_RGTC1_UNORM:
- return MESA_FORMAT_RED_RGTC1;
- case PIPE_FORMAT_RGTC1_SNORM:
- return MESA_FORMAT_SIGNED_RED_RGTC1;
- case PIPE_FORMAT_RGTC2_UNORM:
- return MESA_FORMAT_RG_RGTC2;
- case PIPE_FORMAT_RGTC2_SNORM:
- return MESA_FORMAT_SIGNED_RG_RGTC2;
-
- case PIPE_FORMAT_LATC1_UNORM:
- return MESA_FORMAT_L_LATC1;
- case PIPE_FORMAT_LATC1_SNORM:
- return MESA_FORMAT_SIGNED_L_LATC1;
- case PIPE_FORMAT_LATC2_UNORM:
- return MESA_FORMAT_LA_LATC2;
- case PIPE_FORMAT_LATC2_SNORM:
- return MESA_FORMAT_SIGNED_LA_LATC2;
-
- /* signed normalized formats */
- case PIPE_FORMAT_R8_SNORM:
- return MESA_FORMAT_SIGNED_R8;
- case PIPE_FORMAT_R8G8_SNORM:
- return MESA_FORMAT_SIGNED_RG88_REV;
- case PIPE_FORMAT_R8G8B8A8_SNORM:
- return MESA_FORMAT_SIGNED_RGBA8888_REV;
-
- case PIPE_FORMAT_A8_SNORM:
- return MESA_FORMAT_SIGNED_A8;
- case PIPE_FORMAT_L8_SNORM:
- return MESA_FORMAT_SIGNED_L8;
- case PIPE_FORMAT_L8A8_SNORM:
- return MESA_FORMAT_SIGNED_AL88;
- case PIPE_FORMAT_I8_SNORM:
- return MESA_FORMAT_SIGNED_I8;
-
- case PIPE_FORMAT_R16_SNORM:
- return MESA_FORMAT_SIGNED_R16;
- case PIPE_FORMAT_R16G16_SNORM:
- return MESA_FORMAT_SIGNED_GR1616;
- case PIPE_FORMAT_R16G16B16A16_SNORM:
- return MESA_FORMAT_SIGNED_RGBA_16;
-
- case PIPE_FORMAT_A16_SNORM:
- return MESA_FORMAT_SIGNED_A16;
- case PIPE_FORMAT_L16_SNORM:
- return MESA_FORMAT_SIGNED_L16;
- case PIPE_FORMAT_L16A16_SNORM:
- return MESA_FORMAT_SIGNED_AL1616;
- case PIPE_FORMAT_I16_SNORM:
- return MESA_FORMAT_SIGNED_I16;
-
- case PIPE_FORMAT_R9G9B9E5_FLOAT:
- return MESA_FORMAT_RGB9_E5_FLOAT;
- case PIPE_FORMAT_R11G11B10_FLOAT:
- return MESA_FORMAT_R11_G11_B10_FLOAT;
-
- default:
- assert(0);
- return MESA_FORMAT_NONE;
- }
-}
-
-
-/**
- * Map GL texture formats to Gallium pipe formats.
- */
-struct format_mapping
-{
- GLenum glFormats[18]; /**< list of GLenum formats, 0-terminated */
- enum pipe_format pipeFormats[10]; /**< list of pipe formats, 0-terminated */
-};
-
-
-#define DEFAULT_RGBA_FORMATS \
- PIPE_FORMAT_B8G8R8A8_UNORM, \
- PIPE_FORMAT_A8R8G8B8_UNORM, \
- PIPE_FORMAT_A8B8G8R8_UNORM, \
- PIPE_FORMAT_B5G6R5_UNORM, \
- 0
-
-#define DEFAULT_RGB_FORMATS \
- PIPE_FORMAT_B8G8R8X8_UNORM, \
- PIPE_FORMAT_X8R8G8B8_UNORM, \
- PIPE_FORMAT_X8B8G8R8_UNORM, \
- PIPE_FORMAT_B8G8R8A8_UNORM, \
- PIPE_FORMAT_A8R8G8B8_UNORM, \
- PIPE_FORMAT_A8B8G8R8_UNORM, \
- PIPE_FORMAT_B5G6R5_UNORM, \
- 0
-
-#define DEFAULT_SRGBA_FORMATS \
- PIPE_FORMAT_B8G8R8A8_SRGB, \
- PIPE_FORMAT_A8R8G8B8_SRGB, \
- PIPE_FORMAT_A8B8G8R8_SRGB, \
- 0
-
-#define DEFAULT_DEPTH_FORMATS \
- PIPE_FORMAT_Z24X8_UNORM, \
- PIPE_FORMAT_X8Z24_UNORM, \
- PIPE_FORMAT_Z16_UNORM, \
- PIPE_FORMAT_Z24_UNORM_S8_USCALED, \
- PIPE_FORMAT_S8_USCALED_Z24_UNORM, \
- 0
-
-/**
- * This table maps OpenGL texture format enums to Gallium pipe_format enums.
- * Multiple GL enums might map to multiple pipe_formats.
- * The first pipe format in the list that's supported is the one that's chosen.
- */
-static const struct format_mapping format_map[] = {
- /* Basic RGB, RGBA formats */
- {
- { GL_RGB10, GL_RGB10_A2, 0 },
- { PIPE_FORMAT_B10G10R10A2_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { 4, GL_RGBA, GL_RGBA8, 0 },
- { PIPE_FORMAT_R8G8B8A8_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_BGRA, 0 },
- { PIPE_FORMAT_B8G8R8A8_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { 3, GL_RGB, GL_RGB8, 0 },
- { DEFAULT_RGB_FORMATS }
- },
- {
- { GL_RGB12, GL_RGB16, GL_RGBA12, GL_RGBA16, 0 },
- { PIPE_FORMAT_R16G16B16A16_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_RGBA4, GL_RGBA2, 0 },
- { PIPE_FORMAT_B4G4R4A4_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_RGB5_A1, 0 },
- { PIPE_FORMAT_B5G5R5A1_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_R3_G3_B2, 0 },
- { PIPE_FORMAT_B2G3R3_UNORM, PIPE_FORMAT_B5G6R5_UNORM,
- PIPE_FORMAT_B5G5R5A1_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_RGB5, GL_RGB4 },
- { PIPE_FORMAT_B5G6R5_UNORM, PIPE_FORMAT_B5G5R5A1_UNORM,
- DEFAULT_RGBA_FORMATS }
- },
-
- /* basic Alpha formats */
- {
- { GL_ALPHA12, GL_ALPHA16, 0 },
- { PIPE_FORMAT_A16_UNORM, PIPE_FORMAT_A8_UNORM,
- DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_COMPRESSED_ALPHA, 0 },
- { PIPE_FORMAT_A8_UNORM, DEFAULT_RGBA_FORMATS }
- },
-
- /* basic Luminance formats */
- {
- { GL_LUMINANCE12, GL_LUMINANCE16, 0 },
- { PIPE_FORMAT_L16_UNORM, PIPE_FORMAT_L8_UNORM, DEFAULT_RGB_FORMATS }
- },
- {
- { 1, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, 0 },
- { PIPE_FORMAT_L8_UNORM, DEFAULT_RGB_FORMATS }
- },
-
- /* basic Luminance/Alpha formats */
- {
- { GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12,
- GL_LUMINANCE16_ALPHA16, 0},
- { PIPE_FORMAT_L16A16_UNORM, PIPE_FORMAT_L8A8_UNORM,
- DEFAULT_RGBA_FORMATS }
- },
- {
- { 2, GL_LUMINANCE_ALPHA, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, 0 },
- { PIPE_FORMAT_L8A8_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_LUMINANCE4_ALPHA4, 0 },
- { PIPE_FORMAT_L4A4_UNORM, PIPE_FORMAT_L8A8_UNORM,
- DEFAULT_RGBA_FORMATS }
- },
-
- /* basic Intensity formats */
- {
- { GL_INTENSITY12, GL_INTENSITY16, 0 },
- { PIPE_FORMAT_I16_UNORM, PIPE_FORMAT_I8_UNORM, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8,
- GL_COMPRESSED_INTENSITY, 0 },
- { PIPE_FORMAT_I8_UNORM, DEFAULT_RGBA_FORMATS }
- },
-
- /* YCbCr */
- {
- { GL_YCBCR_MESA, 0 },
- { PIPE_FORMAT_UYVY, PIPE_FORMAT_YUYV, 0 }
- },
-
- /* compressed formats */ /* XXX PIPE_BIND_SAMPLER_VIEW only */
- {
- { GL_COMPRESSED_RGB, 0 },
- { PIPE_FORMAT_DXT1_RGB, DEFAULT_RGB_FORMATS }
- },
- {
- { GL_COMPRESSED_RGBA, 0 },
- { PIPE_FORMAT_DXT5_RGBA, DEFAULT_RGBA_FORMATS }
- },
- {
- { GL_RGB_S3TC, GL_RGB4_S3TC, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0 },
- { PIPE_FORMAT_DXT1_RGB, 0 }
- },
- {
- { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 },
- { PIPE_FORMAT_DXT1_RGBA, 0 }
- },
- {
- { GL_RGBA_S3TC, GL_RGBA4_S3TC, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 },
- { PIPE_FORMAT_DXT3_RGBA, 0 }
- },
- {
- { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 },
- { PIPE_FORMAT_DXT5_RGBA, 0 }
- },
-
-#if 0
- {
- { GL_COMPRESSED_RGB_FXT1_3DFX, 0 },
- { PIPE_FORMAT_RGB_FXT1, 0 }
- },
- {
- { GL_COMPRESSED_RGBA_FXT1_3DFX, 0 },
- { PIPE_FORMAT_RGBA_FXT1, 0 }
- },
-#endif
-
- /* Depth formats */
- {
- { GL_DEPTH_COMPONENT16, 0 },
- { PIPE_FORMAT_Z16_UNORM, DEFAULT_DEPTH_FORMATS }
- },
- {
- { GL_DEPTH_COMPONENT24, 0 },
- { PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM,
- DEFAULT_DEPTH_FORMATS }
- },
- {
- { GL_DEPTH_COMPONENT32, 0 },
- { PIPE_FORMAT_Z32_UNORM, DEFAULT_DEPTH_FORMATS }
- },
- {
- { GL_DEPTH_COMPONENT, 0 },
- { DEFAULT_DEPTH_FORMATS }
- },
- {
- { GL_DEPTH_COMPONENT32F, 0 },
- { PIPE_FORMAT_Z32_FLOAT, 0 }
- },
-
- /* stencil formats */
- {
- { GL_STENCIL_INDEX, GL_STENCIL_INDEX1_EXT, GL_STENCIL_INDEX4_EXT,
- GL_STENCIL_INDEX8_EXT, GL_STENCIL_INDEX16_EXT, 0 },
- {
- PIPE_FORMAT_S8_USCALED, PIPE_FORMAT_Z24_UNORM_S8_USCALED,
- PIPE_FORMAT_S8_USCALED_Z24_UNORM, 0
- }
- },
-
- /* Depth / Stencil formats */
- {
- { GL_DEPTH_STENCIL_EXT, GL_DEPTH24_STENCIL8_EXT, 0 },
- { PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM, 0 }
- },
- {
- { GL_DEPTH32F_STENCIL8, 0 },
- { PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED, 0 }
- },
-
- /* sRGB formats */
- {
- { GL_SRGB_EXT, GL_SRGB8_EXT, GL_SRGB_ALPHA_EXT, GL_SRGB8_ALPHA8_EXT, 0 },
- { DEFAULT_SRGBA_FORMATS }
- },
- {
- { GL_COMPRESSED_SRGB_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, 0 },
- { PIPE_FORMAT_DXT1_SRGB, DEFAULT_SRGBA_FORMATS }
- },
- {
- { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 },
- { PIPE_FORMAT_DXT1_SRGBA, 0 }
- },
- {
- { GL_COMPRESSED_SRGB_ALPHA_EXT,
- GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 },
- { PIPE_FORMAT_DXT3_SRGBA, DEFAULT_SRGBA_FORMATS }
- },
- {
- { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 },
- { PIPE_FORMAT_DXT5_SRGBA, 0 }
- },
- {
- { GL_SLUMINANCE_ALPHA_EXT, GL_SLUMINANCE8_ALPHA8_EXT,
- GL_COMPRESSED_SLUMINANCE_EXT, GL_COMPRESSED_SLUMINANCE_ALPHA_EXT, 0 },
- { PIPE_FORMAT_L8A8_SRGB, DEFAULT_SRGBA_FORMATS }
- },
- {
- { GL_SLUMINANCE_EXT, GL_SLUMINANCE8_EXT, 0 },
- { PIPE_FORMAT_L8_SRGB, DEFAULT_SRGBA_FORMATS }
- },
-
- /* 16-bit float formats */
- {
- { GL_RGBA16F_ARB, 0 },
- { PIPE_FORMAT_R16G16B16A16_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
- {
- { GL_RGB16F_ARB, 0 },
- { PIPE_FORMAT_R16G16B16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_FORMAT_R32G32B32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
- {
- { GL_LUMINANCE_ALPHA16F_ARB, 0 },
- { PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
- {
- { GL_ALPHA16F_ARB, 0 },
- { PIPE_FORMAT_A16_FLOAT, PIPE_FORMAT_L16A16_FLOAT,
- PIPE_FORMAT_A32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
- {
- { GL_INTENSITY16F_ARB, 0 },
- { PIPE_FORMAT_I16_FLOAT, PIPE_FORMAT_L16A16_FLOAT,
- PIPE_FORMAT_I32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
- {
- { GL_LUMINANCE16F_ARB, 0 },
- { PIPE_FORMAT_L16_FLOAT, PIPE_FORMAT_L16A16_FLOAT,
- PIPE_FORMAT_L32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
- {
- { GL_R16F, 0 },
- { PIPE_FORMAT_R16_FLOAT, PIPE_FORMAT_R16G16_FLOAT,
- PIPE_FORMAT_R32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
- {
- { GL_RG16F, 0 },
- { PIPE_FORMAT_R16G16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT,
- PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 }
- },
-
- /* 32-bit float formats */
- {
- { GL_RGBA32F_ARB, 0 },
- { PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
- {
- { GL_RGB32F_ARB, 0 },
- { PIPE_FORMAT_R32G32B32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT,
- PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
- {
- { GL_LUMINANCE_ALPHA32F_ARB, 0 },
- { PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT,
- PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
- {
- { GL_ALPHA32F_ARB, 0 },
- { PIPE_FORMAT_A32_FLOAT, PIPE_FORMAT_L32A32_FLOAT,
- PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_A16_FLOAT,
- PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
- {
- { GL_INTENSITY32F_ARB, 0 },
- { PIPE_FORMAT_I32_FLOAT, PIPE_FORMAT_L32A32_FLOAT,
- PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_I16_FLOAT,
- PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
- {
- { GL_LUMINANCE32F_ARB, 0 },
- { PIPE_FORMAT_L32_FLOAT, PIPE_FORMAT_L32A32_FLOAT,
- PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_L16_FLOAT,
- PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
- {
- { GL_R32F, 0 },
- { PIPE_FORMAT_R32_FLOAT, PIPE_FORMAT_R32G32_FLOAT,
- PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_R16_FLOAT,
- PIPE_FORMAT_R16G16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
- {
- { GL_RG32F, 0 },
- { PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT,
- PIPE_FORMAT_R16G16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 }
- },
-
- /* R, RG formats */
- {
- { GL_RED, GL_R8, 0 },
- { PIPE_FORMAT_R8_UNORM, 0 }
- },
- {
- { GL_RG, GL_RG8, 0 },
- { PIPE_FORMAT_R8G8_UNORM, 0 }
- },
- {
- { GL_R16, 0 },
- { PIPE_FORMAT_R16_UNORM, 0 }
- },
- {
- { GL_RG16, 0 },
- { PIPE_FORMAT_R16G16_UNORM, 0 }
- },
-
- /* compressed R, RG formats */
- {
- { GL_COMPRESSED_RED, GL_COMPRESSED_RED_RGTC1, 0 },
- { PIPE_FORMAT_RGTC1_UNORM, PIPE_FORMAT_R8_UNORM, 0 }
- },
- {
- { GL_COMPRESSED_SIGNED_RED_RGTC1, 0 },
- { PIPE_FORMAT_RGTC1_SNORM, 0 }
- },
- {
- { GL_COMPRESSED_RG, GL_COMPRESSED_RG_RGTC2, 0 },
- { PIPE_FORMAT_RGTC2_UNORM, PIPE_FORMAT_R8G8_UNORM, 0 }
- },
- {
- { GL_COMPRESSED_SIGNED_RG_RGTC2, 0 },
- { PIPE_FORMAT_RGTC2_SNORM, 0 }
- },
- {
- { GL_COMPRESSED_LUMINANCE, GL_COMPRESSED_LUMINANCE_LATC1_EXT, 0 },
- { PIPE_FORMAT_LATC1_UNORM, PIPE_FORMAT_L8_UNORM, 0 }
- },
- {
- { GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT, 0 },
- { PIPE_FORMAT_LATC1_SNORM, 0 }
- },
- {
- { GL_COMPRESSED_LUMINANCE_ALPHA, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT,
- GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI, 0 },
- { PIPE_FORMAT_LATC2_UNORM, PIPE_FORMAT_L8A8_UNORM, 0 }
- },
- {
- { GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT, 0 },
- { PIPE_FORMAT_LATC2_SNORM, 0 }
- },
-
- /* signed/unsigned integer formats.
- * XXX Mesa only has formats for RGBA signed/unsigned integer formats.
- * If/when new formats are added this code should be updated.
- */
- {
- { GL_RED_INTEGER_EXT,
- GL_GREEN_INTEGER_EXT,
- GL_BLUE_INTEGER_EXT,
- GL_ALPHA_INTEGER_EXT,
- GL_RGB_INTEGER_EXT,
- GL_RGBA_INTEGER_EXT,
- GL_BGR_INTEGER_EXT,
- GL_BGRA_INTEGER_EXT,
- GL_LUMINANCE_INTEGER_EXT,
- GL_LUMINANCE_ALPHA_INTEGER_EXT,
- GL_RGBA8I_EXT,
- GL_RGB8I_EXT,
- GL_ALPHA8I_EXT,
- GL_INTENSITY8I_EXT,
- GL_LUMINANCE8I_EXT,
- GL_LUMINANCE_ALPHA8I_EXT, 0 },
- { PIPE_FORMAT_R8G8B8A8_SSCALED, 0 }
- },
- {
- {
- GL_RGBA16I_EXT,
- GL_RGB16I_EXT,
- GL_ALPHA16I_EXT,
- GL_INTENSITY16I_EXT,
- GL_LUMINANCE16I_EXT,
- GL_LUMINANCE_ALPHA16I_EXT, 0 },
- { PIPE_FORMAT_R16G16B16A16_SSCALED, 0 },
- },
- {
- {
- GL_RGBA32I_EXT,
- GL_RGB32I_EXT,
- GL_ALPHA32I_EXT,
- GL_INTENSITY32I_EXT,
- GL_LUMINANCE32I_EXT,
- GL_LUMINANCE_ALPHA32I_EXT, 0 },
- { PIPE_FORMAT_R32G32B32A32_SSCALED, 0 }
- },
- {
- {
- GL_RGBA8UI_EXT,
- GL_RGB8UI_EXT,
- GL_ALPHA8UI_EXT,
- GL_INTENSITY8UI_EXT,
- GL_LUMINANCE8UI_EXT,
- GL_LUMINANCE_ALPHA8UI_EXT, 0 },
- { PIPE_FORMAT_R8G8B8A8_USCALED, 0 }
- },
- {
- {
- GL_RGBA16UI_EXT,
- GL_RGB16UI_EXT,
- GL_ALPHA16UI_EXT,
- GL_INTENSITY16UI_EXT,
- GL_LUMINANCE16UI_EXT,
- GL_LUMINANCE_ALPHA16UI_EXT, 0 },
- { PIPE_FORMAT_R16G16B16A16_USCALED, 0 }
- },
- {
- {
- GL_RGBA32UI_EXT,
- GL_RGB32UI_EXT,
- GL_ALPHA32UI_EXT,
- GL_INTENSITY32UI_EXT,
- GL_LUMINANCE32UI_EXT,
- GL_LUMINANCE_ALPHA32UI_EXT, 0 },
- { PIPE_FORMAT_R32G32B32A32_USCALED, 0 }
- },
-
- /* signed normalized formats */
- {
- { GL_RED_SNORM, GL_R8_SNORM, 0 },
- { PIPE_FORMAT_R8_SNORM, PIPE_FORMAT_R8G8_SNORM,
- PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_R16_SNORM, 0 },
- { PIPE_FORMAT_R16_SNORM,
- PIPE_FORMAT_R16G16_SNORM,
- PIPE_FORMAT_R16G16B16A16_SNORM,
- PIPE_FORMAT_R8_SNORM,
- PIPE_FORMAT_R8G8_SNORM,
- PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_RG_SNORM, GL_RG8_SNORM, 0 },
- { PIPE_FORMAT_R8G8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_RG16_SNORM, 0 },
- { PIPE_FORMAT_R16G16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM,
- PIPE_FORMAT_R8G8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_RGB_SNORM, GL_RGB8_SNORM, GL_RGBA_SNORM, GL_RGBA8_SNORM, 0 },
- { PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_RGB16_SNORM, GL_RGBA16_SNORM, 0 },
- { PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_ALPHA_SNORM, GL_ALPHA8_SNORM, 0 },
- { PIPE_FORMAT_A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_ALPHA16_SNORM, 0 },
- { PIPE_FORMAT_A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM,
- PIPE_FORMAT_A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_LUMINANCE_SNORM, GL_LUMINANCE8_SNORM, 0 },
- { PIPE_FORMAT_L8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_LUMINANCE16_SNORM, 0 },
- { PIPE_FORMAT_L16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM,
- PIPE_FORMAT_L8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_LUMINANCE_ALPHA_SNORM, GL_LUMINANCE8_ALPHA8_SNORM, 0 },
- { PIPE_FORMAT_L8A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_LUMINANCE16_ALPHA16_SNORM, 0 },
- { PIPE_FORMAT_L16A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM,
- PIPE_FORMAT_L8A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_INTENSITY_SNORM, GL_INTENSITY8_SNORM, 0 },
- { PIPE_FORMAT_I8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_INTENSITY16_SNORM, 0 },
- { PIPE_FORMAT_I16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM,
- PIPE_FORMAT_I8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 }
- },
- {
- { GL_RGB9_E5, 0 },
- { PIPE_FORMAT_R9G9B9E5_FLOAT, 0 }
- },
- {
- { GL_R11F_G11F_B10F, 0 },
- { PIPE_FORMAT_R11G11B10_FLOAT, 0 }
- }
-};
-
-
-/**
- * Return first supported format from the given list.
- */
-static enum pipe_format
-find_supported_format(struct pipe_screen *screen,
- const enum pipe_format formats[],
- enum pipe_texture_target target,
- unsigned sample_count,
- unsigned tex_usage)
-{
- uint i;
- for (i = 0; formats[i]; i++) {
- if (screen->is_format_supported(screen, formats[i], target,
- sample_count, tex_usage)) {
- return formats[i];
- }
- }
- return PIPE_FORMAT_NONE;
-}
-
-struct exact_format_mapping
-{
- GLenum format;
- GLenum type;
- enum pipe_format pformat;
-};
-
-static const struct exact_format_mapping rgba8888_tbl[] =
-{
- { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_A8B8G8R8_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_A8B8G8R8_UNORM },
- { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_R8G8B8A8_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_R8G8B8A8_UNORM },
- { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_A8R8G8B8_UNORM },
- { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_B8G8R8A8_UNORM },
- { GL_RGBA, GL_UNSIGNED_BYTE, PIPE_FORMAT_R8G8B8A8_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_BYTE, PIPE_FORMAT_A8B8G8R8_UNORM },
- { GL_BGRA, GL_UNSIGNED_BYTE, PIPE_FORMAT_B8G8R8A8_UNORM },
- { 0, 0, 0 }
-};
-
-static const struct exact_format_mapping rgbx8888_tbl[] =
-{
- { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_X8R8G8B8_UNORM },
- { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_B8G8R8X8_UNORM },
- { GL_BGRA, GL_UNSIGNED_BYTE, PIPE_FORMAT_B8G8R8X8_UNORM },
- /* No Mesa formats for these Gallium formats:
- { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_X8B8G8R8_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_X8B8G8R8_UNORM },
- { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_R8G8B8X8_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_R8G8B8X8_UNORM },
- { GL_RGBA, GL_UNSIGNED_BYTE, PIPE_FORMAT_R8G8B8X8_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_BYTE, PIPE_FORMAT_X8B8G8R8_UNORM },
- */
- { 0, 0, 0 }
-};
-
-static const struct exact_format_mapping rgba1010102_tbl[] =
-{
- { GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, PIPE_FORMAT_B10G10R10A2_UNORM },
- /* No Mesa formats for these Gallium formats:
- { GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, PIPE_FORMAT_R10G10B10A2_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_INT_10_10_10_2, PIPE_FORMAT_R10G10B10A2_UNORM },
- { GL_ABGR_EXT, GL_UNSIGNED_INT, PIPE_FORMAT_R10G10B10A2_UNORM },
- */
- { 0, 0, 0 }
-};
-
-/**
- * If there is an exact pipe_format match for {internalFormat, format, type}
- * return that, otherwise return PIPE_FORMAT_NONE so we can do fuzzy matching.
- */
-static enum pipe_format
-find_exact_format(GLint internalFormat, GLenum format, GLenum type)
-{
- uint i;
- const struct exact_format_mapping* tbl;
-
- if (format == GL_NONE || type == GL_NONE)
- return PIPE_FORMAT_NONE;
-
- switch (internalFormat) {
- case 4:
- case GL_RGBA:
- case GL_RGBA8:
- tbl = rgba8888_tbl;
- break;
- case 3:
- case GL_RGB:
- case GL_RGB8:
- tbl = rgbx8888_tbl;
- break;
- case GL_RGB10_A2:
- tbl = rgba1010102_tbl;
- break;
- default:
- return PIPE_FORMAT_NONE;
- }
-
- for (i = 0; tbl[i].format; i++)
- if (tbl[i].format == format && tbl[i].type == type)
- return tbl[i].pformat;
-
- return PIPE_FORMAT_NONE;
-}
-
-/**
- * Given an OpenGL internalFormat value for a texture or surface, return
- * the best matching PIPE_FORMAT_x, or PIPE_FORMAT_NONE if there's no match.
- * This is called during glTexImage2D, for example.
- *
- * The bindings parameter typically has PIPE_BIND_SAMPLER_VIEW set, plus
- * either PIPE_BINDING_RENDER_TARGET or PIPE_BINDING_DEPTH_STENCIL if
- * we want render-to-texture ability.
- *
- * \param internalFormat the user value passed to glTexImage2D
- * \param target one of PIPE_TEXTURE_x
- * \param bindings bitmask of PIPE_BIND_x flags.
- */
-enum pipe_format
-st_choose_format(struct pipe_screen *screen, GLenum internalFormat,
- GLenum format, GLenum type,
- enum pipe_texture_target target, unsigned sample_count,
- unsigned bindings)
-{
- GET_CURRENT_CONTEXT(ctx); /* XXX this should be a function parameter */
- int i, j;
- enum pipe_format pf;
-
- /* can't render to compressed formats at this time */
- if (_mesa_is_compressed_format(ctx, internalFormat)
- && (bindings & ~PIPE_BIND_SAMPLER_VIEW)) {
- return PIPE_FORMAT_NONE;
- }
-
- /* search for exact matches */
- pf = find_exact_format(internalFormat, format, type);
- if (pf != PIPE_FORMAT_NONE &&
- screen->is_format_supported(screen, pf,
- target, sample_count, bindings))
- return pf;
-
- /* search table for internalFormat */
- for (i = 0; i < Elements(format_map); i++) {
- const struct format_mapping *mapping = &format_map[i];
- for (j = 0; mapping->glFormats[j]; j++) {
- if (mapping->glFormats[j] == internalFormat) {
- /* Found the desired internal format. Find first pipe format
- * which is supported by the driver.
- */
- return find_supported_format(screen, mapping->pipeFormats,
- target, sample_count, bindings);
- }
- }
- }
-
- _mesa_problem(NULL, "unhandled format!\n");
- return PIPE_FORMAT_NONE;
-}
-
-
-/**
- * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces.
- */
-enum pipe_format
-st_choose_renderbuffer_format(struct pipe_screen *screen,
- GLenum internalFormat, unsigned sample_count)
-{
- uint usage;
- if (_mesa_is_depth_or_stencil_format(internalFormat))
- usage = PIPE_BIND_DEPTH_STENCIL;
- else
- usage = PIPE_BIND_RENDER_TARGET;
- return st_choose_format(screen, internalFormat, GL_NONE, GL_NONE, PIPE_TEXTURE_2D,
- sample_count, usage);
-}
-
-
-gl_format
-st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat,
- GLenum format, GLenum type, GLboolean renderable)
-{
- struct pipe_screen *screen = st_context(ctx)->pipe->screen;
- enum pipe_format pFormat;
- uint bindings;
-
- (void) format;
- (void) type;
-
- /* GL textures may wind up being render targets, but we don't know
- * that in advance. Specify potential render target flags now.
- */
- bindings = PIPE_BIND_SAMPLER_VIEW;
- if (renderable) {
- if (_mesa_is_depth_or_stencil_format(internalFormat))
- bindings |= PIPE_BIND_DEPTH_STENCIL;
- else
- bindings |= PIPE_BIND_RENDER_TARGET;
- }
-
- pFormat = st_choose_format(screen, internalFormat, format, type,
- PIPE_TEXTURE_2D, 0, bindings);
-
- if (pFormat == PIPE_FORMAT_NONE) {
- /* try choosing format again, this time without render target bindings */
- pFormat = st_choose_format(screen, internalFormat, format, type,
- PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW);
- }
-
- if (pFormat == PIPE_FORMAT_NONE) {
- /* no luck at all */
- return MESA_FORMAT_NONE;
- }
-
- return st_pipe_format_to_mesa_format(pFormat);
-}
-
-
-/**
- * Called via ctx->Driver.ChooseTextureFormat().
- */
-gl_format
-st_ChooseTextureFormat(struct gl_context *ctx, GLint internalFormat,
- GLenum format, GLenum type)
-{
- boolean want_renderable =
- internalFormat == 3 || internalFormat == 4 ||
- internalFormat == GL_RGB || internalFormat == GL_RGBA ||
- internalFormat == GL_RGB8 || internalFormat == GL_RGBA8 ||
- internalFormat == GL_BGRA;
-
- return st_ChooseTextureFormat_renderable(ctx, internalFormat,
- format, type, want_renderable);
-}
-
-/**
- * Test if a gallium format is equivalent to a GL format/type.
- */
-GLboolean
-st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type)
-{
- switch (pFormat) {
- case PIPE_FORMAT_A8B8G8R8_UNORM:
- return format == GL_RGBA && type == GL_UNSIGNED_BYTE;
- case PIPE_FORMAT_A8R8G8B8_UNORM:
- return format == GL_BGRA && type == GL_UNSIGNED_BYTE;
- case PIPE_FORMAT_B5G6R5_UNORM:
- return format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5;
- /* XXX more combos... */
- default:
- return GL_FALSE;
- }
-}
-
-GLboolean
-st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2)
-{
- if (format1 == format2)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_B8G8R8A8_UNORM &&
- format2 == PIPE_FORMAT_B8G8R8X8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_B8G8R8X8_UNORM &&
- format2 == PIPE_FORMAT_B8G8R8A8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_A8B8G8R8_UNORM &&
- format2 == PIPE_FORMAT_X8B8G8R8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_X8B8G8R8_UNORM &&
- format2 == PIPE_FORMAT_A8B8G8R8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_A8R8G8B8_UNORM &&
- format2 == PIPE_FORMAT_X8R8G8B8_UNORM)
- return GL_TRUE;
-
- if (format1 == PIPE_FORMAT_X8R8G8B8_UNORM &&
- format2 == PIPE_FORMAT_A8R8G8B8_UNORM)
- return GL_TRUE;
-
- return GL_FALSE;
-}
-
-
-
-/**
- * This is used for translating texture border color and the clear
- * color. For example, the clear color is interpreted according to
- * the renderbuffer's base format. For example, if clearing a
- * GL_LUMINANCE buffer, ClearColor[0] = luminance and ClearColor[1] =
- * alpha. Similarly for texture border colors.
- */
-void
-st_translate_color(const GLfloat colorIn[4], GLenum baseFormat,
- GLfloat colorOut[4])
-{
- switch (baseFormat) {
- case GL_RED:
- colorOut[0] = colorIn[0];
- colorOut[1] = 0.0F;
- colorOut[2] = 0.0F;
- colorOut[3] = 1.0F;
- break;
- case GL_RG:
- colorOut[0] = colorIn[0];
- colorOut[1] = colorIn[1];
- colorOut[2] = 0.0F;
- colorOut[3] = 1.0F;
- break;
- case GL_RGB:
- colorOut[0] = colorIn[0];
- colorOut[1] = colorIn[1];
- colorOut[2] = colorIn[2];
- colorOut[3] = 1.0F;
- break;
- case GL_ALPHA:
- colorOut[0] = colorOut[1] = colorOut[2] = 0.0;
- colorOut[3] = colorIn[3];
- break;
- case GL_LUMINANCE:
- colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0];
- colorOut[3] = 1.0;
- break;
- case GL_LUMINANCE_ALPHA:
- colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0];
- colorOut[3] = colorIn[3];
- break;
- case GL_INTENSITY:
- colorOut[0] = colorOut[1] = colorOut[2] = colorOut[3] = colorIn[0];
- break;
- default:
- COPY_4V(colorOut, colorIn);
- }
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (c) 2008-2010 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. + * + **************************************************************************/ + + +/** + * Mesa / Gallium format conversion and format selection code. + * \author Brian Paul + */ + +#include "main/imports.h" +#include "main/context.h" +#include "main/texstore.h" +#include "main/image.h" +#include "main/macros.h" +#include "main/mfeatures.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_screen.h" +#include "util/u_format.h" +#include "st_context.h" +#include "st_format.h" + + +static GLuint +format_max_bits(enum pipe_format format) +{ + GLuint size = util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 0); + + size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 1)); + size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 2)); + size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_RGB, 3)); + size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 0)); + size = MAX2(size, util_format_get_component_bits(format, UTIL_FORMAT_COLORSPACE_ZS, 1)); + return size; +} + + +/** + * Return basic GL datatype for the given gallium format. + */ +GLenum +st_format_datatype(enum pipe_format format) +{ + const struct util_format_description *desc; + int i; + + desc = util_format_description(format); + assert(desc); + + /* Find the first non-VOID channel. */ + for (i = 0; i < 4; i++) { + if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) { + break; + } + } + + if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) { + if (format == PIPE_FORMAT_B5G5R5A1_UNORM || + format == PIPE_FORMAT_B5G6R5_UNORM) { + return GL_UNSIGNED_SHORT; + } + else if (format == PIPE_FORMAT_R11G11B10_FLOAT || + format == PIPE_FORMAT_R9G9B9E5_FLOAT) { + return GL_FLOAT; + } + else if (format == PIPE_FORMAT_Z24_UNORM_S8_USCALED || + format == PIPE_FORMAT_S8_USCALED_Z24_UNORM || + format == PIPE_FORMAT_Z24X8_UNORM || + format == PIPE_FORMAT_X8Z24_UNORM) { + return GL_UNSIGNED_INT_24_8; + } + else if (format == PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED) { + return GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + } + else { + const GLuint size = format_max_bits(format); + + assert(i < 4); + if (i == 4) + return GL_NONE; + + if (size == 8) { + if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) + return GL_UNSIGNED_BYTE; + else + return GL_BYTE; + } + else if (size == 16) { + if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT) + return GL_HALF_FLOAT; + if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) + return GL_UNSIGNED_SHORT; + else + return GL_SHORT; + } + else if (size <= 32) { + if (desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT) + return GL_FLOAT; + if (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED) + return GL_UNSIGNED_INT; + else + return GL_INT; + } + else { + assert(size == 64); + assert(desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT); + return GL_DOUBLE; + } + } + } + else if (format == PIPE_FORMAT_UYVY) { + return GL_UNSIGNED_SHORT; + } + else if (format == PIPE_FORMAT_YUYV) { + return GL_UNSIGNED_SHORT; + } + else { + /* probably a compressed format, unsupported anyway */ + return GL_NONE; + } +} + + +/** + * Translate Mesa format to Gallium format. + */ +enum pipe_format +st_mesa_format_to_pipe_format(gl_format mesaFormat) +{ + switch (mesaFormat) { + case MESA_FORMAT_RGBA8888: + return PIPE_FORMAT_A8B8G8R8_UNORM; + case MESA_FORMAT_RGBA8888_REV: + return PIPE_FORMAT_R8G8B8A8_UNORM; + case MESA_FORMAT_ARGB8888: + return PIPE_FORMAT_B8G8R8A8_UNORM; + case MESA_FORMAT_ARGB8888_REV: + return PIPE_FORMAT_A8R8G8B8_UNORM; + case MESA_FORMAT_XRGB8888: + return PIPE_FORMAT_B8G8R8X8_UNORM; + case MESA_FORMAT_XRGB8888_REV: + return PIPE_FORMAT_X8R8G8B8_UNORM; + case MESA_FORMAT_ARGB1555: + return PIPE_FORMAT_B5G5R5A1_UNORM; + case MESA_FORMAT_ARGB4444: + return PIPE_FORMAT_B4G4R4A4_UNORM; + case MESA_FORMAT_RGB565: + return PIPE_FORMAT_B5G6R5_UNORM; + case MESA_FORMAT_RGB332: + return PIPE_FORMAT_B2G3R3_UNORM; + case MESA_FORMAT_ARGB2101010: + return PIPE_FORMAT_B10G10R10A2_UNORM; + case MESA_FORMAT_AL44: + return PIPE_FORMAT_L4A4_UNORM; + case MESA_FORMAT_AL88: + return PIPE_FORMAT_L8A8_UNORM; + case MESA_FORMAT_AL1616: + return PIPE_FORMAT_L16A16_UNORM; + case MESA_FORMAT_A8: + return PIPE_FORMAT_A8_UNORM; + case MESA_FORMAT_A16: + return PIPE_FORMAT_A16_UNORM; + case MESA_FORMAT_L8: + return PIPE_FORMAT_L8_UNORM; + case MESA_FORMAT_L16: + return PIPE_FORMAT_L16_UNORM; + case MESA_FORMAT_I8: + return PIPE_FORMAT_I8_UNORM; + case MESA_FORMAT_I16: + return PIPE_FORMAT_I16_UNORM; + case MESA_FORMAT_Z16: + return PIPE_FORMAT_Z16_UNORM; + case MESA_FORMAT_Z32: + return PIPE_FORMAT_Z32_UNORM; + case MESA_FORMAT_Z24_S8: + return PIPE_FORMAT_S8_USCALED_Z24_UNORM; + case MESA_FORMAT_S8_Z24: + return PIPE_FORMAT_Z24_UNORM_S8_USCALED; + case MESA_FORMAT_Z24_X8: + return PIPE_FORMAT_X8Z24_UNORM; + case MESA_FORMAT_X8_Z24: + return PIPE_FORMAT_Z24X8_UNORM; + case MESA_FORMAT_S8: + return PIPE_FORMAT_S8_USCALED; + case MESA_FORMAT_Z32_FLOAT: + return PIPE_FORMAT_Z32_FLOAT; + case MESA_FORMAT_Z32_FLOAT_X24S8: + return PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED; + case MESA_FORMAT_YCBCR: + return PIPE_FORMAT_UYVY; +#if FEATURE_texture_s3tc + case MESA_FORMAT_RGB_DXT1: + return PIPE_FORMAT_DXT1_RGB; + case MESA_FORMAT_RGBA_DXT1: + return PIPE_FORMAT_DXT1_RGBA; + case MESA_FORMAT_RGBA_DXT3: + return PIPE_FORMAT_DXT3_RGBA; + case MESA_FORMAT_RGBA_DXT5: + return PIPE_FORMAT_DXT5_RGBA; +#if FEATURE_EXT_texture_sRGB + case MESA_FORMAT_SRGB_DXT1: + return PIPE_FORMAT_DXT1_SRGB; + case MESA_FORMAT_SRGBA_DXT1: + return PIPE_FORMAT_DXT1_SRGBA; + case MESA_FORMAT_SRGBA_DXT3: + return PIPE_FORMAT_DXT3_SRGBA; + case MESA_FORMAT_SRGBA_DXT5: + return PIPE_FORMAT_DXT5_SRGBA; +#endif +#endif +#if FEATURE_EXT_texture_sRGB + case MESA_FORMAT_SLA8: + return PIPE_FORMAT_L8A8_SRGB; + case MESA_FORMAT_SL8: + return PIPE_FORMAT_L8_SRGB; + case MESA_FORMAT_SRGB8: + return PIPE_FORMAT_R8G8B8_SRGB; + case MESA_FORMAT_SRGBA8: + return PIPE_FORMAT_A8B8G8R8_SRGB; + case MESA_FORMAT_SARGB8: + return PIPE_FORMAT_B8G8R8A8_SRGB; +#endif + case MESA_FORMAT_RGBA_FLOAT32: + return PIPE_FORMAT_R32G32B32A32_FLOAT; + case MESA_FORMAT_RGBA_FLOAT16: + return PIPE_FORMAT_R16G16B16A16_FLOAT; + case MESA_FORMAT_RGB_FLOAT32: + return PIPE_FORMAT_R32G32B32_FLOAT; + case MESA_FORMAT_RGB_FLOAT16: + return PIPE_FORMAT_R16G16B16_FLOAT; + case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32: + return PIPE_FORMAT_L32A32_FLOAT; + case MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16: + return PIPE_FORMAT_L16A16_FLOAT; + case MESA_FORMAT_LUMINANCE_FLOAT32: + return PIPE_FORMAT_L32_FLOAT; + case MESA_FORMAT_LUMINANCE_FLOAT16: + return PIPE_FORMAT_L16_FLOAT; + case MESA_FORMAT_ALPHA_FLOAT32: + return PIPE_FORMAT_A32_FLOAT; + case MESA_FORMAT_ALPHA_FLOAT16: + return PIPE_FORMAT_A16_FLOAT; + case MESA_FORMAT_INTENSITY_FLOAT32: + return PIPE_FORMAT_I32_FLOAT; + case MESA_FORMAT_INTENSITY_FLOAT16: + return PIPE_FORMAT_I16_FLOAT; + case MESA_FORMAT_R_FLOAT32: + return PIPE_FORMAT_R32_FLOAT; + case MESA_FORMAT_R_FLOAT16: + return PIPE_FORMAT_R16_FLOAT; + case MESA_FORMAT_RG_FLOAT32: + return PIPE_FORMAT_R32G32_FLOAT; + case MESA_FORMAT_RG_FLOAT16: + return PIPE_FORMAT_R16G16_FLOAT; + + case MESA_FORMAT_R8: + return PIPE_FORMAT_R8_UNORM; + case MESA_FORMAT_R16: + return PIPE_FORMAT_R16_UNORM; + case MESA_FORMAT_RG88: + return PIPE_FORMAT_R8G8_UNORM; + case MESA_FORMAT_RG1616: + return PIPE_FORMAT_R16G16_UNORM; + case MESA_FORMAT_RGBA_16: + return PIPE_FORMAT_R16G16B16A16_UNORM; + + /* signed int formats */ + case MESA_FORMAT_RGBA_INT8: + return PIPE_FORMAT_R8G8B8A8_SSCALED; + case MESA_FORMAT_RGBA_INT16: + return PIPE_FORMAT_R16G16B16A16_SSCALED; + case MESA_FORMAT_RGBA_INT32: + return PIPE_FORMAT_R32G32B32A32_SSCALED; + + /* unsigned int formats */ + case MESA_FORMAT_RGBA_UINT8: + return PIPE_FORMAT_R8G8B8A8_USCALED; + case MESA_FORMAT_RGBA_UINT16: + return PIPE_FORMAT_R16G16B16A16_USCALED; + case MESA_FORMAT_RGBA_UINT32: + return PIPE_FORMAT_R32G32B32A32_USCALED; + + case MESA_FORMAT_RED_RGTC1: + return PIPE_FORMAT_RGTC1_UNORM; + case MESA_FORMAT_SIGNED_RED_RGTC1: + return PIPE_FORMAT_RGTC1_SNORM; + case MESA_FORMAT_RG_RGTC2: + return PIPE_FORMAT_RGTC2_UNORM; + case MESA_FORMAT_SIGNED_RG_RGTC2: + return PIPE_FORMAT_RGTC2_SNORM; + + case MESA_FORMAT_L_LATC1: + return PIPE_FORMAT_LATC1_UNORM; + case MESA_FORMAT_SIGNED_L_LATC1: + return PIPE_FORMAT_LATC1_SNORM; + case MESA_FORMAT_LA_LATC2: + return PIPE_FORMAT_LATC2_UNORM; + case MESA_FORMAT_SIGNED_LA_LATC2: + return PIPE_FORMAT_LATC2_SNORM; + + /* signed normalized formats */ + case MESA_FORMAT_SIGNED_R8: + return PIPE_FORMAT_R8_SNORM; + case MESA_FORMAT_SIGNED_RG88_REV: + return PIPE_FORMAT_R8G8_SNORM; + case MESA_FORMAT_SIGNED_RGBA8888_REV: + return PIPE_FORMAT_R8G8B8A8_SNORM; + + case MESA_FORMAT_SIGNED_A8: + return PIPE_FORMAT_A8_SNORM; + case MESA_FORMAT_SIGNED_L8: + return PIPE_FORMAT_L8_SNORM; + case MESA_FORMAT_SIGNED_AL88: + return PIPE_FORMAT_L8A8_SNORM; + case MESA_FORMAT_SIGNED_I8: + return PIPE_FORMAT_I8_SNORM; + + case MESA_FORMAT_SIGNED_R16: + return PIPE_FORMAT_R16_SNORM; + case MESA_FORMAT_SIGNED_GR1616: + return PIPE_FORMAT_R16G16_SNORM; + case MESA_FORMAT_SIGNED_RGBA_16: + return PIPE_FORMAT_R16G16B16A16_SNORM; + + case MESA_FORMAT_SIGNED_A16: + return PIPE_FORMAT_A16_SNORM; + case MESA_FORMAT_SIGNED_L16: + return PIPE_FORMAT_L16_SNORM; + case MESA_FORMAT_SIGNED_AL1616: + return PIPE_FORMAT_L16A16_SNORM; + case MESA_FORMAT_SIGNED_I16: + return PIPE_FORMAT_I16_SNORM; + + case MESA_FORMAT_RGB9_E5_FLOAT: + return PIPE_FORMAT_R9G9B9E5_FLOAT; + case MESA_FORMAT_R11_G11_B10_FLOAT: + return PIPE_FORMAT_R11G11B10_FLOAT; + + default: + assert(0); + return PIPE_FORMAT_NONE; + } +} + + +/** + * Translate Gallium format to Mesa format. + */ +gl_format +st_pipe_format_to_mesa_format(enum pipe_format format) +{ + switch (format) { + case PIPE_FORMAT_A8B8G8R8_UNORM: + return MESA_FORMAT_RGBA8888; + case PIPE_FORMAT_R8G8B8A8_UNORM: + return MESA_FORMAT_RGBA8888_REV; + case PIPE_FORMAT_B8G8R8A8_UNORM: + return MESA_FORMAT_ARGB8888; + case PIPE_FORMAT_A8R8G8B8_UNORM: + return MESA_FORMAT_ARGB8888_REV; + case PIPE_FORMAT_B8G8R8X8_UNORM: + return MESA_FORMAT_XRGB8888; + case PIPE_FORMAT_X8R8G8B8_UNORM: + return MESA_FORMAT_XRGB8888_REV; + case PIPE_FORMAT_B5G5R5A1_UNORM: + return MESA_FORMAT_ARGB1555; + case PIPE_FORMAT_B4G4R4A4_UNORM: + return MESA_FORMAT_ARGB4444; + case PIPE_FORMAT_B5G6R5_UNORM: + return MESA_FORMAT_RGB565; + case PIPE_FORMAT_B2G3R3_UNORM: + return MESA_FORMAT_RGB332; + case PIPE_FORMAT_B10G10R10A2_UNORM: + return MESA_FORMAT_ARGB2101010; + case PIPE_FORMAT_L4A4_UNORM: + return MESA_FORMAT_AL44; + case PIPE_FORMAT_L8A8_UNORM: + return MESA_FORMAT_AL88; + case PIPE_FORMAT_L16A16_UNORM: + return MESA_FORMAT_AL1616; + case PIPE_FORMAT_A8_UNORM: + return MESA_FORMAT_A8; + case PIPE_FORMAT_A16_UNORM: + return MESA_FORMAT_A16; + case PIPE_FORMAT_L8_UNORM: + return MESA_FORMAT_L8; + case PIPE_FORMAT_L16_UNORM: + return MESA_FORMAT_L16; + case PIPE_FORMAT_I8_UNORM: + return MESA_FORMAT_I8; + case PIPE_FORMAT_I16_UNORM: + return MESA_FORMAT_I16; + case PIPE_FORMAT_S8_USCALED: + return MESA_FORMAT_S8; + + case PIPE_FORMAT_R16G16B16A16_UNORM: + return MESA_FORMAT_RGBA_16; + + case PIPE_FORMAT_Z16_UNORM: + return MESA_FORMAT_Z16; + case PIPE_FORMAT_Z32_UNORM: + return MESA_FORMAT_Z32; + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: + return MESA_FORMAT_Z24_S8; + case PIPE_FORMAT_X8Z24_UNORM: + return MESA_FORMAT_Z24_X8; + case PIPE_FORMAT_Z24X8_UNORM: + return MESA_FORMAT_X8_Z24; + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: + return MESA_FORMAT_S8_Z24; + case PIPE_FORMAT_Z32_FLOAT: + return MESA_FORMAT_Z32_FLOAT; + case PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED: + return MESA_FORMAT_Z32_FLOAT_X24S8; + + case PIPE_FORMAT_UYVY: + return MESA_FORMAT_YCBCR; + case PIPE_FORMAT_YUYV: + return MESA_FORMAT_YCBCR_REV; + +#if FEATURE_texture_s3tc + case PIPE_FORMAT_DXT1_RGB: + return MESA_FORMAT_RGB_DXT1; + case PIPE_FORMAT_DXT1_RGBA: + return MESA_FORMAT_RGBA_DXT1; + case PIPE_FORMAT_DXT3_RGBA: + return MESA_FORMAT_RGBA_DXT3; + case PIPE_FORMAT_DXT5_RGBA: + return MESA_FORMAT_RGBA_DXT5; +#if FEATURE_EXT_texture_sRGB + case PIPE_FORMAT_DXT1_SRGB: + return MESA_FORMAT_SRGB_DXT1; + case PIPE_FORMAT_DXT1_SRGBA: + return MESA_FORMAT_SRGBA_DXT1; + case PIPE_FORMAT_DXT3_SRGBA: + return MESA_FORMAT_SRGBA_DXT3; + case PIPE_FORMAT_DXT5_SRGBA: + return MESA_FORMAT_SRGBA_DXT5; +#endif +#endif + +#if FEATURE_EXT_texture_sRGB + case PIPE_FORMAT_L8A8_SRGB: + return MESA_FORMAT_SLA8; + case PIPE_FORMAT_L8_SRGB: + return MESA_FORMAT_SL8; + case PIPE_FORMAT_R8G8B8_SRGB: + return MESA_FORMAT_SRGB8; + case PIPE_FORMAT_A8B8G8R8_SRGB: + return MESA_FORMAT_SRGBA8; + case PIPE_FORMAT_B8G8R8A8_SRGB: + return MESA_FORMAT_SARGB8; +#endif + case PIPE_FORMAT_R32G32B32A32_FLOAT: + return MESA_FORMAT_RGBA_FLOAT32; + case PIPE_FORMAT_R16G16B16A16_FLOAT: + return MESA_FORMAT_RGBA_FLOAT16; + case PIPE_FORMAT_R32G32B32_FLOAT: + return MESA_FORMAT_RGB_FLOAT32; + case PIPE_FORMAT_R16G16B16_FLOAT: + return MESA_FORMAT_RGB_FLOAT16; + case PIPE_FORMAT_L32A32_FLOAT: + return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32; + case PIPE_FORMAT_L16A16_FLOAT: + return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16; + case PIPE_FORMAT_L32_FLOAT: + return MESA_FORMAT_LUMINANCE_FLOAT32; + case PIPE_FORMAT_L16_FLOAT: + return MESA_FORMAT_LUMINANCE_FLOAT16; + case PIPE_FORMAT_A32_FLOAT: + return MESA_FORMAT_ALPHA_FLOAT32; + case PIPE_FORMAT_A16_FLOAT: + return MESA_FORMAT_ALPHA_FLOAT16; + case PIPE_FORMAT_I32_FLOAT: + return MESA_FORMAT_INTENSITY_FLOAT32; + case PIPE_FORMAT_I16_FLOAT: + return MESA_FORMAT_INTENSITY_FLOAT16; + case PIPE_FORMAT_R32_FLOAT: + return MESA_FORMAT_R_FLOAT32; + case PIPE_FORMAT_R16_FLOAT: + return MESA_FORMAT_R_FLOAT16; + case PIPE_FORMAT_R32G32_FLOAT: + return MESA_FORMAT_RG_FLOAT32; + case PIPE_FORMAT_R16G16_FLOAT: + return MESA_FORMAT_RG_FLOAT16; + + case PIPE_FORMAT_R8_UNORM: + return MESA_FORMAT_R8; + case PIPE_FORMAT_R16_UNORM: + return MESA_FORMAT_R16; + case PIPE_FORMAT_R8G8_UNORM: + return MESA_FORMAT_RG88; + case PIPE_FORMAT_R16G16_UNORM: + return MESA_FORMAT_RG1616; + + /* signed int formats */ + case PIPE_FORMAT_R8G8B8A8_SSCALED: + return MESA_FORMAT_RGBA_INT8; + case PIPE_FORMAT_R16G16B16A16_SSCALED: + return MESA_FORMAT_RGBA_INT16; + case PIPE_FORMAT_R32G32B32A32_SSCALED: + return MESA_FORMAT_RGBA_INT32; + + /* unsigned int formats */ + case PIPE_FORMAT_R8G8B8A8_USCALED: + return MESA_FORMAT_RGBA_UINT8; + case PIPE_FORMAT_R16G16B16A16_USCALED: + return MESA_FORMAT_RGBA_UINT16; + case PIPE_FORMAT_R32G32B32A32_USCALED: + return MESA_FORMAT_RGBA_UINT32; + + case PIPE_FORMAT_RGTC1_UNORM: + return MESA_FORMAT_RED_RGTC1; + case PIPE_FORMAT_RGTC1_SNORM: + return MESA_FORMAT_SIGNED_RED_RGTC1; + case PIPE_FORMAT_RGTC2_UNORM: + return MESA_FORMAT_RG_RGTC2; + case PIPE_FORMAT_RGTC2_SNORM: + return MESA_FORMAT_SIGNED_RG_RGTC2; + + case PIPE_FORMAT_LATC1_UNORM: + return MESA_FORMAT_L_LATC1; + case PIPE_FORMAT_LATC1_SNORM: + return MESA_FORMAT_SIGNED_L_LATC1; + case PIPE_FORMAT_LATC2_UNORM: + return MESA_FORMAT_LA_LATC2; + case PIPE_FORMAT_LATC2_SNORM: + return MESA_FORMAT_SIGNED_LA_LATC2; + + /* signed normalized formats */ + case PIPE_FORMAT_R8_SNORM: + return MESA_FORMAT_SIGNED_R8; + case PIPE_FORMAT_R8G8_SNORM: + return MESA_FORMAT_SIGNED_RG88_REV; + case PIPE_FORMAT_R8G8B8A8_SNORM: + return MESA_FORMAT_SIGNED_RGBA8888_REV; + + case PIPE_FORMAT_A8_SNORM: + return MESA_FORMAT_SIGNED_A8; + case PIPE_FORMAT_L8_SNORM: + return MESA_FORMAT_SIGNED_L8; + case PIPE_FORMAT_L8A8_SNORM: + return MESA_FORMAT_SIGNED_AL88; + case PIPE_FORMAT_I8_SNORM: + return MESA_FORMAT_SIGNED_I8; + + case PIPE_FORMAT_R16_SNORM: + return MESA_FORMAT_SIGNED_R16; + case PIPE_FORMAT_R16G16_SNORM: + return MESA_FORMAT_SIGNED_GR1616; + case PIPE_FORMAT_R16G16B16A16_SNORM: + return MESA_FORMAT_SIGNED_RGBA_16; + + case PIPE_FORMAT_A16_SNORM: + return MESA_FORMAT_SIGNED_A16; + case PIPE_FORMAT_L16_SNORM: + return MESA_FORMAT_SIGNED_L16; + case PIPE_FORMAT_L16A16_SNORM: + return MESA_FORMAT_SIGNED_AL1616; + case PIPE_FORMAT_I16_SNORM: + return MESA_FORMAT_SIGNED_I16; + + case PIPE_FORMAT_R9G9B9E5_FLOAT: + return MESA_FORMAT_RGB9_E5_FLOAT; + case PIPE_FORMAT_R11G11B10_FLOAT: + return MESA_FORMAT_R11_G11_B10_FLOAT; + + default: + assert(0); + return MESA_FORMAT_NONE; + } +} + + +/** + * Map GL texture formats to Gallium pipe formats. + */ +struct format_mapping +{ + GLenum glFormats[18]; /**< list of GLenum formats, 0-terminated */ + enum pipe_format pipeFormats[10]; /**< list of pipe formats, 0-terminated */ +}; + + +#define DEFAULT_RGBA_FORMATS \ + PIPE_FORMAT_B8G8R8A8_UNORM, \ + PIPE_FORMAT_A8R8G8B8_UNORM, \ + PIPE_FORMAT_A8B8G8R8_UNORM, \ + PIPE_FORMAT_B5G6R5_UNORM, \ + 0 + +#define DEFAULT_RGB_FORMATS \ + PIPE_FORMAT_B8G8R8X8_UNORM, \ + PIPE_FORMAT_X8R8G8B8_UNORM, \ + PIPE_FORMAT_X8B8G8R8_UNORM, \ + PIPE_FORMAT_B8G8R8A8_UNORM, \ + PIPE_FORMAT_A8R8G8B8_UNORM, \ + PIPE_FORMAT_A8B8G8R8_UNORM, \ + PIPE_FORMAT_B5G6R5_UNORM, \ + 0 + +#define DEFAULT_SRGBA_FORMATS \ + PIPE_FORMAT_B8G8R8A8_SRGB, \ + PIPE_FORMAT_A8R8G8B8_SRGB, \ + PIPE_FORMAT_A8B8G8R8_SRGB, \ + 0 + +#define DEFAULT_DEPTH_FORMATS \ + PIPE_FORMAT_Z24X8_UNORM, \ + PIPE_FORMAT_X8Z24_UNORM, \ + PIPE_FORMAT_Z16_UNORM, \ + PIPE_FORMAT_Z24_UNORM_S8_USCALED, \ + PIPE_FORMAT_S8_USCALED_Z24_UNORM, \ + 0 + +/** + * This table maps OpenGL texture format enums to Gallium pipe_format enums. + * Multiple GL enums might map to multiple pipe_formats. + * The first pipe format in the list that's supported is the one that's chosen. + */ +static const struct format_mapping format_map[] = { + /* Basic RGB, RGBA formats */ + { + { GL_RGB10, GL_RGB10_A2, 0 }, + { PIPE_FORMAT_B10G10R10A2_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { 4, GL_RGBA, GL_RGBA8, 0 }, + { PIPE_FORMAT_R8G8B8A8_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { GL_BGRA, 0 }, + { PIPE_FORMAT_B8G8R8A8_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { 3, GL_RGB, GL_RGB8, 0 }, + { DEFAULT_RGB_FORMATS } + }, + { + { GL_RGB12, GL_RGB16, GL_RGBA12, GL_RGBA16, 0 }, + { PIPE_FORMAT_R16G16B16A16_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { GL_RGBA4, GL_RGBA2, 0 }, + { PIPE_FORMAT_B4G4R4A4_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { GL_RGB5_A1, 0 }, + { PIPE_FORMAT_B5G5R5A1_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { GL_R3_G3_B2, 0 }, + { PIPE_FORMAT_B2G3R3_UNORM, PIPE_FORMAT_B5G6R5_UNORM, + PIPE_FORMAT_B5G5R5A1_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { GL_RGB5, GL_RGB4 }, + { PIPE_FORMAT_B5G6R5_UNORM, PIPE_FORMAT_B5G5R5A1_UNORM, + DEFAULT_RGBA_FORMATS } + }, + + /* basic Alpha formats */ + { + { GL_ALPHA12, GL_ALPHA16, 0 }, + { PIPE_FORMAT_A16_UNORM, PIPE_FORMAT_A8_UNORM, + DEFAULT_RGBA_FORMATS } + }, + { + { GL_ALPHA, GL_ALPHA4, GL_ALPHA8, GL_COMPRESSED_ALPHA, 0 }, + { PIPE_FORMAT_A8_UNORM, DEFAULT_RGBA_FORMATS } + }, + + /* basic Luminance formats */ + { + { GL_LUMINANCE12, GL_LUMINANCE16, 0 }, + { PIPE_FORMAT_L16_UNORM, PIPE_FORMAT_L8_UNORM, DEFAULT_RGB_FORMATS } + }, + { + { 1, GL_LUMINANCE, GL_LUMINANCE4, GL_LUMINANCE8, 0 }, + { PIPE_FORMAT_L8_UNORM, DEFAULT_RGB_FORMATS } + }, + + /* basic Luminance/Alpha formats */ + { + { GL_LUMINANCE12_ALPHA4, GL_LUMINANCE12_ALPHA12, + GL_LUMINANCE16_ALPHA16, 0}, + { PIPE_FORMAT_L16A16_UNORM, PIPE_FORMAT_L8A8_UNORM, + DEFAULT_RGBA_FORMATS } + }, + { + { 2, GL_LUMINANCE_ALPHA, GL_LUMINANCE6_ALPHA2, GL_LUMINANCE8_ALPHA8, 0 }, + { PIPE_FORMAT_L8A8_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { GL_LUMINANCE4_ALPHA4, 0 }, + { PIPE_FORMAT_L4A4_UNORM, PIPE_FORMAT_L8A8_UNORM, + DEFAULT_RGBA_FORMATS } + }, + + /* basic Intensity formats */ + { + { GL_INTENSITY12, GL_INTENSITY16, 0 }, + { PIPE_FORMAT_I16_UNORM, PIPE_FORMAT_I8_UNORM, DEFAULT_RGBA_FORMATS } + }, + { + { GL_INTENSITY, GL_INTENSITY4, GL_INTENSITY8, + GL_COMPRESSED_INTENSITY, 0 }, + { PIPE_FORMAT_I8_UNORM, DEFAULT_RGBA_FORMATS } + }, + + /* YCbCr */ + { + { GL_YCBCR_MESA, 0 }, + { PIPE_FORMAT_UYVY, PIPE_FORMAT_YUYV, 0 } + }, + + /* compressed formats */ /* XXX PIPE_BIND_SAMPLER_VIEW only */ + { + { GL_COMPRESSED_RGB, 0 }, + { PIPE_FORMAT_DXT1_RGB, DEFAULT_RGB_FORMATS } + }, + { + { GL_COMPRESSED_RGBA, 0 }, + { PIPE_FORMAT_DXT5_RGBA, DEFAULT_RGBA_FORMATS } + }, + { + { GL_RGB_S3TC, GL_RGB4_S3TC, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0 }, + { PIPE_FORMAT_DXT1_RGB, 0 } + }, + { + { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0 }, + { PIPE_FORMAT_DXT1_RGBA, 0 } + }, + { + { GL_RGBA_S3TC, GL_RGBA4_S3TC, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0 }, + { PIPE_FORMAT_DXT3_RGBA, 0 } + }, + { + { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 0 }, + { PIPE_FORMAT_DXT5_RGBA, 0 } + }, + +#if 0 + { + { GL_COMPRESSED_RGB_FXT1_3DFX, 0 }, + { PIPE_FORMAT_RGB_FXT1, 0 } + }, + { + { GL_COMPRESSED_RGBA_FXT1_3DFX, 0 }, + { PIPE_FORMAT_RGBA_FXT1, 0 } + }, +#endif + + /* Depth formats */ + { + { GL_DEPTH_COMPONENT16, 0 }, + { PIPE_FORMAT_Z16_UNORM, DEFAULT_DEPTH_FORMATS } + }, + { + { GL_DEPTH_COMPONENT24, 0 }, + { PIPE_FORMAT_Z24X8_UNORM, PIPE_FORMAT_X8Z24_UNORM, + DEFAULT_DEPTH_FORMATS } + }, + { + { GL_DEPTH_COMPONENT32, 0 }, + { PIPE_FORMAT_Z32_UNORM, DEFAULT_DEPTH_FORMATS } + }, + { + { GL_DEPTH_COMPONENT, 0 }, + { DEFAULT_DEPTH_FORMATS } + }, + { + { GL_DEPTH_COMPONENT32F, 0 }, + { PIPE_FORMAT_Z32_FLOAT, 0 } + }, + + /* stencil formats */ + { + { GL_STENCIL_INDEX, GL_STENCIL_INDEX1_EXT, GL_STENCIL_INDEX4_EXT, + GL_STENCIL_INDEX8_EXT, GL_STENCIL_INDEX16_EXT, 0 }, + { + PIPE_FORMAT_S8_USCALED, PIPE_FORMAT_Z24_UNORM_S8_USCALED, + PIPE_FORMAT_S8_USCALED_Z24_UNORM, 0 + } + }, + + /* Depth / Stencil formats */ + { + { GL_DEPTH_STENCIL_EXT, GL_DEPTH24_STENCIL8_EXT, 0 }, + { PIPE_FORMAT_Z24_UNORM_S8_USCALED, PIPE_FORMAT_S8_USCALED_Z24_UNORM, 0 } + }, + { + { GL_DEPTH32F_STENCIL8, 0 }, + { PIPE_FORMAT_Z32_FLOAT_S8X24_USCALED, 0 } + }, + + /* sRGB formats */ + { + { GL_SRGB_EXT, GL_SRGB8_EXT, GL_SRGB_ALPHA_EXT, GL_SRGB8_ALPHA8_EXT, 0 }, + { DEFAULT_SRGBA_FORMATS } + }, + { + { GL_COMPRESSED_SRGB_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, 0 }, + { PIPE_FORMAT_DXT1_SRGB, DEFAULT_SRGBA_FORMATS } + }, + { + { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, 0 }, + { PIPE_FORMAT_DXT1_SRGBA, 0 } + }, + { + { GL_COMPRESSED_SRGB_ALPHA_EXT, + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 0 }, + { PIPE_FORMAT_DXT3_SRGBA, DEFAULT_SRGBA_FORMATS } + }, + { + { GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 0 }, + { PIPE_FORMAT_DXT5_SRGBA, 0 } + }, + { + { GL_SLUMINANCE_ALPHA_EXT, GL_SLUMINANCE8_ALPHA8_EXT, + GL_COMPRESSED_SLUMINANCE_EXT, GL_COMPRESSED_SLUMINANCE_ALPHA_EXT, 0 }, + { PIPE_FORMAT_L8A8_SRGB, DEFAULT_SRGBA_FORMATS } + }, + { + { GL_SLUMINANCE_EXT, GL_SLUMINANCE8_EXT, 0 }, + { PIPE_FORMAT_L8_SRGB, DEFAULT_SRGBA_FORMATS } + }, + + /* 16-bit float formats */ + { + { GL_RGBA16F_ARB, 0 }, + { PIPE_FORMAT_R16G16B16A16_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + { + { GL_RGB16F_ARB, 0 }, + { PIPE_FORMAT_R16G16B16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_FORMAT_R32G32B32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + { + { GL_LUMINANCE_ALPHA16F_ARB, 0 }, + { PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + { + { GL_ALPHA16F_ARB, 0 }, + { PIPE_FORMAT_A16_FLOAT, PIPE_FORMAT_L16A16_FLOAT, + PIPE_FORMAT_A32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + { + { GL_INTENSITY16F_ARB, 0 }, + { PIPE_FORMAT_I16_FLOAT, PIPE_FORMAT_L16A16_FLOAT, + PIPE_FORMAT_I32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + { + { GL_LUMINANCE16F_ARB, 0 }, + { PIPE_FORMAT_L16_FLOAT, PIPE_FORMAT_L16A16_FLOAT, + PIPE_FORMAT_L32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + { + { GL_R16F, 0 }, + { PIPE_FORMAT_R16_FLOAT, PIPE_FORMAT_R16G16_FLOAT, + PIPE_FORMAT_R32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + { + { GL_RG16F, 0 }, + { PIPE_FORMAT_R16G16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, + PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, 0 } + }, + + /* 32-bit float formats */ + { + { GL_RGBA32F_ARB, 0 }, + { PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + { + { GL_RGB32F_ARB, 0 }, + { PIPE_FORMAT_R32G32B32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + { + { GL_LUMINANCE_ALPHA32F_ARB, 0 }, + { PIPE_FORMAT_L32A32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + { + { GL_ALPHA32F_ARB, 0 }, + { PIPE_FORMAT_A32_FLOAT, PIPE_FORMAT_L32A32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_A16_FLOAT, + PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + { + { GL_INTENSITY32F_ARB, 0 }, + { PIPE_FORMAT_I32_FLOAT, PIPE_FORMAT_L32A32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_I16_FLOAT, + PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + { + { GL_LUMINANCE32F_ARB, 0 }, + { PIPE_FORMAT_L32_FLOAT, PIPE_FORMAT_L32A32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_L16_FLOAT, + PIPE_FORMAT_L16A16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + { + { GL_R32F, 0 }, + { PIPE_FORMAT_R32_FLOAT, PIPE_FORMAT_R32G32_FLOAT, + PIPE_FORMAT_R32G32B32A32_FLOAT, PIPE_FORMAT_R16_FLOAT, + PIPE_FORMAT_R16G16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + { + { GL_RG32F, 0 }, + { PIPE_FORMAT_R32G32_FLOAT, PIPE_FORMAT_R32G32B32A32_FLOAT, + PIPE_FORMAT_R16G16_FLOAT, PIPE_FORMAT_R16G16B16A16_FLOAT, 0 } + }, + + /* R, RG formats */ + { + { GL_RED, GL_R8, 0 }, + { PIPE_FORMAT_R8_UNORM, 0 } + }, + { + { GL_RG, GL_RG8, 0 }, + { PIPE_FORMAT_R8G8_UNORM, 0 } + }, + { + { GL_R16, 0 }, + { PIPE_FORMAT_R16_UNORM, 0 } + }, + { + { GL_RG16, 0 }, + { PIPE_FORMAT_R16G16_UNORM, 0 } + }, + + /* compressed R, RG formats */ + { + { GL_COMPRESSED_RED, GL_COMPRESSED_RED_RGTC1, 0 }, + { PIPE_FORMAT_RGTC1_UNORM, PIPE_FORMAT_R8_UNORM, 0 } + }, + { + { GL_COMPRESSED_SIGNED_RED_RGTC1, 0 }, + { PIPE_FORMAT_RGTC1_SNORM, 0 } + }, + { + { GL_COMPRESSED_RG, GL_COMPRESSED_RG_RGTC2, 0 }, + { PIPE_FORMAT_RGTC2_UNORM, PIPE_FORMAT_R8G8_UNORM, 0 } + }, + { + { GL_COMPRESSED_SIGNED_RG_RGTC2, 0 }, + { PIPE_FORMAT_RGTC2_SNORM, 0 } + }, + { + { GL_COMPRESSED_LUMINANCE, GL_COMPRESSED_LUMINANCE_LATC1_EXT, 0 }, + { PIPE_FORMAT_LATC1_UNORM, PIPE_FORMAT_L8_UNORM, 0 } + }, + { + { GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT, 0 }, + { PIPE_FORMAT_LATC1_SNORM, 0 } + }, + { + { GL_COMPRESSED_LUMINANCE_ALPHA, GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, + GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI, 0 }, + { PIPE_FORMAT_LATC2_UNORM, PIPE_FORMAT_L8A8_UNORM, 0 } + }, + { + { GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT, 0 }, + { PIPE_FORMAT_LATC2_SNORM, 0 } + }, + + /* signed/unsigned integer formats. + * XXX Mesa only has formats for RGBA signed/unsigned integer formats. + * If/when new formats are added this code should be updated. + */ + { + { GL_RED_INTEGER_EXT, + GL_GREEN_INTEGER_EXT, + GL_BLUE_INTEGER_EXT, + GL_ALPHA_INTEGER_EXT, + GL_RGB_INTEGER_EXT, + GL_RGBA_INTEGER_EXT, + GL_BGR_INTEGER_EXT, + GL_BGRA_INTEGER_EXT, + GL_LUMINANCE_INTEGER_EXT, + GL_LUMINANCE_ALPHA_INTEGER_EXT, + GL_RGBA8I_EXT, + GL_RGB8I_EXT, + GL_ALPHA8I_EXT, + GL_INTENSITY8I_EXT, + GL_LUMINANCE8I_EXT, + GL_LUMINANCE_ALPHA8I_EXT, 0 }, + { PIPE_FORMAT_R8G8B8A8_SSCALED, 0 } + }, + { + { + GL_RGBA16I_EXT, + GL_RGB16I_EXT, + GL_ALPHA16I_EXT, + GL_INTENSITY16I_EXT, + GL_LUMINANCE16I_EXT, + GL_LUMINANCE_ALPHA16I_EXT, 0 }, + { PIPE_FORMAT_R16G16B16A16_SSCALED, 0 }, + }, + { + { + GL_RGBA32I_EXT, + GL_RGB32I_EXT, + GL_ALPHA32I_EXT, + GL_INTENSITY32I_EXT, + GL_LUMINANCE32I_EXT, + GL_LUMINANCE_ALPHA32I_EXT, 0 }, + { PIPE_FORMAT_R32G32B32A32_SSCALED, 0 } + }, + { + { + GL_RGBA8UI_EXT, + GL_RGB8UI_EXT, + GL_ALPHA8UI_EXT, + GL_INTENSITY8UI_EXT, + GL_LUMINANCE8UI_EXT, + GL_LUMINANCE_ALPHA8UI_EXT, 0 }, + { PIPE_FORMAT_R8G8B8A8_USCALED, 0 } + }, + { + { + GL_RGBA16UI_EXT, + GL_RGB16UI_EXT, + GL_ALPHA16UI_EXT, + GL_INTENSITY16UI_EXT, + GL_LUMINANCE16UI_EXT, + GL_LUMINANCE_ALPHA16UI_EXT, 0 }, + { PIPE_FORMAT_R16G16B16A16_USCALED, 0 } + }, + { + { + GL_RGBA32UI_EXT, + GL_RGB32UI_EXT, + GL_ALPHA32UI_EXT, + GL_INTENSITY32UI_EXT, + GL_LUMINANCE32UI_EXT, + GL_LUMINANCE_ALPHA32UI_EXT, 0 }, + { PIPE_FORMAT_R32G32B32A32_USCALED, 0 } + }, + + /* signed normalized formats */ + { + { GL_RED_SNORM, GL_R8_SNORM, 0 }, + { PIPE_FORMAT_R8_SNORM, PIPE_FORMAT_R8G8_SNORM, + PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_R16_SNORM, 0 }, + { PIPE_FORMAT_R16_SNORM, + PIPE_FORMAT_R16G16_SNORM, + PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_FORMAT_R8_SNORM, + PIPE_FORMAT_R8G8_SNORM, + PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_RG_SNORM, GL_RG8_SNORM, 0 }, + { PIPE_FORMAT_R8G8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_RG16_SNORM, 0 }, + { PIPE_FORMAT_R16G16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_FORMAT_R8G8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_RGB_SNORM, GL_RGB8_SNORM, GL_RGBA_SNORM, GL_RGBA8_SNORM, 0 }, + { PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_RGB16_SNORM, GL_RGBA16_SNORM, 0 }, + { PIPE_FORMAT_R16G16B16A16_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_ALPHA_SNORM, GL_ALPHA8_SNORM, 0 }, + { PIPE_FORMAT_A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_ALPHA16_SNORM, 0 }, + { PIPE_FORMAT_A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_FORMAT_A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_LUMINANCE_SNORM, GL_LUMINANCE8_SNORM, 0 }, + { PIPE_FORMAT_L8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_LUMINANCE16_SNORM, 0 }, + { PIPE_FORMAT_L16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_FORMAT_L8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_LUMINANCE_ALPHA_SNORM, GL_LUMINANCE8_ALPHA8_SNORM, 0 }, + { PIPE_FORMAT_L8A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_LUMINANCE16_ALPHA16_SNORM, 0 }, + { PIPE_FORMAT_L16A16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_FORMAT_L8A8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_INTENSITY_SNORM, GL_INTENSITY8_SNORM, 0 }, + { PIPE_FORMAT_I8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_INTENSITY16_SNORM, 0 }, + { PIPE_FORMAT_I16_SNORM, PIPE_FORMAT_R16G16B16A16_SNORM, + PIPE_FORMAT_I8_SNORM, PIPE_FORMAT_R8G8B8A8_SNORM, 0 } + }, + { + { GL_RGB9_E5, 0 }, + { PIPE_FORMAT_R9G9B9E5_FLOAT, 0 } + }, + { + { GL_R11F_G11F_B10F, 0 }, + { PIPE_FORMAT_R11G11B10_FLOAT, 0 } + } +}; + + +/** + * Return first supported format from the given list. + */ +static enum pipe_format +find_supported_format(struct pipe_screen *screen, + const enum pipe_format formats[], + enum pipe_texture_target target, + unsigned sample_count, + unsigned tex_usage) +{ + uint i; + for (i = 0; formats[i]; i++) { + if (screen->is_format_supported(screen, formats[i], target, + sample_count, tex_usage)) { + return formats[i]; + } + } + return PIPE_FORMAT_NONE; +} + +struct exact_format_mapping +{ + GLenum format; + GLenum type; + enum pipe_format pformat; +}; + +static const struct exact_format_mapping rgba8888_tbl[] = +{ + { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_A8B8G8R8_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_A8B8G8R8_UNORM }, + { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_R8G8B8A8_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_R8G8B8A8_UNORM }, + { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_A8R8G8B8_UNORM }, + { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_B8G8R8A8_UNORM }, + { GL_RGBA, GL_UNSIGNED_BYTE, PIPE_FORMAT_R8G8B8A8_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_BYTE, PIPE_FORMAT_A8B8G8R8_UNORM }, + { GL_BGRA, GL_UNSIGNED_BYTE, PIPE_FORMAT_B8G8R8A8_UNORM }, + { 0, 0, 0 } +}; + +static const struct exact_format_mapping rgbx8888_tbl[] = +{ + { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_X8R8G8B8_UNORM }, + { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_B8G8R8X8_UNORM }, + { GL_BGRA, GL_UNSIGNED_BYTE, PIPE_FORMAT_B8G8R8X8_UNORM }, + /* No Mesa formats for these Gallium formats: + { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_X8B8G8R8_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_X8B8G8R8_UNORM }, + { GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, PIPE_FORMAT_R8G8B8X8_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_INT_8_8_8_8, PIPE_FORMAT_R8G8B8X8_UNORM }, + { GL_RGBA, GL_UNSIGNED_BYTE, PIPE_FORMAT_R8G8B8X8_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_BYTE, PIPE_FORMAT_X8B8G8R8_UNORM }, + */ + { 0, 0, 0 } +}; + +static const struct exact_format_mapping rgba1010102_tbl[] = +{ + { GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV, PIPE_FORMAT_B10G10R10A2_UNORM }, + /* No Mesa formats for these Gallium formats: + { GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, PIPE_FORMAT_R10G10B10A2_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_INT_10_10_10_2, PIPE_FORMAT_R10G10B10A2_UNORM }, + { GL_ABGR_EXT, GL_UNSIGNED_INT, PIPE_FORMAT_R10G10B10A2_UNORM }, + */ + { 0, 0, 0 } +}; + +/** + * If there is an exact pipe_format match for {internalFormat, format, type} + * return that, otherwise return PIPE_FORMAT_NONE so we can do fuzzy matching. + */ +static enum pipe_format +find_exact_format(GLint internalFormat, GLenum format, GLenum type) +{ + uint i; + const struct exact_format_mapping* tbl; + + if (format == GL_NONE || type == GL_NONE) + return PIPE_FORMAT_NONE; + + switch (internalFormat) { + case 4: + case GL_RGBA: + case GL_RGBA8: + tbl = rgba8888_tbl; + break; + case 3: + case GL_RGB: + case GL_RGB8: + tbl = rgbx8888_tbl; + break; + case GL_RGB10_A2: + tbl = rgba1010102_tbl; + break; + default: + return PIPE_FORMAT_NONE; + } + + for (i = 0; tbl[i].format; i++) + if (tbl[i].format == format && tbl[i].type == type) + return tbl[i].pformat; + + return PIPE_FORMAT_NONE; +} + +/** + * Given an OpenGL internalFormat value for a texture or surface, return + * the best matching PIPE_FORMAT_x, or PIPE_FORMAT_NONE if there's no match. + * This is called during glTexImage2D, for example. + * + * The bindings parameter typically has PIPE_BIND_SAMPLER_VIEW set, plus + * either PIPE_BINDING_RENDER_TARGET or PIPE_BINDING_DEPTH_STENCIL if + * we want render-to-texture ability. + * + * \param internalFormat the user value passed to glTexImage2D + * \param target one of PIPE_TEXTURE_x + * \param bindings bitmask of PIPE_BIND_x flags. + */ +enum pipe_format +st_choose_format(struct pipe_screen *screen, GLenum internalFormat, + GLenum format, GLenum type, + enum pipe_texture_target target, unsigned sample_count, + unsigned bindings) +{ + GET_CURRENT_CONTEXT(ctx); /* XXX this should be a function parameter */ + int i, j; + enum pipe_format pf; + + /* can't render to compressed formats at this time */ + if (_mesa_is_compressed_format(ctx, internalFormat) + && (bindings & ~PIPE_BIND_SAMPLER_VIEW)) { + return PIPE_FORMAT_NONE; + } + + /* search for exact matches */ + pf = find_exact_format(internalFormat, format, type); + if (pf != PIPE_FORMAT_NONE && + screen->is_format_supported(screen, pf, + target, sample_count, bindings)) + return pf; + + /* search table for internalFormat */ + for (i = 0; i < Elements(format_map); i++) { + const struct format_mapping *mapping = &format_map[i]; + for (j = 0; mapping->glFormats[j]; j++) { + if (mapping->glFormats[j] == internalFormat) { + /* Found the desired internal format. Find first pipe format + * which is supported by the driver. + */ + return find_supported_format(screen, mapping->pipeFormats, + target, sample_count, bindings); + } + } + } + + _mesa_problem(NULL, "unhandled format!\n"); + return PIPE_FORMAT_NONE; +} + + +/** + * Called by FBO code to choose a PIPE_FORMAT_ for drawing surfaces. + */ +enum pipe_format +st_choose_renderbuffer_format(struct pipe_screen *screen, + GLenum internalFormat, unsigned sample_count) +{ + uint usage; + if (_mesa_is_depth_or_stencil_format(internalFormat)) + usage = PIPE_BIND_DEPTH_STENCIL; + else + usage = PIPE_BIND_RENDER_TARGET; + return st_choose_format(screen, internalFormat, GL_NONE, GL_NONE, PIPE_TEXTURE_2D, + sample_count, usage); +} + + +gl_format +st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat, + GLenum format, GLenum type, GLboolean renderable) +{ + struct pipe_screen *screen = st_context(ctx)->pipe->screen; + enum pipe_format pFormat; + uint bindings; + + (void) format; + (void) type; + + /* GL textures may wind up being render targets, but we don't know + * that in advance. Specify potential render target flags now. + */ + bindings = PIPE_BIND_SAMPLER_VIEW; + if (renderable) { + if (_mesa_is_depth_or_stencil_format(internalFormat)) + bindings |= PIPE_BIND_DEPTH_STENCIL; + else + bindings |= PIPE_BIND_RENDER_TARGET; + } + + pFormat = st_choose_format(screen, internalFormat, format, type, + PIPE_TEXTURE_2D, 0, bindings); + + if (pFormat == PIPE_FORMAT_NONE) { + /* try choosing format again, this time without render target bindings */ + pFormat = st_choose_format(screen, internalFormat, format, type, + PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW); + } + + if (pFormat == PIPE_FORMAT_NONE) { + /* no luck at all */ + return MESA_FORMAT_NONE; + } + + return st_pipe_format_to_mesa_format(pFormat); +} + + +/** + * Called via ctx->Driver.ChooseTextureFormat(). + */ +gl_format +st_ChooseTextureFormat(struct gl_context *ctx, GLint internalFormat, + GLenum format, GLenum type) +{ + boolean want_renderable = + internalFormat == 3 || internalFormat == 4 || + internalFormat == GL_RGB || internalFormat == GL_RGBA || + internalFormat == GL_RGB8 || internalFormat == GL_RGBA8 || + internalFormat == GL_BGRA; + + return st_ChooseTextureFormat_renderable(ctx, internalFormat, + format, type, want_renderable); +} + +/** + * Test if a gallium format is equivalent to a GL format/type. + */ +GLboolean +st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type) +{ + switch (pFormat) { + case PIPE_FORMAT_A8B8G8R8_UNORM: + return format == GL_RGBA && type == GL_UNSIGNED_BYTE; + case PIPE_FORMAT_A8R8G8B8_UNORM: + return format == GL_BGRA && type == GL_UNSIGNED_BYTE; + case PIPE_FORMAT_B5G6R5_UNORM: + return format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5; + /* XXX more combos... */ + default: + return GL_FALSE; + } +} + +GLboolean +st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2) +{ + if (format1 == format2) + return GL_TRUE; + + if (format1 == PIPE_FORMAT_B8G8R8A8_UNORM && + format2 == PIPE_FORMAT_B8G8R8X8_UNORM) + return GL_TRUE; + + if (format1 == PIPE_FORMAT_B8G8R8X8_UNORM && + format2 == PIPE_FORMAT_B8G8R8A8_UNORM) + return GL_TRUE; + + if (format1 == PIPE_FORMAT_A8B8G8R8_UNORM && + format2 == PIPE_FORMAT_X8B8G8R8_UNORM) + return GL_TRUE; + + if (format1 == PIPE_FORMAT_X8B8G8R8_UNORM && + format2 == PIPE_FORMAT_A8B8G8R8_UNORM) + return GL_TRUE; + + if (format1 == PIPE_FORMAT_A8R8G8B8_UNORM && + format2 == PIPE_FORMAT_X8R8G8B8_UNORM) + return GL_TRUE; + + if (format1 == PIPE_FORMAT_X8R8G8B8_UNORM && + format2 == PIPE_FORMAT_A8R8G8B8_UNORM) + return GL_TRUE; + + return GL_FALSE; +} + + + +/** + * This is used for translating texture border color and the clear + * color. For example, the clear color is interpreted according to + * the renderbuffer's base format. For example, if clearing a + * GL_LUMINANCE buffer, ClearColor[0] = luminance and ClearColor[1] = + * alpha. Similarly for texture border colors. + */ +void +st_translate_color(const GLfloat colorIn[4], GLenum baseFormat, + GLfloat colorOut[4]) +{ + switch (baseFormat) { + case GL_RED: + colorOut[0] = colorIn[0]; + colorOut[1] = 0.0F; + colorOut[2] = 0.0F; + colorOut[3] = 1.0F; + break; + case GL_RG: + colorOut[0] = colorIn[0]; + colorOut[1] = colorIn[1]; + colorOut[2] = 0.0F; + colorOut[3] = 1.0F; + break; + case GL_RGB: + colorOut[0] = colorIn[0]; + colorOut[1] = colorIn[1]; + colorOut[2] = colorIn[2]; + colorOut[3] = 1.0F; + break; + case GL_ALPHA: + colorOut[0] = colorOut[1] = colorOut[2] = 0.0; + colorOut[3] = colorIn[3]; + break; + case GL_LUMINANCE: + colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0]; + colorOut[3] = 1.0; + break; + case GL_LUMINANCE_ALPHA: + colorOut[0] = colorOut[1] = colorOut[2] = colorIn[0]; + colorOut[3] = colorIn[3]; + break; + case GL_INTENSITY: + colorOut[0] = colorOut[1] = colorOut[2] = colorOut[3] = colorIn[0]; + break; + default: + COPY_4V(colorOut, colorIn); + } +} diff --git a/mesalib/src/mesa/state_tracker/st_format.h b/mesalib/src/mesa/state_tracker/st_format.h index fcfb47201..1c1f5965f 100644 --- a/mesalib/src/mesa/state_tracker/st_format.h +++ b/mesalib/src/mesa/state_tracker/st_format.h @@ -1,87 +1,87 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * Copyright (c) 2010 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.
- *
- **************************************************************************/
-
-
-#ifndef ST_FORMAT_H
-#define ST_FORMAT_H
-
-#include "main/formats.h"
-#include "main/glheader.h"
-
-#include "pipe/p_defines.h"
-#include "pipe/p_format.h"
-
-struct gl_context;
-struct pipe_screen;
-
-extern GLenum
-st_format_datatype(enum pipe_format format);
-
-
-extern enum pipe_format
-st_mesa_format_to_pipe_format(gl_format mesaFormat);
-
-extern gl_format
-st_pipe_format_to_mesa_format(enum pipe_format pipeFormat);
-
-
-extern enum pipe_format
-st_choose_format(struct pipe_screen *screen, GLenum internalFormat,
- GLenum format, GLenum type,
- enum pipe_texture_target target, unsigned sample_count,
- unsigned bindings);
-
-extern enum pipe_format
-st_choose_renderbuffer_format(struct pipe_screen *screen,
- GLenum internalFormat, unsigned sample_count);
-
-
-gl_format
-st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat,
- GLenum format, GLenum type, GLboolean renderable);
-
-extern gl_format
-st_ChooseTextureFormat(struct gl_context * ctx, GLint internalFormat,
- GLenum format, GLenum type);
-
-
-extern GLboolean
-st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type);
-
-/* can we use a sampler view to translate these formats
- only used to make TFP so far */
-extern GLboolean
-st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2);
-
-
-extern void
-st_translate_color(const GLfloat colorIn[4], GLenum baseFormat,
- GLfloat colorOut[4]);
-
-
-#endif /* ST_FORMAT_H */
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (c) 2010 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. + * + **************************************************************************/ + + +#ifndef ST_FORMAT_H +#define ST_FORMAT_H + +#include "main/formats.h" +#include "main/glheader.h" + +#include "pipe/p_defines.h" +#include "pipe/p_format.h" + +struct gl_context; +struct pipe_screen; + +extern GLenum +st_format_datatype(enum pipe_format format); + + +extern enum pipe_format +st_mesa_format_to_pipe_format(gl_format mesaFormat); + +extern gl_format +st_pipe_format_to_mesa_format(enum pipe_format pipeFormat); + + +extern enum pipe_format +st_choose_format(struct pipe_screen *screen, GLenum internalFormat, + GLenum format, GLenum type, + enum pipe_texture_target target, unsigned sample_count, + unsigned bindings); + +extern enum pipe_format +st_choose_renderbuffer_format(struct pipe_screen *screen, + GLenum internalFormat, unsigned sample_count); + + +gl_format +st_ChooseTextureFormat_renderable(struct gl_context *ctx, GLint internalFormat, + GLenum format, GLenum type, GLboolean renderable); + +extern gl_format +st_ChooseTextureFormat(struct gl_context * ctx, GLint internalFormat, + GLenum format, GLenum type); + + +extern GLboolean +st_equal_formats(enum pipe_format pFormat, GLenum format, GLenum type); + +/* can we use a sampler view to translate these formats + only used to make TFP so far */ +extern GLboolean +st_sampler_compat_formats(enum pipe_format format1, enum pipe_format format2); + + +extern void +st_translate_color(const GLfloat colorIn[4], GLenum baseFormat, + GLfloat colorOut[4]); + + +#endif /* ST_FORMAT_H */ diff --git a/mesalib/src/mesa/state_tracker/st_mesa_to_tgsi.c b/mesalib/src/mesa/state_tracker/st_mesa_to_tgsi.c index 3ced74e41..b4111b00d 100644 --- a/mesalib/src/mesa/state_tracker/st_mesa_to_tgsi.c +++ b/mesalib/src/mesa/state_tracker/st_mesa_to_tgsi.c @@ -1,1284 +1,1284 @@ -/**************************************************************************
- *
- * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-/*
- * \author
- * Michal Krol,
- * Keith Whitwell
- */
-
-#include "pipe/p_compiler.h"
-#include "pipe/p_context.h"
-#include "pipe/p_screen.h"
-#include "pipe/p_shader_tokens.h"
-#include "pipe/p_state.h"
-#include "tgsi/tgsi_ureg.h"
-#include "st_mesa_to_tgsi.h"
-#include "st_context.h"
-#include "program/prog_instruction.h"
-#include "program/prog_parameter.h"
-#include "util/u_debug.h"
-#include "util/u_math.h"
-#include "util/u_memory.h"
-
-
-#define PROGRAM_ANY_CONST ((1 << PROGRAM_LOCAL_PARAM) | \
- (1 << PROGRAM_ENV_PARAM) | \
- (1 << PROGRAM_STATE_VAR) | \
- (1 << PROGRAM_NAMED_PARAM) | \
- (1 << PROGRAM_CONSTANT) | \
- (1 << PROGRAM_UNIFORM))
-
-
-struct label {
- unsigned branch_target;
- unsigned token;
-};
-
-
-/**
- * Intermediate state used during shader translation.
- */
-struct st_translate {
- struct ureg_program *ureg;
-
- struct ureg_dst temps[MAX_PROGRAM_TEMPS];
- struct ureg_src *constants;
- struct ureg_dst outputs[PIPE_MAX_SHADER_OUTPUTS];
- struct ureg_src inputs[PIPE_MAX_SHADER_INPUTS];
- struct ureg_dst address[1];
- struct ureg_src samplers[PIPE_MAX_SAMPLERS];
- struct ureg_src systemValues[SYSTEM_VALUE_MAX];
-
- /* Extra info for handling point size clamping in vertex shader */
- struct ureg_dst pointSizeResult; /**< Actual point size output register */
- struct ureg_src pointSizeConst; /**< Point size range constant register */
- GLint pointSizeOutIndex; /**< Temp point size output register */
- GLboolean prevInstWrotePointSize;
-
- const GLuint *inputMapping;
- const GLuint *outputMapping;
-
- /* For every instruction that contains a label (eg CALL), keep
- * details so that we can go back afterwards and emit the correct
- * tgsi instruction number for each label.
- */
- struct label *labels;
- unsigned labels_size;
- unsigned labels_count;
-
- /* Keep a record of the tgsi instruction number that each mesa
- * instruction starts at, will be used to fix up labels after
- * translation.
- */
- unsigned *insn;
- unsigned insn_size;
- unsigned insn_count;
-
- unsigned procType; /**< TGSI_PROCESSOR_VERTEX/FRAGMENT */
-
- boolean error;
-};
-
-
-/** Map Mesa's SYSTEM_VALUE_x to TGSI_SEMANTIC_x */
-static unsigned mesa_sysval_to_semantic[SYSTEM_VALUE_MAX] = {
- TGSI_SEMANTIC_FACE,
- TGSI_SEMANTIC_INSTANCEID
-};
-
-
-/**
- * Make note of a branch to a label in the TGSI code.
- * After we've emitted all instructions, we'll go over the list
- * of labels built here and patch the TGSI code with the actual
- * location of each label.
- */
-static unsigned *get_label( struct st_translate *t,
- unsigned branch_target )
-{
- unsigned i;
-
- if (t->labels_count + 1 >= t->labels_size) {
- unsigned old_size = t->labels_size;
- t->labels_size = 1 << (util_logbase2(t->labels_size) + 1);
- t->labels = REALLOC( t->labels,
- old_size * sizeof t->labels[0],
- t->labels_size * sizeof t->labels[0] );
- if (t->labels == NULL) {
- static unsigned dummy;
- t->error = TRUE;
- return &dummy;
- }
- }
-
- i = t->labels_count++;
- t->labels[i].branch_target = branch_target;
- return &t->labels[i].token;
-}
-
-
-/**
- * Called prior to emitting the TGSI code for each Mesa instruction.
- * Allocate additional space for instructions if needed.
- * Update the insn[] array so the next Mesa instruction points to
- * the next TGSI instruction.
- */
-static void set_insn_start( struct st_translate *t,
- unsigned start )
-{
- if (t->insn_count + 1 >= t->insn_size) {
- unsigned old_size = t->insn_size;
- t->insn_size = 1 << (util_logbase2(t->insn_size) + 1);
- t->insn = REALLOC( t->insn,
- old_size * sizeof t->insn[0],
- t->insn_size * sizeof t->insn[0] );
- if (t->insn == NULL) {
- t->error = TRUE;
- return;
- }
- }
-
- t->insn[t->insn_count++] = start;
-}
-
-
-/**
- * Map a Mesa dst register to a TGSI ureg_dst register.
- */
-static struct ureg_dst
-dst_register( struct st_translate *t,
- gl_register_file file,
- GLuint index )
-{
- switch( file ) {
- case PROGRAM_UNDEFINED:
- return ureg_dst_undef();
-
- case PROGRAM_TEMPORARY:
- if (ureg_dst_is_undef(t->temps[index]))
- t->temps[index] = ureg_DECL_temporary( t->ureg );
-
- return t->temps[index];
-
- case PROGRAM_OUTPUT:
- if (t->procType == TGSI_PROCESSOR_VERTEX && index == VERT_RESULT_PSIZ)
- t->prevInstWrotePointSize = GL_TRUE;
-
- if (t->procType == TGSI_PROCESSOR_VERTEX)
- assert(index < VERT_RESULT_MAX);
- else if (t->procType == TGSI_PROCESSOR_FRAGMENT)
- assert(index < FRAG_RESULT_MAX);
- else
- assert(index < GEOM_RESULT_MAX);
-
- assert(t->outputMapping[index] < Elements(t->outputs));
-
- return t->outputs[t->outputMapping[index]];
-
- case PROGRAM_ADDRESS:
- return t->address[index];
-
- default:
- debug_assert( 0 );
- return ureg_dst_undef();
- }
-}
-
-
-/**
- * Map a Mesa src register to a TGSI ureg_src register.
- */
-static struct ureg_src
-src_register( struct st_translate *t,
- gl_register_file file,
- GLint index )
-{
- switch( file ) {
- case PROGRAM_UNDEFINED:
- return ureg_src_undef();
-
- case PROGRAM_TEMPORARY:
- assert(index >= 0);
- assert(index < Elements(t->temps));
- if (ureg_dst_is_undef(t->temps[index]))
- t->temps[index] = ureg_DECL_temporary( t->ureg );
- return ureg_src(t->temps[index]);
-
- case PROGRAM_NAMED_PARAM:
- case PROGRAM_ENV_PARAM:
- case PROGRAM_LOCAL_PARAM:
- case PROGRAM_UNIFORM:
- assert(index >= 0);
- return t->constants[index];
- case PROGRAM_STATE_VAR:
- case PROGRAM_CONSTANT: /* ie, immediate */
- if (index < 0)
- return ureg_DECL_constant( t->ureg, 0 );
- else
- return t->constants[index];
-
- case PROGRAM_INPUT:
- assert(t->inputMapping[index] < Elements(t->inputs));
- return t->inputs[t->inputMapping[index]];
-
- case PROGRAM_OUTPUT:
- assert(t->outputMapping[index] < Elements(t->outputs));
- return ureg_src(t->outputs[t->outputMapping[index]]); /* not needed? */
-
- case PROGRAM_ADDRESS:
- return ureg_src(t->address[index]);
-
- case PROGRAM_SYSTEM_VALUE:
- assert(index < Elements(t->systemValues));
- return t->systemValues[index];
-
- default:
- debug_assert( 0 );
- return ureg_src_undef();
- }
-}
-
-
-/**
- * Map mesa texture target to TGSI texture target.
- */
-unsigned
-translate_texture_target( GLuint textarget,
- GLboolean shadow )
-{
- if (shadow) {
- switch( textarget ) {
- case TEXTURE_1D_INDEX: return TGSI_TEXTURE_SHADOW1D;
- case TEXTURE_2D_INDEX: return TGSI_TEXTURE_SHADOW2D;
- case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_SHADOWRECT;
- case TEXTURE_1D_ARRAY_INDEX: return TGSI_TEXTURE_SHADOW1D_ARRAY;
- case TEXTURE_2D_ARRAY_INDEX: return TGSI_TEXTURE_SHADOW2D_ARRAY;
- default: break;
- }
- }
-
- switch( textarget ) {
- case TEXTURE_1D_INDEX: return TGSI_TEXTURE_1D;
- case TEXTURE_2D_INDEX: return TGSI_TEXTURE_2D;
- case TEXTURE_3D_INDEX: return TGSI_TEXTURE_3D;
- case TEXTURE_CUBE_INDEX: return TGSI_TEXTURE_CUBE;
- case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_RECT;
- case TEXTURE_1D_ARRAY_INDEX: return TGSI_TEXTURE_1D_ARRAY;
- case TEXTURE_2D_ARRAY_INDEX: return TGSI_TEXTURE_2D_ARRAY;
- default:
- debug_assert( 0 );
- return TGSI_TEXTURE_1D;
- }
-}
-
-
-/**
- * Create a TGSI ureg_dst register from a Mesa dest register.
- */
-static struct ureg_dst
-translate_dst( struct st_translate *t,
- const struct prog_dst_register *DstReg,
- boolean saturate )
-{
- struct ureg_dst dst = dst_register( t,
- DstReg->File,
- DstReg->Index );
-
- dst = ureg_writemask( dst,
- DstReg->WriteMask );
-
- if (saturate)
- dst = ureg_saturate( dst );
-
- if (DstReg->RelAddr)
- dst = ureg_dst_indirect( dst, ureg_src(t->address[0]) );
-
- return dst;
-}
-
-
-/**
- * Create a TGSI ureg_src register from a Mesa src register.
- */
-static struct ureg_src
-translate_src( struct st_translate *t,
- const struct prog_src_register *SrcReg )
-{
- struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index );
-
- if (t->procType == TGSI_PROCESSOR_GEOMETRY && SrcReg->HasIndex2) {
- src = src_register( t, SrcReg->File, SrcReg->Index2 );
- if (SrcReg->RelAddr2)
- src = ureg_src_dimension_indirect( src, ureg_src(t->address[0]),
- SrcReg->Index);
- else
- src = ureg_src_dimension( src, SrcReg->Index);
- }
-
- src = ureg_swizzle( src,
- GET_SWZ( SrcReg->Swizzle, 0 ) & 0x3,
- GET_SWZ( SrcReg->Swizzle, 1 ) & 0x3,
- GET_SWZ( SrcReg->Swizzle, 2 ) & 0x3,
- GET_SWZ( SrcReg->Swizzle, 3 ) & 0x3);
-
- if (SrcReg->Negate == NEGATE_XYZW)
- src = ureg_negate(src);
-
- if (SrcReg->Abs)
- src = ureg_abs(src);
-
- if (SrcReg->RelAddr) {
- src = ureg_src_indirect( src, ureg_src(t->address[0]));
- if (SrcReg->File != PROGRAM_INPUT &&
- SrcReg->File != PROGRAM_OUTPUT) {
- /* If SrcReg->Index was negative, it was set to zero in
- * src_register(). Reassign it now. But don't do this
- * for input/output regs since they get remapped while
- * const buffers don't.
- */
- src.Index = SrcReg->Index;
- }
- }
-
- return src;
-}
-
-
-static struct ureg_src swizzle_4v( struct ureg_src src,
- const unsigned *swz )
-{
- return ureg_swizzle( src, swz[0], swz[1], swz[2], swz[3] );
-}
-
-
-/**
- * Translate a SWZ instruction into a MOV, MUL or MAD instruction. EG:
- *
- * SWZ dst, src.x-y10
- *
- * becomes:
- *
- * MAD dst {1,-1,0,0}, src.xyxx, {0,0,1,0}
- */
-static void emit_swz( struct st_translate *t,
- struct ureg_dst dst,
- const struct prog_src_register *SrcReg )
-{
- struct ureg_program *ureg = t->ureg;
- struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index );
-
- unsigned negate_mask = SrcReg->Negate;
-
- unsigned one_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ONE) << 0 |
- (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ONE) << 1 |
- (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ONE) << 2 |
- (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ONE) << 3);
-
- unsigned zero_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ZERO) << 0 |
- (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ZERO) << 1 |
- (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ZERO) << 2 |
- (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ZERO) << 3);
-
- unsigned negative_one_mask = one_mask & negate_mask;
- unsigned positive_one_mask = one_mask & ~negate_mask;
-
- struct ureg_src imm;
- unsigned i;
- unsigned mul_swizzle[4] = {0,0,0,0};
- unsigned add_swizzle[4] = {0,0,0,0};
- unsigned src_swizzle[4] = {0,0,0,0};
- boolean need_add = FALSE;
- boolean need_mul = FALSE;
-
- if (dst.WriteMask == 0)
- return;
-
- /* Is this just a MOV?
- */
- if (zero_mask == 0 &&
- one_mask == 0 &&
- (negate_mask == 0 || negate_mask == TGSI_WRITEMASK_XYZW))
- {
- ureg_MOV( ureg, dst, translate_src( t, SrcReg ));
- return;
- }
-
-#define IMM_ZERO 0
-#define IMM_ONE 1
-#define IMM_NEG_ONE 2
-
- imm = ureg_imm3f( ureg, 0, 1, -1 );
-
- for (i = 0; i < 4; i++) {
- unsigned bit = 1 << i;
-
- if (dst.WriteMask & bit) {
- if (positive_one_mask & bit) {
- mul_swizzle[i] = IMM_ZERO;
- add_swizzle[i] = IMM_ONE;
- need_add = TRUE;
- }
- else if (negative_one_mask & bit) {
- mul_swizzle[i] = IMM_ZERO;
- add_swizzle[i] = IMM_NEG_ONE;
- need_add = TRUE;
- }
- else if (zero_mask & bit) {
- mul_swizzle[i] = IMM_ZERO;
- add_swizzle[i] = IMM_ZERO;
- need_add = TRUE;
- }
- else {
- add_swizzle[i] = IMM_ZERO;
- src_swizzle[i] = GET_SWZ(SrcReg->Swizzle, i);
- need_mul = TRUE;
- if (negate_mask & bit) {
- mul_swizzle[i] = IMM_NEG_ONE;
- }
- else {
- mul_swizzle[i] = IMM_ONE;
- }
- }
- }
- }
-
- if (need_mul && need_add) {
- ureg_MAD( ureg,
- dst,
- swizzle_4v( src, src_swizzle ),
- swizzle_4v( imm, mul_swizzle ),
- swizzle_4v( imm, add_swizzle ) );
- }
- else if (need_mul) {
- ureg_MUL( ureg,
- dst,
- swizzle_4v( src, src_swizzle ),
- swizzle_4v( imm, mul_swizzle ) );
- }
- else if (need_add) {
- ureg_MOV( ureg,
- dst,
- swizzle_4v( imm, add_swizzle ) );
- }
- else {
- debug_assert(0);
- }
-
-#undef IMM_ZERO
-#undef IMM_ONE
-#undef IMM_NEG_ONE
-}
-
-
-/**
- * Negate the value of DDY to match GL semantics where (0,0) is the
- * lower-left corner of the window.
- * Note that the GL_ARB_fragment_coord_conventions extension will
- * effect this someday.
- */
-static void emit_ddy( struct st_translate *t,
- struct ureg_dst dst,
- const struct prog_src_register *SrcReg )
-{
- struct ureg_program *ureg = t->ureg;
- struct ureg_src src = translate_src( t, SrcReg );
- src = ureg_negate( src );
- ureg_DDY( ureg, dst, src );
-}
-
-
-
-unsigned
-translate_opcode( unsigned op )
-{
- switch( op ) {
- case OPCODE_ARL:
- return TGSI_OPCODE_ARL;
- case OPCODE_ABS:
- return TGSI_OPCODE_ABS;
- case OPCODE_ADD:
- return TGSI_OPCODE_ADD;
- case OPCODE_BGNLOOP:
- return TGSI_OPCODE_BGNLOOP;
- case OPCODE_BGNSUB:
- return TGSI_OPCODE_BGNSUB;
- case OPCODE_BRA:
- return TGSI_OPCODE_BRA;
- case OPCODE_BRK:
- return TGSI_OPCODE_BRK;
- case OPCODE_CAL:
- return TGSI_OPCODE_CAL;
- case OPCODE_CMP:
- return TGSI_OPCODE_CMP;
- case OPCODE_CONT:
- return TGSI_OPCODE_CONT;
- case OPCODE_COS:
- return TGSI_OPCODE_COS;
- case OPCODE_DDX:
- return TGSI_OPCODE_DDX;
- case OPCODE_DDY:
- return TGSI_OPCODE_DDY;
- case OPCODE_DP2:
- return TGSI_OPCODE_DP2;
- case OPCODE_DP2A:
- return TGSI_OPCODE_DP2A;
- case OPCODE_DP3:
- return TGSI_OPCODE_DP3;
- case OPCODE_DP4:
- return TGSI_OPCODE_DP4;
- case OPCODE_DPH:
- return TGSI_OPCODE_DPH;
- case OPCODE_DST:
- return TGSI_OPCODE_DST;
- case OPCODE_ELSE:
- return TGSI_OPCODE_ELSE;
- case OPCODE_EMIT_VERTEX:
- return TGSI_OPCODE_EMIT;
- case OPCODE_END_PRIMITIVE:
- return TGSI_OPCODE_ENDPRIM;
- case OPCODE_ENDIF:
- return TGSI_OPCODE_ENDIF;
- case OPCODE_ENDLOOP:
- return TGSI_OPCODE_ENDLOOP;
- case OPCODE_ENDSUB:
- return TGSI_OPCODE_ENDSUB;
- case OPCODE_EX2:
- return TGSI_OPCODE_EX2;
- case OPCODE_EXP:
- return TGSI_OPCODE_EXP;
- case OPCODE_FLR:
- return TGSI_OPCODE_FLR;
- case OPCODE_FRC:
- return TGSI_OPCODE_FRC;
- case OPCODE_IF:
- return TGSI_OPCODE_IF;
- case OPCODE_TRUNC:
- return TGSI_OPCODE_TRUNC;
- case OPCODE_KIL:
- return TGSI_OPCODE_KIL;
- case OPCODE_KIL_NV:
- return TGSI_OPCODE_KILP;
- case OPCODE_LG2:
- return TGSI_OPCODE_LG2;
- case OPCODE_LOG:
- return TGSI_OPCODE_LOG;
- case OPCODE_LIT:
- return TGSI_OPCODE_LIT;
- case OPCODE_LRP:
- return TGSI_OPCODE_LRP;
- case OPCODE_MAD:
- return TGSI_OPCODE_MAD;
- case OPCODE_MAX:
- return TGSI_OPCODE_MAX;
- case OPCODE_MIN:
- return TGSI_OPCODE_MIN;
- case OPCODE_MOV:
- return TGSI_OPCODE_MOV;
- case OPCODE_MUL:
- return TGSI_OPCODE_MUL;
- case OPCODE_NOP:
- return TGSI_OPCODE_NOP;
- case OPCODE_NRM3:
- return TGSI_OPCODE_NRM;
- case OPCODE_NRM4:
- return TGSI_OPCODE_NRM4;
- case OPCODE_POW:
- return TGSI_OPCODE_POW;
- case OPCODE_RCP:
- return TGSI_OPCODE_RCP;
- case OPCODE_RET:
- return TGSI_OPCODE_RET;
- case OPCODE_RSQ:
- return TGSI_OPCODE_RSQ;
- case OPCODE_SCS:
- return TGSI_OPCODE_SCS;
- case OPCODE_SEQ:
- return TGSI_OPCODE_SEQ;
- case OPCODE_SGE:
- return TGSI_OPCODE_SGE;
- case OPCODE_SGT:
- return TGSI_OPCODE_SGT;
- case OPCODE_SIN:
- return TGSI_OPCODE_SIN;
- case OPCODE_SLE:
- return TGSI_OPCODE_SLE;
- case OPCODE_SLT:
- return TGSI_OPCODE_SLT;
- case OPCODE_SNE:
- return TGSI_OPCODE_SNE;
- case OPCODE_SSG:
- return TGSI_OPCODE_SSG;
- case OPCODE_SUB:
- return TGSI_OPCODE_SUB;
- case OPCODE_TEX:
- return TGSI_OPCODE_TEX;
- case OPCODE_TXB:
- return TGSI_OPCODE_TXB;
- case OPCODE_TXD:
- return TGSI_OPCODE_TXD;
- case OPCODE_TXL:
- return TGSI_OPCODE_TXL;
- case OPCODE_TXP:
- return TGSI_OPCODE_TXP;
- case OPCODE_XPD:
- return TGSI_OPCODE_XPD;
- case OPCODE_END:
- return TGSI_OPCODE_END;
- default:
- debug_assert( 0 );
- return TGSI_OPCODE_NOP;
- }
-}
-
-
-static void
-compile_instruction(
- struct st_translate *t,
- const struct prog_instruction *inst )
-{
- struct ureg_program *ureg = t->ureg;
- GLuint i;
- struct ureg_dst dst[1];
- struct ureg_src src[4];
- unsigned num_dst;
- unsigned num_src;
-
- num_dst = _mesa_num_inst_dst_regs( inst->Opcode );
- num_src = _mesa_num_inst_src_regs( inst->Opcode );
-
- if (num_dst)
- dst[0] = translate_dst( t,
- &inst->DstReg,
- inst->SaturateMode );
-
- for (i = 0; i < num_src; i++)
- src[i] = translate_src( t, &inst->SrcReg[i] );
-
- switch( inst->Opcode ) {
- case OPCODE_SWZ:
- emit_swz( t, dst[0], &inst->SrcReg[0] );
- return;
-
- case OPCODE_BGNLOOP:
- case OPCODE_CAL:
- case OPCODE_ELSE:
- case OPCODE_ENDLOOP:
- case OPCODE_IF:
- debug_assert(num_dst == 0);
- ureg_label_insn( ureg,
- translate_opcode( inst->Opcode ),
- src, num_src,
- get_label( t, inst->BranchTarget ));
- return;
-
- case OPCODE_TEX:
- case OPCODE_TXB:
- case OPCODE_TXD:
- case OPCODE_TXL:
- case OPCODE_TXP:
- src[num_src++] = t->samplers[inst->TexSrcUnit];
- ureg_tex_insn( ureg,
- translate_opcode( inst->Opcode ),
- dst, num_dst,
- translate_texture_target( inst->TexSrcTarget,
- inst->TexShadow ),
- NULL, 0,
- src, num_src );
- return;
-
- case OPCODE_SCS:
- dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XY );
- ureg_insn( ureg,
- translate_opcode( inst->Opcode ),
- dst, num_dst,
- src, num_src );
- break;
-
- case OPCODE_XPD:
- dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XYZ );
- ureg_insn( ureg,
- translate_opcode( inst->Opcode ),
- dst, num_dst,
- src, num_src );
- break;
-
- case OPCODE_NOISE1:
- case OPCODE_NOISE2:
- case OPCODE_NOISE3:
- case OPCODE_NOISE4:
- /* At some point, a motivated person could add a better
- * implementation of noise. Currently not even the nvidia
- * binary drivers do anything more than this. In any case, the
- * place to do this is in the GL state tracker, not the poor
- * driver.
- */
- ureg_MOV( ureg, dst[0], ureg_imm1f(ureg, 0.5) );
- break;
-
- case OPCODE_DDY:
- emit_ddy( t, dst[0], &inst->SrcReg[0] );
- break;
-
- default:
- ureg_insn( ureg,
- translate_opcode( inst->Opcode ),
- dst, num_dst,
- src, num_src );
- break;
- }
-}
-
-
-/**
- * Emit the TGSI instructions for inverting and adjusting WPOS.
- * This code is unavoidable because it also depends on whether
- * a FBO is bound (STATE_FB_WPOS_Y_TRANSFORM).
- */
-static void
-emit_wpos_adjustment( struct st_translate *t,
- const struct gl_program *program,
- boolean invert,
- GLfloat adjX, GLfloat adjY[2])
-{
- struct ureg_program *ureg = t->ureg;
-
- /* Fragment program uses fragment position input.
- * Need to replace instances of INPUT[WPOS] with temp T
- * where T = INPUT[WPOS] by y is inverted.
- */
- static const gl_state_index wposTransformState[STATE_LENGTH]
- = { STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM, 0, 0, 0 };
-
- /* XXX: note we are modifying the incoming shader here! Need to
- * do this before emitting the constant decls below, or this
- * will be missed:
- */
- unsigned wposTransConst = _mesa_add_state_reference(program->Parameters,
- wposTransformState);
-
- struct ureg_src wpostrans = ureg_DECL_constant( ureg, wposTransConst );
- struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg );
- struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]];
-
- /* First, apply the coordinate shift: */
- if (adjX || adjY[0] || adjY[1]) {
- if (adjY[0] != adjY[1]) {
- /* Adjust the y coordinate by adjY[1] or adjY[0] respectively
- * depending on whether inversion is actually going to be applied
- * or not, which is determined by testing against the inversion
- * state variable used below, which will be either +1 or -1.
- */
- struct ureg_dst adj_temp = ureg_DECL_temporary(ureg);
-
- ureg_CMP(ureg, adj_temp,
- ureg_scalar(wpostrans, invert ? 2 : 0),
- ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f),
- ureg_imm4f(ureg, adjX, adjY[1], 0.0f, 0.0f));
- ureg_ADD(ureg, wpos_temp, wpos_input, ureg_src(adj_temp));
- } else {
- ureg_ADD(ureg, wpos_temp, wpos_input,
- ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f));
- }
- wpos_input = ureg_src(wpos_temp);
- } else {
- /* MOV wpos_temp, input[wpos]
- */
- ureg_MOV( ureg, wpos_temp, wpos_input );
- }
-
- /* Now the conditional y flip: STATE_FB_WPOS_Y_TRANSFORM.xy/zw will be
- * inversion/identity, or the other way around if we're drawing to an FBO.
- */
- if (invert) {
- /* MAD wpos_temp.y, wpos_input, wpostrans.xxxx, wpostrans.yyyy
- */
- ureg_MAD( ureg,
- ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
- wpos_input,
- ureg_scalar(wpostrans, 0),
- ureg_scalar(wpostrans, 1));
- } else {
- /* MAD wpos_temp.y, wpos_input, wpostrans.zzzz, wpostrans.wwww
- */
- ureg_MAD( ureg,
- ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
- wpos_input,
- ureg_scalar(wpostrans, 2),
- ureg_scalar(wpostrans, 3));
- }
-
- /* Use wpos_temp as position input from here on:
- */
- t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp);
-}
-
-
-/**
- * Emit fragment position/ooordinate code.
- */
-static void
-emit_wpos(struct st_context *st,
- struct st_translate *t,
- const struct gl_program *program,
- struct ureg_program *ureg)
-{
- const struct gl_fragment_program *fp =
- (const struct gl_fragment_program *) program;
- struct pipe_screen *pscreen = st->pipe->screen;
- GLfloat adjX = 0.0f;
- GLfloat adjY[2] = { 0.0f, 0.0f };
- boolean invert = FALSE;
-
- /* Query the pixel center conventions supported by the pipe driver and set
- * adjX, adjY to help out if it cannot handle the requested one internally.
- *
- * The bias of the y-coordinate depends on whether y-inversion takes place
- * (adjY[1]) or not (adjY[0]), which is in turn dependent on whether we are
- * drawing to an FBO (causes additional inversion), and whether the the pipe
- * driver origin and the requested origin differ (the latter condition is
- * stored in the 'invert' variable).
- *
- * For height = 100 (i = integer, h = half-integer, l = lower, u = upper):
- *
- * center shift only:
- * i -> h: +0.5
- * h -> i: -0.5
- *
- * inversion only:
- * l,i -> u,i: ( 0.0 + 1.0) * -1 + 100 = 99
- * l,h -> u,h: ( 0.5 + 0.0) * -1 + 100 = 99.5
- * u,i -> l,i: (99.0 + 1.0) * -1 + 100 = 0
- * u,h -> l,h: (99.5 + 0.0) * -1 + 100 = 0.5
- *
- * inversion and center shift:
- * l,i -> u,h: ( 0.0 + 0.5) * -1 + 100 = 99.5
- * l,h -> u,i: ( 0.5 + 0.5) * -1 + 100 = 99
- * u,i -> l,h: (99.0 + 0.5) * -1 + 100 = 0.5
- * u,h -> l,i: (99.5 + 0.5) * -1 + 100 = 0
- */
- if (fp->OriginUpperLeft) {
- /* Fragment shader wants origin in upper-left */
- if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) {
- /* the driver supports upper-left origin */
- }
- else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT)) {
- /* the driver supports lower-left origin, need to invert Y */
- ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT);
- invert = TRUE;
- }
- else
- assert(0);
- }
- else {
- /* Fragment shader wants origin in lower-left */
- if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT))
- /* the driver supports lower-left origin */
- ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT);
- else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT))
- /* the driver supports upper-left origin, need to invert Y */
- invert = TRUE;
- else
- assert(0);
- }
-
- if (fp->PixelCenterInteger) {
- /* Fragment shader wants pixel center integer */
- if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) {
- /* the driver supports pixel center integer */
- adjY[1] = 1.0f;
- ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
- }
- else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) {
- /* the driver supports pixel center half integer, need to bias X,Y */
- adjX = -0.5f;
- adjY[0] = -0.5f;
- adjY[1] = 0.5f;
- }
- else
- assert(0);
- }
- else {
- /* Fragment shader wants pixel center half integer */
- if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) {
- /* the driver supports pixel center half integer */
- }
- else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) {
- /* the driver supports pixel center integer, need to bias X,Y */
- adjX = adjY[0] = adjY[1] = 0.5f;
- ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
- }
- else
- assert(0);
- }
-
- /* we invert after adjustment so that we avoid the MOV to temporary,
- * and reuse the adjustment ADD instead */
- emit_wpos_adjustment(t, program, invert, adjX, adjY);
-}
-
-
-/**
- * OpenGL's fragment gl_FrontFace input is 1 for front-facing, 0 for back.
- * TGSI uses +1 for front, -1 for back.
- * This function converts the TGSI value to the GL value. Simply clamping/
- * saturating the value to [0,1] does the job.
- */
-static void
-emit_face_var( struct st_translate *t,
- const struct gl_program *program )
-{
- struct ureg_program *ureg = t->ureg;
- struct ureg_dst face_temp = ureg_DECL_temporary( ureg );
- struct ureg_src face_input = t->inputs[t->inputMapping[FRAG_ATTRIB_FACE]];
-
- /* MOV_SAT face_temp, input[face]
- */
- face_temp = ureg_saturate( face_temp );
- ureg_MOV( ureg, face_temp, face_input );
-
- /* Use face_temp as face input from here on:
- */
- t->inputs[t->inputMapping[FRAG_ATTRIB_FACE]] = ureg_src(face_temp);
-}
-
-
-static void
-emit_edgeflags( struct st_translate *t,
- const struct gl_program *program )
-{
- struct ureg_program *ureg = t->ureg;
- struct ureg_dst edge_dst = t->outputs[t->outputMapping[VERT_RESULT_EDGE]];
- struct ureg_src edge_src = t->inputs[t->inputMapping[VERT_ATTRIB_EDGEFLAG]];
-
- ureg_MOV( ureg, edge_dst, edge_src );
-}
-
-
-/**
- * Translate Mesa program to TGSI format.
- * \param program the program to translate
- * \param numInputs number of input registers used
- * \param inputMapping maps Mesa fragment program inputs to TGSI generic
- * input indexes
- * \param inputSemanticName the TGSI_SEMANTIC flag for each input
- * \param inputSemanticIndex the semantic index (ex: which texcoord) for
- * each input
- * \param interpMode the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input
- * \param numOutputs number of output registers used
- * \param outputMapping maps Mesa fragment program outputs to TGSI
- * generic outputs
- * \param outputSemanticName the TGSI_SEMANTIC flag for each output
- * \param outputSemanticIndex the semantic index (ex: which texcoord) for
- * each output
- *
- * \return PIPE_OK or PIPE_ERROR_OUT_OF_MEMORY
- */
-enum pipe_error
-st_translate_mesa_program(
- struct gl_context *ctx,
- uint procType,
- struct ureg_program *ureg,
- const struct gl_program *program,
- GLuint numInputs,
- const GLuint inputMapping[],
- const ubyte inputSemanticName[],
- const ubyte inputSemanticIndex[],
- const GLuint interpMode[],
- GLuint numOutputs,
- const GLuint outputMapping[],
- const ubyte outputSemanticName[],
- const ubyte outputSemanticIndex[],
- boolean passthrough_edgeflags )
-{
- struct st_translate translate, *t;
- unsigned i;
- enum pipe_error ret = PIPE_OK;
-
- assert(numInputs <= Elements(t->inputs));
- assert(numOutputs <= Elements(t->outputs));
-
- t = &translate;
- memset(t, 0, sizeof *t);
-
- t->procType = procType;
- t->inputMapping = inputMapping;
- t->outputMapping = outputMapping;
- t->ureg = ureg;
- t->pointSizeOutIndex = -1;
- t->prevInstWrotePointSize = GL_FALSE;
-
- /*_mesa_print_program(program);*/
-
- /*
- * Declare input attributes.
- */
- if (procType == TGSI_PROCESSOR_FRAGMENT) {
- for (i = 0; i < numInputs; i++) {
- if (program->InputFlags[0] & PROG_PARAM_BIT_CYL_WRAP) {
- t->inputs[i] = ureg_DECL_fs_input_cyl(ureg,
- inputSemanticName[i],
- inputSemanticIndex[i],
- interpMode[i],
- TGSI_CYLINDRICAL_WRAP_X);
- }
- else {
- t->inputs[i] = ureg_DECL_fs_input(ureg,
- inputSemanticName[i],
- inputSemanticIndex[i],
- interpMode[i]);
- }
- }
-
- if (program->InputsRead & FRAG_BIT_WPOS) {
- /* Must do this after setting up t->inputs, and before
- * emitting constant references, below:
- */
- emit_wpos(st_context(ctx), t, program, ureg);
- }
-
- if (program->InputsRead & FRAG_BIT_FACE) {
- emit_face_var( t, program );
- }
-
- /*
- * Declare output attributes.
- */
- for (i = 0; i < numOutputs; i++) {
- switch (outputSemanticName[i]) {
- case TGSI_SEMANTIC_POSITION:
- t->outputs[i] = ureg_DECL_output( ureg,
- TGSI_SEMANTIC_POSITION, /* Z / Depth */
- outputSemanticIndex[i] );
-
- t->outputs[i] = ureg_writemask( t->outputs[i],
- TGSI_WRITEMASK_Z );
- break;
- case TGSI_SEMANTIC_STENCIL:
- t->outputs[i] = ureg_DECL_output( ureg,
- TGSI_SEMANTIC_STENCIL, /* Stencil */
- outputSemanticIndex[i] );
- t->outputs[i] = ureg_writemask( t->outputs[i],
- TGSI_WRITEMASK_Y );
- break;
- case TGSI_SEMANTIC_COLOR:
- t->outputs[i] = ureg_DECL_output( ureg,
- TGSI_SEMANTIC_COLOR,
- outputSemanticIndex[i] );
- break;
- default:
- debug_assert(0);
- return 0;
- }
- }
- }
- else if (procType == TGSI_PROCESSOR_GEOMETRY) {
- for (i = 0; i < numInputs; i++) {
- t->inputs[i] = ureg_DECL_gs_input(ureg,
- i,
- inputSemanticName[i],
- inputSemanticIndex[i]);
- }
-
- for (i = 0; i < numOutputs; i++) {
- t->outputs[i] = ureg_DECL_output( ureg,
- outputSemanticName[i],
- outputSemanticIndex[i] );
- }
- }
- else {
- assert(procType == TGSI_PROCESSOR_VERTEX);
-
- for (i = 0; i < numInputs; i++) {
- t->inputs[i] = ureg_DECL_vs_input(ureg, i);
- }
-
- for (i = 0; i < numOutputs; i++) {
- t->outputs[i] = ureg_DECL_output( ureg,
- outputSemanticName[i],
- outputSemanticIndex[i] );
- if ((outputSemanticName[i] == TGSI_SEMANTIC_PSIZE) && program->Id) {
- /* Writing to the point size result register requires special
- * handling to implement clamping.
- */
- static const gl_state_index pointSizeClampState[STATE_LENGTH]
- = { STATE_INTERNAL, STATE_POINT_SIZE_IMPL_CLAMP, 0, 0, 0 };
- /* XXX: note we are modifying the incoming shader here! Need to
- * do this before emitting the constant decls below, or this
- * will be missed:
- */
- unsigned pointSizeClampConst =
- _mesa_add_state_reference(program->Parameters,
- pointSizeClampState);
- struct ureg_dst psizregtemp = ureg_DECL_temporary( ureg );
- t->pointSizeConst = ureg_DECL_constant( ureg, pointSizeClampConst );
- t->pointSizeResult = t->outputs[i];
- t->pointSizeOutIndex = i;
- t->outputs[i] = psizregtemp;
- }
- }
- if (passthrough_edgeflags)
- emit_edgeflags( t, program );
- }
-
- /* Declare address register.
- */
- if (program->NumAddressRegs > 0) {
- debug_assert( program->NumAddressRegs == 1 );
- t->address[0] = ureg_DECL_address( ureg );
- }
-
- /* Declare misc input registers
- */
- {
- GLbitfield sysInputs = program->SystemValuesRead;
- unsigned numSys = 0;
- for (i = 0; sysInputs; i++) {
- if (sysInputs & (1 << i)) {
- unsigned semName = mesa_sysval_to_semantic[i];
- t->systemValues[i] = ureg_DECL_system_value(ureg, numSys, semName, 0);
- numSys++;
- sysInputs &= ~(1 << i);
- }
- }
- }
-
- if (program->IndirectRegisterFiles & (1 << PROGRAM_TEMPORARY)) {
- /* If temps are accessed with indirect addressing, declare temporaries
- * in sequential order. Else, we declare them on demand elsewhere.
- */
- for (i = 0; i < program->NumTemporaries; i++) {
- /* XXX use TGSI_FILE_TEMPORARY_ARRAY when it's supported by ureg */
- t->temps[i] = ureg_DECL_temporary( t->ureg );
- }
- }
-
- /* Emit constants and immediates. Mesa uses a single index space
- * for these, so we put all the translated regs in t->constants.
- */
- if (program->Parameters) {
- t->constants = CALLOC( program->Parameters->NumParameters,
- sizeof t->constants[0] );
- if (t->constants == NULL) {
- ret = PIPE_ERROR_OUT_OF_MEMORY;
- goto out;
- }
-
- for (i = 0; i < program->Parameters->NumParameters; i++) {
- switch (program->Parameters->Parameters[i].Type) {
- case PROGRAM_ENV_PARAM:
- case PROGRAM_LOCAL_PARAM:
- case PROGRAM_STATE_VAR:
- case PROGRAM_NAMED_PARAM:
- case PROGRAM_UNIFORM:
- t->constants[i] = ureg_DECL_constant( ureg, i );
- break;
-
- /* Emit immediates only when there's no indirect addressing of
- * the const buffer.
- * FIXME: Be smarter and recognize param arrays:
- * indirect addressing is only valid within the referenced
- * array.
- */
- case PROGRAM_CONSTANT:
- if (program->IndirectRegisterFiles & PROGRAM_ANY_CONST)
- t->constants[i] = ureg_DECL_constant( ureg, i );
- else
- t->constants[i] =
- ureg_DECL_immediate( ureg,
- (const float*) program->Parameters->ParameterValues[i],
- 4 );
- break;
- default:
- break;
- }
- }
- }
-
- /* texture samplers */
- for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
- if (program->SamplersUsed & (1 << i)) {
- t->samplers[i] = ureg_DECL_sampler( ureg, i );
- }
- }
-
- /* Emit each instruction in turn:
- */
- for (i = 0; i < program->NumInstructions; i++) {
- set_insn_start( t, ureg_get_instruction_number( ureg ));
- compile_instruction( t, &program->Instructions[i] );
-
- if (t->prevInstWrotePointSize && program->Id) {
- /* The previous instruction wrote to the (fake) vertex point size
- * result register. Now we need to clamp that value to the min/max
- * point size range, putting the result into the real point size
- * register.
- * Note that we can't do this easily at the end of program due to
- * possible early return.
- */
- set_insn_start( t, ureg_get_instruction_number( ureg ));
- ureg_MAX( t->ureg,
- ureg_writemask(t->outputs[t->pointSizeOutIndex], WRITEMASK_X),
- ureg_src(t->outputs[t->pointSizeOutIndex]),
- ureg_swizzle(t->pointSizeConst, 1,1,1,1));
- ureg_MIN( t->ureg, ureg_writemask(t->pointSizeResult, WRITEMASK_X),
- ureg_src(t->outputs[t->pointSizeOutIndex]),
- ureg_swizzle(t->pointSizeConst, 2,2,2,2));
- }
- t->prevInstWrotePointSize = GL_FALSE;
- }
-
- /* Fix up all emitted labels:
- */
- for (i = 0; i < t->labels_count; i++) {
- ureg_fixup_label( ureg,
- t->labels[i].token,
- t->insn[t->labels[i].branch_target] );
- }
-
-out:
- FREE(t->insn);
- FREE(t->labels);
- FREE(t->constants);
-
- if (t->error) {
- debug_printf("%s: translate error flag set\n", __FUNCTION__);
- }
-
- return ret;
-}
-
-
-/**
- * Tokens cannot be free with free otherwise the builtin gallium
- * malloc debugging will get confused.
- */
-void
-st_free_tokens(const struct tgsi_token *tokens)
-{
- FREE((void *)tokens);
-}
+/************************************************************************** + * + * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + +/* + * \author + * Michal Krol, + * Keith Whitwell + */ + +#include "pipe/p_compiler.h" +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "pipe/p_shader_tokens.h" +#include "pipe/p_state.h" +#include "tgsi/tgsi_ureg.h" +#include "st_mesa_to_tgsi.h" +#include "st_context.h" +#include "program/prog_instruction.h" +#include "program/prog_parameter.h" +#include "util/u_debug.h" +#include "util/u_math.h" +#include "util/u_memory.h" + + +#define PROGRAM_ANY_CONST ((1 << PROGRAM_LOCAL_PARAM) | \ + (1 << PROGRAM_ENV_PARAM) | \ + (1 << PROGRAM_STATE_VAR) | \ + (1 << PROGRAM_NAMED_PARAM) | \ + (1 << PROGRAM_CONSTANT) | \ + (1 << PROGRAM_UNIFORM)) + + +struct label { + unsigned branch_target; + unsigned token; +}; + + +/** + * Intermediate state used during shader translation. + */ +struct st_translate { + struct ureg_program *ureg; + + struct ureg_dst temps[MAX_PROGRAM_TEMPS]; + struct ureg_src *constants; + struct ureg_dst outputs[PIPE_MAX_SHADER_OUTPUTS]; + struct ureg_src inputs[PIPE_MAX_SHADER_INPUTS]; + struct ureg_dst address[1]; + struct ureg_src samplers[PIPE_MAX_SAMPLERS]; + struct ureg_src systemValues[SYSTEM_VALUE_MAX]; + + /* Extra info for handling point size clamping in vertex shader */ + struct ureg_dst pointSizeResult; /**< Actual point size output register */ + struct ureg_src pointSizeConst; /**< Point size range constant register */ + GLint pointSizeOutIndex; /**< Temp point size output register */ + GLboolean prevInstWrotePointSize; + + const GLuint *inputMapping; + const GLuint *outputMapping; + + /* For every instruction that contains a label (eg CALL), keep + * details so that we can go back afterwards and emit the correct + * tgsi instruction number for each label. + */ + struct label *labels; + unsigned labels_size; + unsigned labels_count; + + /* Keep a record of the tgsi instruction number that each mesa + * instruction starts at, will be used to fix up labels after + * translation. + */ + unsigned *insn; + unsigned insn_size; + unsigned insn_count; + + unsigned procType; /**< TGSI_PROCESSOR_VERTEX/FRAGMENT */ + + boolean error; +}; + + +/** Map Mesa's SYSTEM_VALUE_x to TGSI_SEMANTIC_x */ +static unsigned mesa_sysval_to_semantic[SYSTEM_VALUE_MAX] = { + TGSI_SEMANTIC_FACE, + TGSI_SEMANTIC_INSTANCEID +}; + + +/** + * Make note of a branch to a label in the TGSI code. + * After we've emitted all instructions, we'll go over the list + * of labels built here and patch the TGSI code with the actual + * location of each label. + */ +static unsigned *get_label( struct st_translate *t, + unsigned branch_target ) +{ + unsigned i; + + if (t->labels_count + 1 >= t->labels_size) { + unsigned old_size = t->labels_size; + t->labels_size = 1 << (util_logbase2(t->labels_size) + 1); + t->labels = REALLOC( t->labels, + old_size * sizeof t->labels[0], + t->labels_size * sizeof t->labels[0] ); + if (t->labels == NULL) { + static unsigned dummy; + t->error = TRUE; + return &dummy; + } + } + + i = t->labels_count++; + t->labels[i].branch_target = branch_target; + return &t->labels[i].token; +} + + +/** + * Called prior to emitting the TGSI code for each Mesa instruction. + * Allocate additional space for instructions if needed. + * Update the insn[] array so the next Mesa instruction points to + * the next TGSI instruction. + */ +static void set_insn_start( struct st_translate *t, + unsigned start ) +{ + if (t->insn_count + 1 >= t->insn_size) { + unsigned old_size = t->insn_size; + t->insn_size = 1 << (util_logbase2(t->insn_size) + 1); + t->insn = REALLOC( t->insn, + old_size * sizeof t->insn[0], + t->insn_size * sizeof t->insn[0] ); + if (t->insn == NULL) { + t->error = TRUE; + return; + } + } + + t->insn[t->insn_count++] = start; +} + + +/** + * Map a Mesa dst register to a TGSI ureg_dst register. + */ +static struct ureg_dst +dst_register( struct st_translate *t, + gl_register_file file, + GLuint index ) +{ + switch( file ) { + case PROGRAM_UNDEFINED: + return ureg_dst_undef(); + + case PROGRAM_TEMPORARY: + if (ureg_dst_is_undef(t->temps[index])) + t->temps[index] = ureg_DECL_temporary( t->ureg ); + + return t->temps[index]; + + case PROGRAM_OUTPUT: + if (t->procType == TGSI_PROCESSOR_VERTEX && index == VERT_RESULT_PSIZ) + t->prevInstWrotePointSize = GL_TRUE; + + if (t->procType == TGSI_PROCESSOR_VERTEX) + assert(index < VERT_RESULT_MAX); + else if (t->procType == TGSI_PROCESSOR_FRAGMENT) + assert(index < FRAG_RESULT_MAX); + else + assert(index < GEOM_RESULT_MAX); + + assert(t->outputMapping[index] < Elements(t->outputs)); + + return t->outputs[t->outputMapping[index]]; + + case PROGRAM_ADDRESS: + return t->address[index]; + + default: + debug_assert( 0 ); + return ureg_dst_undef(); + } +} + + +/** + * Map a Mesa src register to a TGSI ureg_src register. + */ +static struct ureg_src +src_register( struct st_translate *t, + gl_register_file file, + GLint index ) +{ + switch( file ) { + case PROGRAM_UNDEFINED: + return ureg_src_undef(); + + case PROGRAM_TEMPORARY: + assert(index >= 0); + assert(index < Elements(t->temps)); + if (ureg_dst_is_undef(t->temps[index])) + t->temps[index] = ureg_DECL_temporary( t->ureg ); + return ureg_src(t->temps[index]); + + case PROGRAM_NAMED_PARAM: + case PROGRAM_ENV_PARAM: + case PROGRAM_LOCAL_PARAM: + case PROGRAM_UNIFORM: + assert(index >= 0); + return t->constants[index]; + case PROGRAM_STATE_VAR: + case PROGRAM_CONSTANT: /* ie, immediate */ + if (index < 0) + return ureg_DECL_constant( t->ureg, 0 ); + else + return t->constants[index]; + + case PROGRAM_INPUT: + assert(t->inputMapping[index] < Elements(t->inputs)); + return t->inputs[t->inputMapping[index]]; + + case PROGRAM_OUTPUT: + assert(t->outputMapping[index] < Elements(t->outputs)); + return ureg_src(t->outputs[t->outputMapping[index]]); /* not needed? */ + + case PROGRAM_ADDRESS: + return ureg_src(t->address[index]); + + case PROGRAM_SYSTEM_VALUE: + assert(index < Elements(t->systemValues)); + return t->systemValues[index]; + + default: + debug_assert( 0 ); + return ureg_src_undef(); + } +} + + +/** + * Map mesa texture target to TGSI texture target. + */ +unsigned +translate_texture_target( GLuint textarget, + GLboolean shadow ) +{ + if (shadow) { + switch( textarget ) { + case TEXTURE_1D_INDEX: return TGSI_TEXTURE_SHADOW1D; + case TEXTURE_2D_INDEX: return TGSI_TEXTURE_SHADOW2D; + case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_SHADOWRECT; + case TEXTURE_1D_ARRAY_INDEX: return TGSI_TEXTURE_SHADOW1D_ARRAY; + case TEXTURE_2D_ARRAY_INDEX: return TGSI_TEXTURE_SHADOW2D_ARRAY; + default: break; + } + } + + switch( textarget ) { + case TEXTURE_1D_INDEX: return TGSI_TEXTURE_1D; + case TEXTURE_2D_INDEX: return TGSI_TEXTURE_2D; + case TEXTURE_3D_INDEX: return TGSI_TEXTURE_3D; + case TEXTURE_CUBE_INDEX: return TGSI_TEXTURE_CUBE; + case TEXTURE_RECT_INDEX: return TGSI_TEXTURE_RECT; + case TEXTURE_1D_ARRAY_INDEX: return TGSI_TEXTURE_1D_ARRAY; + case TEXTURE_2D_ARRAY_INDEX: return TGSI_TEXTURE_2D_ARRAY; + default: + debug_assert( 0 ); + return TGSI_TEXTURE_1D; + } +} + + +/** + * Create a TGSI ureg_dst register from a Mesa dest register. + */ +static struct ureg_dst +translate_dst( struct st_translate *t, + const struct prog_dst_register *DstReg, + boolean saturate ) +{ + struct ureg_dst dst = dst_register( t, + DstReg->File, + DstReg->Index ); + + dst = ureg_writemask( dst, + DstReg->WriteMask ); + + if (saturate) + dst = ureg_saturate( dst ); + + if (DstReg->RelAddr) + dst = ureg_dst_indirect( dst, ureg_src(t->address[0]) ); + + return dst; +} + + +/** + * Create a TGSI ureg_src register from a Mesa src register. + */ +static struct ureg_src +translate_src( struct st_translate *t, + const struct prog_src_register *SrcReg ) +{ + struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index ); + + if (t->procType == TGSI_PROCESSOR_GEOMETRY && SrcReg->HasIndex2) { + src = src_register( t, SrcReg->File, SrcReg->Index2 ); + if (SrcReg->RelAddr2) + src = ureg_src_dimension_indirect( src, ureg_src(t->address[0]), + SrcReg->Index); + else + src = ureg_src_dimension( src, SrcReg->Index); + } + + src = ureg_swizzle( src, + GET_SWZ( SrcReg->Swizzle, 0 ) & 0x3, + GET_SWZ( SrcReg->Swizzle, 1 ) & 0x3, + GET_SWZ( SrcReg->Swizzle, 2 ) & 0x3, + GET_SWZ( SrcReg->Swizzle, 3 ) & 0x3); + + if (SrcReg->Negate == NEGATE_XYZW) + src = ureg_negate(src); + + if (SrcReg->Abs) + src = ureg_abs(src); + + if (SrcReg->RelAddr) { + src = ureg_src_indirect( src, ureg_src(t->address[0])); + if (SrcReg->File != PROGRAM_INPUT && + SrcReg->File != PROGRAM_OUTPUT) { + /* If SrcReg->Index was negative, it was set to zero in + * src_register(). Reassign it now. But don't do this + * for input/output regs since they get remapped while + * const buffers don't. + */ + src.Index = SrcReg->Index; + } + } + + return src; +} + + +static struct ureg_src swizzle_4v( struct ureg_src src, + const unsigned *swz ) +{ + return ureg_swizzle( src, swz[0], swz[1], swz[2], swz[3] ); +} + + +/** + * Translate a SWZ instruction into a MOV, MUL or MAD instruction. EG: + * + * SWZ dst, src.x-y10 + * + * becomes: + * + * MAD dst {1,-1,0,0}, src.xyxx, {0,0,1,0} + */ +static void emit_swz( struct st_translate *t, + struct ureg_dst dst, + const struct prog_src_register *SrcReg ) +{ + struct ureg_program *ureg = t->ureg; + struct ureg_src src = src_register( t, SrcReg->File, SrcReg->Index ); + + unsigned negate_mask = SrcReg->Negate; + + unsigned one_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ONE) << 0 | + (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ONE) << 1 | + (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ONE) << 2 | + (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ONE) << 3); + + unsigned zero_mask = ((GET_SWZ(SrcReg->Swizzle, 0) == SWIZZLE_ZERO) << 0 | + (GET_SWZ(SrcReg->Swizzle, 1) == SWIZZLE_ZERO) << 1 | + (GET_SWZ(SrcReg->Swizzle, 2) == SWIZZLE_ZERO) << 2 | + (GET_SWZ(SrcReg->Swizzle, 3) == SWIZZLE_ZERO) << 3); + + unsigned negative_one_mask = one_mask & negate_mask; + unsigned positive_one_mask = one_mask & ~negate_mask; + + struct ureg_src imm; + unsigned i; + unsigned mul_swizzle[4] = {0,0,0,0}; + unsigned add_swizzle[4] = {0,0,0,0}; + unsigned src_swizzle[4] = {0,0,0,0}; + boolean need_add = FALSE; + boolean need_mul = FALSE; + + if (dst.WriteMask == 0) + return; + + /* Is this just a MOV? + */ + if (zero_mask == 0 && + one_mask == 0 && + (negate_mask == 0 || negate_mask == TGSI_WRITEMASK_XYZW)) + { + ureg_MOV( ureg, dst, translate_src( t, SrcReg )); + return; + } + +#define IMM_ZERO 0 +#define IMM_ONE 1 +#define IMM_NEG_ONE 2 + + imm = ureg_imm3f( ureg, 0, 1, -1 ); + + for (i = 0; i < 4; i++) { + unsigned bit = 1 << i; + + if (dst.WriteMask & bit) { + if (positive_one_mask & bit) { + mul_swizzle[i] = IMM_ZERO; + add_swizzle[i] = IMM_ONE; + need_add = TRUE; + } + else if (negative_one_mask & bit) { + mul_swizzle[i] = IMM_ZERO; + add_swizzle[i] = IMM_NEG_ONE; + need_add = TRUE; + } + else if (zero_mask & bit) { + mul_swizzle[i] = IMM_ZERO; + add_swizzle[i] = IMM_ZERO; + need_add = TRUE; + } + else { + add_swizzle[i] = IMM_ZERO; + src_swizzle[i] = GET_SWZ(SrcReg->Swizzle, i); + need_mul = TRUE; + if (negate_mask & bit) { + mul_swizzle[i] = IMM_NEG_ONE; + } + else { + mul_swizzle[i] = IMM_ONE; + } + } + } + } + + if (need_mul && need_add) { + ureg_MAD( ureg, + dst, + swizzle_4v( src, src_swizzle ), + swizzle_4v( imm, mul_swizzle ), + swizzle_4v( imm, add_swizzle ) ); + } + else if (need_mul) { + ureg_MUL( ureg, + dst, + swizzle_4v( src, src_swizzle ), + swizzle_4v( imm, mul_swizzle ) ); + } + else if (need_add) { + ureg_MOV( ureg, + dst, + swizzle_4v( imm, add_swizzle ) ); + } + else { + debug_assert(0); + } + +#undef IMM_ZERO +#undef IMM_ONE +#undef IMM_NEG_ONE +} + + +/** + * Negate the value of DDY to match GL semantics where (0,0) is the + * lower-left corner of the window. + * Note that the GL_ARB_fragment_coord_conventions extension will + * effect this someday. + */ +static void emit_ddy( struct st_translate *t, + struct ureg_dst dst, + const struct prog_src_register *SrcReg ) +{ + struct ureg_program *ureg = t->ureg; + struct ureg_src src = translate_src( t, SrcReg ); + src = ureg_negate( src ); + ureg_DDY( ureg, dst, src ); +} + + + +unsigned +translate_opcode( unsigned op ) +{ + switch( op ) { + case OPCODE_ARL: + return TGSI_OPCODE_ARL; + case OPCODE_ABS: + return TGSI_OPCODE_ABS; + case OPCODE_ADD: + return TGSI_OPCODE_ADD; + case OPCODE_BGNLOOP: + return TGSI_OPCODE_BGNLOOP; + case OPCODE_BGNSUB: + return TGSI_OPCODE_BGNSUB; + case OPCODE_BRA: + return TGSI_OPCODE_BRA; + case OPCODE_BRK: + return TGSI_OPCODE_BRK; + case OPCODE_CAL: + return TGSI_OPCODE_CAL; + case OPCODE_CMP: + return TGSI_OPCODE_CMP; + case OPCODE_CONT: + return TGSI_OPCODE_CONT; + case OPCODE_COS: + return TGSI_OPCODE_COS; + case OPCODE_DDX: + return TGSI_OPCODE_DDX; + case OPCODE_DDY: + return TGSI_OPCODE_DDY; + case OPCODE_DP2: + return TGSI_OPCODE_DP2; + case OPCODE_DP2A: + return TGSI_OPCODE_DP2A; + case OPCODE_DP3: + return TGSI_OPCODE_DP3; + case OPCODE_DP4: + return TGSI_OPCODE_DP4; + case OPCODE_DPH: + return TGSI_OPCODE_DPH; + case OPCODE_DST: + return TGSI_OPCODE_DST; + case OPCODE_ELSE: + return TGSI_OPCODE_ELSE; + case OPCODE_EMIT_VERTEX: + return TGSI_OPCODE_EMIT; + case OPCODE_END_PRIMITIVE: + return TGSI_OPCODE_ENDPRIM; + case OPCODE_ENDIF: + return TGSI_OPCODE_ENDIF; + case OPCODE_ENDLOOP: + return TGSI_OPCODE_ENDLOOP; + case OPCODE_ENDSUB: + return TGSI_OPCODE_ENDSUB; + case OPCODE_EX2: + return TGSI_OPCODE_EX2; + case OPCODE_EXP: + return TGSI_OPCODE_EXP; + case OPCODE_FLR: + return TGSI_OPCODE_FLR; + case OPCODE_FRC: + return TGSI_OPCODE_FRC; + case OPCODE_IF: + return TGSI_OPCODE_IF; + case OPCODE_TRUNC: + return TGSI_OPCODE_TRUNC; + case OPCODE_KIL: + return TGSI_OPCODE_KIL; + case OPCODE_KIL_NV: + return TGSI_OPCODE_KILP; + case OPCODE_LG2: + return TGSI_OPCODE_LG2; + case OPCODE_LOG: + return TGSI_OPCODE_LOG; + case OPCODE_LIT: + return TGSI_OPCODE_LIT; + case OPCODE_LRP: + return TGSI_OPCODE_LRP; + case OPCODE_MAD: + return TGSI_OPCODE_MAD; + case OPCODE_MAX: + return TGSI_OPCODE_MAX; + case OPCODE_MIN: + return TGSI_OPCODE_MIN; + case OPCODE_MOV: + return TGSI_OPCODE_MOV; + case OPCODE_MUL: + return TGSI_OPCODE_MUL; + case OPCODE_NOP: + return TGSI_OPCODE_NOP; + case OPCODE_NRM3: + return TGSI_OPCODE_NRM; + case OPCODE_NRM4: + return TGSI_OPCODE_NRM4; + case OPCODE_POW: + return TGSI_OPCODE_POW; + case OPCODE_RCP: + return TGSI_OPCODE_RCP; + case OPCODE_RET: + return TGSI_OPCODE_RET; + case OPCODE_RSQ: + return TGSI_OPCODE_RSQ; + case OPCODE_SCS: + return TGSI_OPCODE_SCS; + case OPCODE_SEQ: + return TGSI_OPCODE_SEQ; + case OPCODE_SGE: + return TGSI_OPCODE_SGE; + case OPCODE_SGT: + return TGSI_OPCODE_SGT; + case OPCODE_SIN: + return TGSI_OPCODE_SIN; + case OPCODE_SLE: + return TGSI_OPCODE_SLE; + case OPCODE_SLT: + return TGSI_OPCODE_SLT; + case OPCODE_SNE: + return TGSI_OPCODE_SNE; + case OPCODE_SSG: + return TGSI_OPCODE_SSG; + case OPCODE_SUB: + return TGSI_OPCODE_SUB; + case OPCODE_TEX: + return TGSI_OPCODE_TEX; + case OPCODE_TXB: + return TGSI_OPCODE_TXB; + case OPCODE_TXD: + return TGSI_OPCODE_TXD; + case OPCODE_TXL: + return TGSI_OPCODE_TXL; + case OPCODE_TXP: + return TGSI_OPCODE_TXP; + case OPCODE_XPD: + return TGSI_OPCODE_XPD; + case OPCODE_END: + return TGSI_OPCODE_END; + default: + debug_assert( 0 ); + return TGSI_OPCODE_NOP; + } +} + + +static void +compile_instruction( + struct st_translate *t, + const struct prog_instruction *inst ) +{ + struct ureg_program *ureg = t->ureg; + GLuint i; + struct ureg_dst dst[1]; + struct ureg_src src[4]; + unsigned num_dst; + unsigned num_src; + + num_dst = _mesa_num_inst_dst_regs( inst->Opcode ); + num_src = _mesa_num_inst_src_regs( inst->Opcode ); + + if (num_dst) + dst[0] = translate_dst( t, + &inst->DstReg, + inst->SaturateMode ); + + for (i = 0; i < num_src; i++) + src[i] = translate_src( t, &inst->SrcReg[i] ); + + switch( inst->Opcode ) { + case OPCODE_SWZ: + emit_swz( t, dst[0], &inst->SrcReg[0] ); + return; + + case OPCODE_BGNLOOP: + case OPCODE_CAL: + case OPCODE_ELSE: + case OPCODE_ENDLOOP: + case OPCODE_IF: + debug_assert(num_dst == 0); + ureg_label_insn( ureg, + translate_opcode( inst->Opcode ), + src, num_src, + get_label( t, inst->BranchTarget )); + return; + + case OPCODE_TEX: + case OPCODE_TXB: + case OPCODE_TXD: + case OPCODE_TXL: + case OPCODE_TXP: + src[num_src++] = t->samplers[inst->TexSrcUnit]; + ureg_tex_insn( ureg, + translate_opcode( inst->Opcode ), + dst, num_dst, + translate_texture_target( inst->TexSrcTarget, + inst->TexShadow ), + NULL, 0, + src, num_src ); + return; + + case OPCODE_SCS: + dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XY ); + ureg_insn( ureg, + translate_opcode( inst->Opcode ), + dst, num_dst, + src, num_src ); + break; + + case OPCODE_XPD: + dst[0] = ureg_writemask(dst[0], TGSI_WRITEMASK_XYZ ); + ureg_insn( ureg, + translate_opcode( inst->Opcode ), + dst, num_dst, + src, num_src ); + break; + + case OPCODE_NOISE1: + case OPCODE_NOISE2: + case OPCODE_NOISE3: + case OPCODE_NOISE4: + /* At some point, a motivated person could add a better + * implementation of noise. Currently not even the nvidia + * binary drivers do anything more than this. In any case, the + * place to do this is in the GL state tracker, not the poor + * driver. + */ + ureg_MOV( ureg, dst[0], ureg_imm1f(ureg, 0.5) ); + break; + + case OPCODE_DDY: + emit_ddy( t, dst[0], &inst->SrcReg[0] ); + break; + + default: + ureg_insn( ureg, + translate_opcode( inst->Opcode ), + dst, num_dst, + src, num_src ); + break; + } +} + + +/** + * Emit the TGSI instructions for inverting and adjusting WPOS. + * This code is unavoidable because it also depends on whether + * a FBO is bound (STATE_FB_WPOS_Y_TRANSFORM). + */ +static void +emit_wpos_adjustment( struct st_translate *t, + const struct gl_program *program, + boolean invert, + GLfloat adjX, GLfloat adjY[2]) +{ + struct ureg_program *ureg = t->ureg; + + /* Fragment program uses fragment position input. + * Need to replace instances of INPUT[WPOS] with temp T + * where T = INPUT[WPOS] by y is inverted. + */ + static const gl_state_index wposTransformState[STATE_LENGTH] + = { STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM, 0, 0, 0 }; + + /* XXX: note we are modifying the incoming shader here! Need to + * do this before emitting the constant decls below, or this + * will be missed: + */ + unsigned wposTransConst = _mesa_add_state_reference(program->Parameters, + wposTransformState); + + struct ureg_src wpostrans = ureg_DECL_constant( ureg, wposTransConst ); + struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg ); + struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]]; + + /* First, apply the coordinate shift: */ + if (adjX || adjY[0] || adjY[1]) { + if (adjY[0] != adjY[1]) { + /* Adjust the y coordinate by adjY[1] or adjY[0] respectively + * depending on whether inversion is actually going to be applied + * or not, which is determined by testing against the inversion + * state variable used below, which will be either +1 or -1. + */ + struct ureg_dst adj_temp = ureg_DECL_temporary(ureg); + + ureg_CMP(ureg, adj_temp, + ureg_scalar(wpostrans, invert ? 2 : 0), + ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f), + ureg_imm4f(ureg, adjX, adjY[1], 0.0f, 0.0f)); + ureg_ADD(ureg, wpos_temp, wpos_input, ureg_src(adj_temp)); + } else { + ureg_ADD(ureg, wpos_temp, wpos_input, + ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f)); + } + wpos_input = ureg_src(wpos_temp); + } else { + /* MOV wpos_temp, input[wpos] + */ + ureg_MOV( ureg, wpos_temp, wpos_input ); + } + + /* Now the conditional y flip: STATE_FB_WPOS_Y_TRANSFORM.xy/zw will be + * inversion/identity, or the other way around if we're drawing to an FBO. + */ + if (invert) { + /* MAD wpos_temp.y, wpos_input, wpostrans.xxxx, wpostrans.yyyy + */ + ureg_MAD( ureg, + ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ), + wpos_input, + ureg_scalar(wpostrans, 0), + ureg_scalar(wpostrans, 1)); + } else { + /* MAD wpos_temp.y, wpos_input, wpostrans.zzzz, wpostrans.wwww + */ + ureg_MAD( ureg, + ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ), + wpos_input, + ureg_scalar(wpostrans, 2), + ureg_scalar(wpostrans, 3)); + } + + /* Use wpos_temp as position input from here on: + */ + t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp); +} + + +/** + * Emit fragment position/ooordinate code. + */ +static void +emit_wpos(struct st_context *st, + struct st_translate *t, + const struct gl_program *program, + struct ureg_program *ureg) +{ + const struct gl_fragment_program *fp = + (const struct gl_fragment_program *) program; + struct pipe_screen *pscreen = st->pipe->screen; + GLfloat adjX = 0.0f; + GLfloat adjY[2] = { 0.0f, 0.0f }; + boolean invert = FALSE; + + /* Query the pixel center conventions supported by the pipe driver and set + * adjX, adjY to help out if it cannot handle the requested one internally. + * + * The bias of the y-coordinate depends on whether y-inversion takes place + * (adjY[1]) or not (adjY[0]), which is in turn dependent on whether we are + * drawing to an FBO (causes additional inversion), and whether the the pipe + * driver origin and the requested origin differ (the latter condition is + * stored in the 'invert' variable). + * + * For height = 100 (i = integer, h = half-integer, l = lower, u = upper): + * + * center shift only: + * i -> h: +0.5 + * h -> i: -0.5 + * + * inversion only: + * l,i -> u,i: ( 0.0 + 1.0) * -1 + 100 = 99 + * l,h -> u,h: ( 0.5 + 0.0) * -1 + 100 = 99.5 + * u,i -> l,i: (99.0 + 1.0) * -1 + 100 = 0 + * u,h -> l,h: (99.5 + 0.0) * -1 + 100 = 0.5 + * + * inversion and center shift: + * l,i -> u,h: ( 0.0 + 0.5) * -1 + 100 = 99.5 + * l,h -> u,i: ( 0.5 + 0.5) * -1 + 100 = 99 + * u,i -> l,h: (99.0 + 0.5) * -1 + 100 = 0.5 + * u,h -> l,i: (99.5 + 0.5) * -1 + 100 = 0 + */ + if (fp->OriginUpperLeft) { + /* Fragment shader wants origin in upper-left */ + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) { + /* the driver supports upper-left origin */ + } + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT)) { + /* the driver supports lower-left origin, need to invert Y */ + ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT); + invert = TRUE; + } + else + assert(0); + } + else { + /* Fragment shader wants origin in lower-left */ + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT)) + /* the driver supports lower-left origin */ + ureg_property_fs_coord_origin(ureg, TGSI_FS_COORD_ORIGIN_LOWER_LEFT); + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) + /* the driver supports upper-left origin, need to invert Y */ + invert = TRUE; + else + assert(0); + } + + if (fp->PixelCenterInteger) { + /* Fragment shader wants pixel center integer */ + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) { + /* the driver supports pixel center integer */ + adjY[1] = 1.0f; + ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + } + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) { + /* the driver supports pixel center half integer, need to bias X,Y */ + adjX = -0.5f; + adjY[0] = -0.5f; + adjY[1] = 0.5f; + } + else + assert(0); + } + else { + /* Fragment shader wants pixel center half integer */ + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) { + /* the driver supports pixel center half integer */ + } + else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) { + /* the driver supports pixel center integer, need to bias X,Y */ + adjX = adjY[0] = adjY[1] = 0.5f; + ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + } + else + assert(0); + } + + /* we invert after adjustment so that we avoid the MOV to temporary, + * and reuse the adjustment ADD instead */ + emit_wpos_adjustment(t, program, invert, adjX, adjY); +} + + +/** + * OpenGL's fragment gl_FrontFace input is 1 for front-facing, 0 for back. + * TGSI uses +1 for front, -1 for back. + * This function converts the TGSI value to the GL value. Simply clamping/ + * saturating the value to [0,1] does the job. + */ +static void +emit_face_var( struct st_translate *t, + const struct gl_program *program ) +{ + struct ureg_program *ureg = t->ureg; + struct ureg_dst face_temp = ureg_DECL_temporary( ureg ); + struct ureg_src face_input = t->inputs[t->inputMapping[FRAG_ATTRIB_FACE]]; + + /* MOV_SAT face_temp, input[face] + */ + face_temp = ureg_saturate( face_temp ); + ureg_MOV( ureg, face_temp, face_input ); + + /* Use face_temp as face input from here on: + */ + t->inputs[t->inputMapping[FRAG_ATTRIB_FACE]] = ureg_src(face_temp); +} + + +static void +emit_edgeflags( struct st_translate *t, + const struct gl_program *program ) +{ + struct ureg_program *ureg = t->ureg; + struct ureg_dst edge_dst = t->outputs[t->outputMapping[VERT_RESULT_EDGE]]; + struct ureg_src edge_src = t->inputs[t->inputMapping[VERT_ATTRIB_EDGEFLAG]]; + + ureg_MOV( ureg, edge_dst, edge_src ); +} + + +/** + * Translate Mesa program to TGSI format. + * \param program the program to translate + * \param numInputs number of input registers used + * \param inputMapping maps Mesa fragment program inputs to TGSI generic + * input indexes + * \param inputSemanticName the TGSI_SEMANTIC flag for each input + * \param inputSemanticIndex the semantic index (ex: which texcoord) for + * each input + * \param interpMode the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input + * \param numOutputs number of output registers used + * \param outputMapping maps Mesa fragment program outputs to TGSI + * generic outputs + * \param outputSemanticName the TGSI_SEMANTIC flag for each output + * \param outputSemanticIndex the semantic index (ex: which texcoord) for + * each output + * + * \return PIPE_OK or PIPE_ERROR_OUT_OF_MEMORY + */ +enum pipe_error +st_translate_mesa_program( + struct gl_context *ctx, + uint procType, + struct ureg_program *ureg, + const struct gl_program *program, + GLuint numInputs, + const GLuint inputMapping[], + const ubyte inputSemanticName[], + const ubyte inputSemanticIndex[], + const GLuint interpMode[], + GLuint numOutputs, + const GLuint outputMapping[], + const ubyte outputSemanticName[], + const ubyte outputSemanticIndex[], + boolean passthrough_edgeflags ) +{ + struct st_translate translate, *t; + unsigned i; + enum pipe_error ret = PIPE_OK; + + assert(numInputs <= Elements(t->inputs)); + assert(numOutputs <= Elements(t->outputs)); + + t = &translate; + memset(t, 0, sizeof *t); + + t->procType = procType; + t->inputMapping = inputMapping; + t->outputMapping = outputMapping; + t->ureg = ureg; + t->pointSizeOutIndex = -1; + t->prevInstWrotePointSize = GL_FALSE; + + /*_mesa_print_program(program);*/ + + /* + * Declare input attributes. + */ + if (procType == TGSI_PROCESSOR_FRAGMENT) { + for (i = 0; i < numInputs; i++) { + if (program->InputFlags[0] & PROG_PARAM_BIT_CYL_WRAP) { + t->inputs[i] = ureg_DECL_fs_input_cyl(ureg, + inputSemanticName[i], + inputSemanticIndex[i], + interpMode[i], + TGSI_CYLINDRICAL_WRAP_X); + } + else { + t->inputs[i] = ureg_DECL_fs_input(ureg, + inputSemanticName[i], + inputSemanticIndex[i], + interpMode[i]); + } + } + + if (program->InputsRead & FRAG_BIT_WPOS) { + /* Must do this after setting up t->inputs, and before + * emitting constant references, below: + */ + emit_wpos(st_context(ctx), t, program, ureg); + } + + if (program->InputsRead & FRAG_BIT_FACE) { + emit_face_var( t, program ); + } + + /* + * Declare output attributes. + */ + for (i = 0; i < numOutputs; i++) { + switch (outputSemanticName[i]) { + case TGSI_SEMANTIC_POSITION: + t->outputs[i] = ureg_DECL_output( ureg, + TGSI_SEMANTIC_POSITION, /* Z / Depth */ + outputSemanticIndex[i] ); + + t->outputs[i] = ureg_writemask( t->outputs[i], + TGSI_WRITEMASK_Z ); + break; + case TGSI_SEMANTIC_STENCIL: + t->outputs[i] = ureg_DECL_output( ureg, + TGSI_SEMANTIC_STENCIL, /* Stencil */ + outputSemanticIndex[i] ); + t->outputs[i] = ureg_writemask( t->outputs[i], + TGSI_WRITEMASK_Y ); + break; + case TGSI_SEMANTIC_COLOR: + t->outputs[i] = ureg_DECL_output( ureg, + TGSI_SEMANTIC_COLOR, + outputSemanticIndex[i] ); + break; + default: + debug_assert(0); + return 0; + } + } + } + else if (procType == TGSI_PROCESSOR_GEOMETRY) { + for (i = 0; i < numInputs; i++) { + t->inputs[i] = ureg_DECL_gs_input(ureg, + i, + inputSemanticName[i], + inputSemanticIndex[i]); + } + + for (i = 0; i < numOutputs; i++) { + t->outputs[i] = ureg_DECL_output( ureg, + outputSemanticName[i], + outputSemanticIndex[i] ); + } + } + else { + assert(procType == TGSI_PROCESSOR_VERTEX); + + for (i = 0; i < numInputs; i++) { + t->inputs[i] = ureg_DECL_vs_input(ureg, i); + } + + for (i = 0; i < numOutputs; i++) { + t->outputs[i] = ureg_DECL_output( ureg, + outputSemanticName[i], + outputSemanticIndex[i] ); + if ((outputSemanticName[i] == TGSI_SEMANTIC_PSIZE) && program->Id) { + /* Writing to the point size result register requires special + * handling to implement clamping. + */ + static const gl_state_index pointSizeClampState[STATE_LENGTH] + = { STATE_INTERNAL, STATE_POINT_SIZE_IMPL_CLAMP, 0, 0, 0 }; + /* XXX: note we are modifying the incoming shader here! Need to + * do this before emitting the constant decls below, or this + * will be missed: + */ + unsigned pointSizeClampConst = + _mesa_add_state_reference(program->Parameters, + pointSizeClampState); + struct ureg_dst psizregtemp = ureg_DECL_temporary( ureg ); + t->pointSizeConst = ureg_DECL_constant( ureg, pointSizeClampConst ); + t->pointSizeResult = t->outputs[i]; + t->pointSizeOutIndex = i; + t->outputs[i] = psizregtemp; + } + } + if (passthrough_edgeflags) + emit_edgeflags( t, program ); + } + + /* Declare address register. + */ + if (program->NumAddressRegs > 0) { + debug_assert( program->NumAddressRegs == 1 ); + t->address[0] = ureg_DECL_address( ureg ); + } + + /* Declare misc input registers + */ + { + GLbitfield sysInputs = program->SystemValuesRead; + unsigned numSys = 0; + for (i = 0; sysInputs; i++) { + if (sysInputs & (1 << i)) { + unsigned semName = mesa_sysval_to_semantic[i]; + t->systemValues[i] = ureg_DECL_system_value(ureg, numSys, semName, 0); + numSys++; + sysInputs &= ~(1 << i); + } + } + } + + if (program->IndirectRegisterFiles & (1 << PROGRAM_TEMPORARY)) { + /* If temps are accessed with indirect addressing, declare temporaries + * in sequential order. Else, we declare them on demand elsewhere. + */ + for (i = 0; i < program->NumTemporaries; i++) { + /* XXX use TGSI_FILE_TEMPORARY_ARRAY when it's supported by ureg */ + t->temps[i] = ureg_DECL_temporary( t->ureg ); + } + } + + /* Emit constants and immediates. Mesa uses a single index space + * for these, so we put all the translated regs in t->constants. + */ + if (program->Parameters) { + t->constants = CALLOC( program->Parameters->NumParameters, + sizeof t->constants[0] ); + if (t->constants == NULL) { + ret = PIPE_ERROR_OUT_OF_MEMORY; + goto out; + } + + for (i = 0; i < program->Parameters->NumParameters; i++) { + switch (program->Parameters->Parameters[i].Type) { + case PROGRAM_ENV_PARAM: + case PROGRAM_LOCAL_PARAM: + case PROGRAM_STATE_VAR: + case PROGRAM_NAMED_PARAM: + case PROGRAM_UNIFORM: + t->constants[i] = ureg_DECL_constant( ureg, i ); + break; + + /* Emit immediates only when there's no indirect addressing of + * the const buffer. + * FIXME: Be smarter and recognize param arrays: + * indirect addressing is only valid within the referenced + * array. + */ + case PROGRAM_CONSTANT: + if (program->IndirectRegisterFiles & PROGRAM_ANY_CONST) + t->constants[i] = ureg_DECL_constant( ureg, i ); + else + t->constants[i] = + ureg_DECL_immediate( ureg, + (const float*) program->Parameters->ParameterValues[i], + 4 ); + break; + default: + break; + } + } + } + + /* texture samplers */ + for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) { + if (program->SamplersUsed & (1 << i)) { + t->samplers[i] = ureg_DECL_sampler( ureg, i ); + } + } + + /* Emit each instruction in turn: + */ + for (i = 0; i < program->NumInstructions; i++) { + set_insn_start( t, ureg_get_instruction_number( ureg )); + compile_instruction( t, &program->Instructions[i] ); + + if (t->prevInstWrotePointSize && program->Id) { + /* The previous instruction wrote to the (fake) vertex point size + * result register. Now we need to clamp that value to the min/max + * point size range, putting the result into the real point size + * register. + * Note that we can't do this easily at the end of program due to + * possible early return. + */ + set_insn_start( t, ureg_get_instruction_number( ureg )); + ureg_MAX( t->ureg, + ureg_writemask(t->outputs[t->pointSizeOutIndex], WRITEMASK_X), + ureg_src(t->outputs[t->pointSizeOutIndex]), + ureg_swizzle(t->pointSizeConst, 1,1,1,1)); + ureg_MIN( t->ureg, ureg_writemask(t->pointSizeResult, WRITEMASK_X), + ureg_src(t->outputs[t->pointSizeOutIndex]), + ureg_swizzle(t->pointSizeConst, 2,2,2,2)); + } + t->prevInstWrotePointSize = GL_FALSE; + } + + /* Fix up all emitted labels: + */ + for (i = 0; i < t->labels_count; i++) { + ureg_fixup_label( ureg, + t->labels[i].token, + t->insn[t->labels[i].branch_target] ); + } + +out: + FREE(t->insn); + FREE(t->labels); + FREE(t->constants); + + if (t->error) { + debug_printf("%s: translate error flag set\n", __FUNCTION__); + } + + return ret; +} + + +/** + * Tokens cannot be free with free otherwise the builtin gallium + * malloc debugging will get confused. + */ +void +st_free_tokens(const struct tgsi_token *tokens) +{ + FREE((void *)tokens); +} diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c index 090e9a4f6..a4f47edfc 100644 --- a/mesalib/src/mesa/state_tracker/st_program.c +++ b/mesalib/src/mesa/state_tracker/st_program.c @@ -1,1205 +1,1205 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
- /*
- * Authors:
- * Keith Whitwell <keith@tungstengraphics.com>
- * Brian Paul
- */
-
-
-#include "main/imports.h"
-#include "main/hash.h"
-#include "main/mfeatures.h"
-#include "main/mtypes.h"
-#include "program/prog_parameter.h"
-#include "program/prog_print.h"
-#include "program/programopt.h"
-
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_shader_tokens.h"
-#include "draw/draw_context.h"
-#include "tgsi/tgsi_dump.h"
-#include "tgsi/tgsi_ureg.h"
-
-#include "st_debug.h"
-#include "st_cb_bitmap.h"
-#include "st_cb_drawpixels.h"
-#include "st_context.h"
-#include "st_program.h"
-#include "st_mesa_to_tgsi.h"
-#include "cso_cache/cso_context.h"
-
-
-
-/**
- * Delete a vertex program variant. Note the caller must unlink
- * the variant from the linked list.
- */
-static void
-delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv)
-{
- if (vpv->driver_shader)
- cso_delete_vertex_shader(st->cso_context, vpv->driver_shader);
-
-#if FEATURE_feedback || FEATURE_rastpos
- if (vpv->draw_shader)
- draw_delete_vertex_shader( st->draw, vpv->draw_shader );
-#endif
-
- if (vpv->tgsi.tokens)
- st_free_tokens(vpv->tgsi.tokens);
-
- FREE( vpv );
-}
-
-
-
-/**
- * Clean out any old compilations:
- */
-void
-st_release_vp_variants( struct st_context *st,
- struct st_vertex_program *stvp )
-{
- struct st_vp_variant *vpv;
-
- for (vpv = stvp->variants; vpv; ) {
- struct st_vp_variant *next = vpv->next;
- delete_vp_variant(st, vpv);
- vpv = next;
- }
-
- stvp->variants = NULL;
-}
-
-
-
-/**
- * Delete a fragment program variant. Note the caller must unlink
- * the variant from the linked list.
- */
-static void
-delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv)
-{
- if (fpv->driver_shader)
- cso_delete_fragment_shader(st->cso_context, fpv->driver_shader);
- if (fpv->parameters)
- _mesa_free_parameter_list(fpv->parameters);
-
- FREE(fpv);
-}
-
-
-/**
- * Free all variants of a fragment program.
- */
-void
-st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp)
-{
- struct st_fp_variant *fpv;
-
- for (fpv = stfp->variants; fpv; ) {
- struct st_fp_variant *next = fpv->next;
- delete_fp_variant(st, fpv);
- fpv = next;
- }
-
- stfp->variants = NULL;
-}
-
-
-/**
- * Delete a geometry program variant. Note the caller must unlink
- * the variant from the linked list.
- */
-static void
-delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv)
-{
- if (gpv->driver_shader)
- cso_delete_geometry_shader(st->cso_context, gpv->driver_shader);
-
- FREE(gpv);
-}
-
-
-/**
- * Free all variants of a geometry program.
- */
-void
-st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp)
-{
- struct st_gp_variant *gpv;
-
- for (gpv = stgp->variants; gpv; ) {
- struct st_gp_variant *next = gpv->next;
- delete_gp_variant(st, gpv);
- gpv = next;
- }
-
- stgp->variants = NULL;
-}
-
-
-
-
-/**
- * Translate a Mesa vertex shader into a TGSI shader.
- * \param outputMapping to map vertex program output registers (VERT_RESULT_x)
- * to TGSI output slots
- * \param tokensOut destination for TGSI tokens
- * \return pointer to cached pipe_shader object.
- */
-void
-st_prepare_vertex_program(struct gl_context *ctx,
- struct st_vertex_program *stvp)
-{
- GLuint attr;
-
- stvp->num_inputs = 0;
- stvp->num_outputs = 0;
-
- if (stvp->Base.IsPositionInvariant)
- _mesa_insert_mvp_code(ctx, &stvp->Base);
-
- if (!stvp->glsl_to_tgsi)
- assert(stvp->Base.Base.NumInstructions > 1);
-
- /*
- * Determine number of inputs, the mappings between VERT_ATTRIB_x
- * and TGSI generic input indexes, plus input attrib semantic info.
- */
- for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
- if (stvp->Base.Base.InputsRead & (1 << attr)) {
- stvp->input_to_index[attr] = stvp->num_inputs;
- stvp->index_to_input[stvp->num_inputs] = attr;
- stvp->num_inputs++;
- }
- }
- /* bit of a hack, presetup potentially unused edgeflag input */
- stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs;
- stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG;
-
- /* Compute mapping of vertex program outputs to slots.
- */
- for (attr = 0; attr < VERT_RESULT_MAX; attr++) {
- if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) {
- stvp->result_to_output[attr] = ~0;
- }
- else {
- unsigned slot = stvp->num_outputs++;
-
- stvp->result_to_output[attr] = slot;
-
- switch (attr) {
- case VERT_RESULT_HPOS:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
- stvp->output_semantic_index[slot] = 0;
- break;
- case VERT_RESULT_COL0:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- stvp->output_semantic_index[slot] = 0;
- break;
- case VERT_RESULT_COL1:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- stvp->output_semantic_index[slot] = 1;
- break;
- case VERT_RESULT_BFC0:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
- stvp->output_semantic_index[slot] = 0;
- break;
- case VERT_RESULT_BFC1:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
- stvp->output_semantic_index[slot] = 1;
- break;
- case VERT_RESULT_FOGC:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG;
- stvp->output_semantic_index[slot] = 0;
- break;
- case VERT_RESULT_PSIZ:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE;
- stvp->output_semantic_index[slot] = 0;
- break;
- case VERT_RESULT_EDGE:
- assert(0);
- break;
-
- case VERT_RESULT_TEX0:
- case VERT_RESULT_TEX1:
- case VERT_RESULT_TEX2:
- case VERT_RESULT_TEX3:
- case VERT_RESULT_TEX4:
- case VERT_RESULT_TEX5:
- case VERT_RESULT_TEX6:
- case VERT_RESULT_TEX7:
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
- stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0;
- break;
-
- case VERT_RESULT_VAR0:
- default:
- assert(attr < VERT_RESULT_MAX);
- stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
- stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 -
- FRAG_ATTRIB_TEX0 +
- attr -
- VERT_RESULT_VAR0);
- break;
- }
- }
- }
- /* similar hack to above, presetup potentially unused edgeflag output */
- stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs;
- stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG;
- stvp->output_semantic_index[stvp->num_outputs] = 0;
-}
-
-
-/**
- * Translate a vertex program to create a new variant.
- */
-static struct st_vp_variant *
-st_translate_vertex_program(struct st_context *st,
- struct st_vertex_program *stvp,
- const struct st_vp_variant_key *key)
-{
- struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant);
- struct pipe_context *pipe = st->pipe;
- struct ureg_program *ureg;
- enum pipe_error error;
- unsigned num_outputs;
-
- st_prepare_vertex_program(st->ctx, stvp);
-
- if (!stvp->glsl_to_tgsi)
- {
- _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT);
- _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING);
- }
-
- ureg = ureg_create( TGSI_PROCESSOR_VERTEX );
- if (ureg == NULL) {
- FREE(vpv);
- return NULL;
- }
-
- vpv->key = *key;
-
- vpv->num_inputs = stvp->num_inputs;
- num_outputs = stvp->num_outputs;
- if (key->passthrough_edgeflags) {
- vpv->num_inputs++;
- num_outputs++;
- }
-
- if (ST_DEBUG & DEBUG_MESA) {
- _mesa_print_program(&stvp->Base.Base);
- _mesa_print_program_parameters(st->ctx, &stvp->Base.Base);
- debug_printf("\n");
- }
-
- if (stvp->glsl_to_tgsi)
- error = st_translate_program(st->ctx,
- TGSI_PROCESSOR_VERTEX,
- ureg,
- stvp->glsl_to_tgsi,
- &stvp->Base.Base,
- /* inputs */
- stvp->num_inputs,
- stvp->input_to_index,
- NULL, /* input semantic name */
- NULL, /* input semantic index */
- NULL, /* interp mode */
- /* outputs */
- stvp->num_outputs,
- stvp->result_to_output,
- stvp->output_semantic_name,
- stvp->output_semantic_index,
- key->passthrough_edgeflags );
- else
- error = st_translate_mesa_program(st->ctx,
- TGSI_PROCESSOR_VERTEX,
- ureg,
- &stvp->Base.Base,
- /* inputs */
- vpv->num_inputs,
- stvp->input_to_index,
- NULL, /* input semantic name */
- NULL, /* input semantic index */
- NULL,
- /* outputs */
- num_outputs,
- stvp->result_to_output,
- stvp->output_semantic_name,
- stvp->output_semantic_index,
- key->passthrough_edgeflags );
-
- if (error)
- goto fail;
-
- vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL );
- if (!vpv->tgsi.tokens)
- goto fail;
-
- ureg_destroy( ureg );
-
- vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi);
-
- if (ST_DEBUG & DEBUG_TGSI) {
- tgsi_dump( vpv->tgsi.tokens, 0 );
- debug_printf("\n");
- }
-
- return vpv;
-
-fail:
- debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__);
- _mesa_print_program(&stvp->Base.Base);
- debug_assert(0);
-
- ureg_destroy( ureg );
- return NULL;
-}
-
-
-/**
- * Find/create a vertex program variant.
- */
-struct st_vp_variant *
-st_get_vp_variant(struct st_context *st,
- struct st_vertex_program *stvp,
- const struct st_vp_variant_key *key)
-{
- struct st_vp_variant *vpv;
-
- /* Search for existing variant */
- for (vpv = stvp->variants; vpv; vpv = vpv->next) {
- if (memcmp(&vpv->key, key, sizeof(*key)) == 0) {
- break;
- }
- }
-
- if (!vpv) {
- /* create now */
- vpv = st_translate_vertex_program(st, stvp, key);
- if (vpv) {
- /* insert into list */
- vpv->next = stvp->variants;
- stvp->variants = vpv;
- }
- }
-
- return vpv;
-}
-
-
-/**
- * Translate a Mesa fragment shader into a TGSI shader using extra info in
- * the key.
- * \return new fragment program variant
- */
-static struct st_fp_variant *
-st_translate_fragment_program(struct st_context *st,
- struct st_fragment_program *stfp,
- const struct st_fp_variant_key *key)
-{
- struct pipe_context *pipe = st->pipe;
- struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant);
- GLboolean deleteFP = GL_FALSE;
-
- if (!variant)
- return NULL;
-
- assert(!(key->bitmap && key->drawpixels));
-
-#if FEATURE_drawpix
- if (key->bitmap) {
- /* glBitmap drawing */
- struct gl_fragment_program *fp; /* we free this temp program below */
-
- st_make_bitmap_fragment_program(st, &stfp->Base,
- &fp, &variant->bitmap_sampler);
-
- variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters);
- stfp = st_fragment_program(fp);
- deleteFP = GL_TRUE;
- }
- else if (key->drawpixels) {
- /* glDrawPixels drawing */
- struct gl_fragment_program *fp; /* we free this temp program below */
-
- if (key->drawpixels_z || key->drawpixels_stencil) {
- fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z,
- key->drawpixels_stencil);
- }
- else {
- /* RGBA */
- st_make_drawpix_fragment_program(st, &stfp->Base, &fp);
- variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters);
- deleteFP = GL_TRUE;
- }
- stfp = st_fragment_program(fp);
- }
-#endif
-
- if (!stfp->tgsi.tokens) {
- /* need to translate Mesa instructions to TGSI now */
- GLuint outputMapping[FRAG_RESULT_MAX];
- GLuint inputMapping[FRAG_ATTRIB_MAX];
- GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */
- GLuint attr;
- const GLbitfield inputsRead = stfp->Base.Base.InputsRead;
- struct ureg_program *ureg;
-
- GLboolean write_all = GL_FALSE;
-
- ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS];
- ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS];
- uint fs_num_inputs = 0;
-
- ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
- ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
- uint fs_num_outputs = 0;
-
- if (!stfp->glsl_to_tgsi)
- _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT);
-
- /*
- * Convert Mesa program inputs to TGSI input register semantics.
- */
- for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) {
- if (inputsRead & (1 << attr)) {
- const GLuint slot = fs_num_inputs++;
-
- inputMapping[attr] = slot;
-
- switch (attr) {
- case FRAG_ATTRIB_WPOS:
- input_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
- input_semantic_index[slot] = 0;
- interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
- break;
- case FRAG_ATTRIB_COL0:
- input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- input_semantic_index[slot] = 0;
- interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
- break;
- case FRAG_ATTRIB_COL1:
- input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- input_semantic_index[slot] = 1;
- interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
- break;
- case FRAG_ATTRIB_FOGC:
- input_semantic_name[slot] = TGSI_SEMANTIC_FOG;
- input_semantic_index[slot] = 0;
- interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
- break;
- case FRAG_ATTRIB_FACE:
- input_semantic_name[slot] = TGSI_SEMANTIC_FACE;
- input_semantic_index[slot] = 0;
- interpMode[slot] = TGSI_INTERPOLATE_CONSTANT;
- break;
- /* In most cases, there is nothing special about these
- * inputs, so adopt a convention to use the generic
- * semantic name and the mesa FRAG_ATTRIB_ number as the
- * index.
- *
- * All that is required is that the vertex shader labels
- * its own outputs similarly, and that the vertex shader
- * generates at least every output required by the
- * fragment shader plus fixed-function hardware (such as
- * BFC).
- *
- * There is no requirement that semantic indexes start at
- * zero or be restricted to a particular range -- nobody
- * should be building tables based on semantic index.
- */
- case FRAG_ATTRIB_PNTC:
- case FRAG_ATTRIB_TEX0:
- case FRAG_ATTRIB_TEX1:
- case FRAG_ATTRIB_TEX2:
- case FRAG_ATTRIB_TEX3:
- case FRAG_ATTRIB_TEX4:
- case FRAG_ATTRIB_TEX5:
- case FRAG_ATTRIB_TEX6:
- case FRAG_ATTRIB_TEX7:
- case FRAG_ATTRIB_VAR0:
- default:
- /* Actually, let's try and zero-base this just for
- * readability of the generated TGSI.
- */
- assert(attr >= FRAG_ATTRIB_TEX0);
- input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0);
- input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
- if (attr == FRAG_ATTRIB_PNTC)
- interpMode[slot] = TGSI_INTERPOLATE_LINEAR;
- else
- interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE;
- break;
- }
- }
- else {
- inputMapping[attr] = -1;
- }
- }
-
- /*
- * Semantics and mapping for outputs
- */
- {
- uint numColors = 0;
- GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten;
-
- /* if z is written, emit that first */
- if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
- fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION;
- fs_output_semantic_index[fs_num_outputs] = 0;
- outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs;
- fs_num_outputs++;
- outputsWritten &= ~(1 << FRAG_RESULT_DEPTH);
- }
-
- if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) {
- fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL;
- fs_output_semantic_index[fs_num_outputs] = 0;
- outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs;
- fs_num_outputs++;
- outputsWritten &= ~(1 << FRAG_RESULT_STENCIL);
- }
-
- /* handle remaning outputs (color) */
- for (attr = 0; attr < FRAG_RESULT_MAX; attr++) {
- if (outputsWritten & BITFIELD64_BIT(attr)) {
- switch (attr) {
- case FRAG_RESULT_DEPTH:
- case FRAG_RESULT_STENCIL:
- /* handled above */
- assert(0);
- break;
- case FRAG_RESULT_COLOR:
- write_all = GL_TRUE; /* fallthrough */
- default:
- assert(attr == FRAG_RESULT_COLOR ||
- (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX));
- fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR;
- fs_output_semantic_index[fs_num_outputs] = numColors;
- outputMapping[attr] = fs_num_outputs;
- numColors++;
- break;
- }
-
- fs_num_outputs++;
- }
- }
- }
-
- ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
- if (ureg == NULL)
- return NULL;
-
- if (ST_DEBUG & DEBUG_MESA) {
- _mesa_print_program(&stfp->Base.Base);
- _mesa_print_program_parameters(st->ctx, &stfp->Base.Base);
- debug_printf("\n");
- }
- if (write_all == GL_TRUE)
- ureg_property_fs_color0_writes_all_cbufs(ureg, 1);
-
- if (stfp->glsl_to_tgsi)
- st_translate_program(st->ctx,
- TGSI_PROCESSOR_FRAGMENT,
- ureg,
- stfp->glsl_to_tgsi,
- &stfp->Base.Base,
- /* inputs */
- fs_num_inputs,
- inputMapping,
- input_semantic_name,
- input_semantic_index,
- interpMode,
- /* outputs */
- fs_num_outputs,
- outputMapping,
- fs_output_semantic_name,
- fs_output_semantic_index, FALSE );
- else
- st_translate_mesa_program(st->ctx,
- TGSI_PROCESSOR_FRAGMENT,
- ureg,
- &stfp->Base.Base,
- /* inputs */
- fs_num_inputs,
- inputMapping,
- input_semantic_name,
- input_semantic_index,
- interpMode,
- /* outputs */
- fs_num_outputs,
- outputMapping,
- fs_output_semantic_name,
- fs_output_semantic_index, FALSE );
-
- stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL );
- ureg_destroy( ureg );
- }
-
- /* fill in variant */
- variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi);
- variant->key = *key;
-
- if (ST_DEBUG & DEBUG_TGSI) {
- tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ );
- debug_printf("\n");
- }
-
- if (deleteFP) {
- /* Free the temporary program made above */
- struct gl_fragment_program *fp = &stfp->Base;
- _mesa_reference_fragprog(st->ctx, &fp, NULL);
- }
-
- return variant;
-}
-
-
-/**
- * Translate fragment program if needed.
- */
-struct st_fp_variant *
-st_get_fp_variant(struct st_context *st,
- struct st_fragment_program *stfp,
- const struct st_fp_variant_key *key)
-{
- struct st_fp_variant *fpv;
-
- /* Search for existing variant */
- for (fpv = stfp->variants; fpv; fpv = fpv->next) {
- if (memcmp(&fpv->key, key, sizeof(*key)) == 0) {
- break;
- }
- }
-
- if (!fpv) {
- /* create new */
- fpv = st_translate_fragment_program(st, stfp, key);
- if (fpv) {
- /* insert into list */
- fpv->next = stfp->variants;
- stfp->variants = fpv;
- }
- }
-
- return fpv;
-}
-
-
-/**
- * Translate a geometry program to create a new variant.
- */
-static struct st_gp_variant *
-st_translate_geometry_program(struct st_context *st,
- struct st_geometry_program *stgp,
- const struct st_gp_variant_key *key)
-{
- GLuint inputMapping[GEOM_ATTRIB_MAX];
- GLuint outputMapping[GEOM_RESULT_MAX];
- struct pipe_context *pipe = st->pipe;
- GLuint attr;
- const GLbitfield inputsRead = stgp->Base.Base.InputsRead;
- GLuint vslot = 0;
- GLuint num_generic = 0;
-
- uint gs_num_inputs = 0;
- uint gs_builtin_inputs = 0;
- uint gs_array_offset = 0;
-
- ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS];
- ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS];
- uint gs_num_outputs = 0;
-
- GLint i;
- GLuint maxSlot = 0;
- struct ureg_program *ureg;
-
- struct st_gp_variant *gpv;
-
- gpv = CALLOC_STRUCT(st_gp_variant);
- if (!gpv)
- return NULL;
-
- _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT);
- _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING);
-
- ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY );
- if (ureg == NULL) {
- FREE(gpv);
- return NULL;
- }
-
- /* which vertex output goes to the first geometry input */
- vslot = 0;
-
- memset(inputMapping, 0, sizeof(inputMapping));
- memset(outputMapping, 0, sizeof(outputMapping));
-
- /*
- * Convert Mesa program inputs to TGSI input register semantics.
- */
- for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) {
- if (inputsRead & (1 << attr)) {
- const GLuint slot = gs_num_inputs;
-
- gs_num_inputs++;
-
- inputMapping[attr] = slot;
-
- stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs;
- stgp->input_to_index[attr] = vslot;
- stgp->index_to_input[vslot] = attr;
- ++vslot;
-
- if (attr != GEOM_ATTRIB_PRIMITIVE_ID) {
- gs_array_offset += 2;
- } else
- ++gs_builtin_inputs;
-
-#if 0
- debug_printf("input map at %d = %d\n",
- slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]);
-#endif
-
- switch (attr) {
- case GEOM_ATTRIB_PRIMITIVE_ID:
- stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID;
- stgp->input_semantic_index[slot] = 0;
- break;
- case GEOM_ATTRIB_POSITION:
- stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
- stgp->input_semantic_index[slot] = 0;
- break;
- case GEOM_ATTRIB_COLOR0:
- stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- stgp->input_semantic_index[slot] = 0;
- break;
- case GEOM_ATTRIB_COLOR1:
- stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- stgp->input_semantic_index[slot] = 1;
- break;
- case GEOM_ATTRIB_FOG_FRAG_COORD:
- stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG;
- stgp->input_semantic_index[slot] = 0;
- break;
- case GEOM_ATTRIB_TEX_COORD:
- stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
- stgp->input_semantic_index[slot] = num_generic++;
- break;
- case GEOM_ATTRIB_VAR0:
- /* fall-through */
- default:
- stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
- stgp->input_semantic_index[slot] = num_generic++;
- }
- }
- }
-
- /* initialize output semantics to defaults */
- for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) {
- gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC;
- gs_output_semantic_index[i] = 0;
- }
-
- num_generic = 0;
- /*
- * Determine number of outputs, the (default) output register
- * mapping and the semantic information for each output.
- */
- for (attr = 0; attr < GEOM_RESULT_MAX; attr++) {
- if (stgp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) {
- GLuint slot;
-
- slot = gs_num_outputs;
- gs_num_outputs++;
- outputMapping[attr] = slot;
-
- switch (attr) {
- case GEOM_RESULT_POS:
- assert(slot == 0);
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION;
- gs_output_semantic_index[slot] = 0;
- break;
- case GEOM_RESULT_COL0:
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- gs_output_semantic_index[slot] = 0;
- break;
- case GEOM_RESULT_COL1:
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR;
- gs_output_semantic_index[slot] = 1;
- break;
- case GEOM_RESULT_SCOL0:
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
- gs_output_semantic_index[slot] = 0;
- break;
- case GEOM_RESULT_SCOL1:
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR;
- gs_output_semantic_index[slot] = 1;
- break;
- case GEOM_RESULT_FOGC:
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG;
- gs_output_semantic_index[slot] = 0;
- break;
- case GEOM_RESULT_PSIZ:
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE;
- gs_output_semantic_index[slot] = 0;
- break;
- case GEOM_RESULT_TEX0:
- case GEOM_RESULT_TEX1:
- case GEOM_RESULT_TEX2:
- case GEOM_RESULT_TEX3:
- case GEOM_RESULT_TEX4:
- case GEOM_RESULT_TEX5:
- case GEOM_RESULT_TEX6:
- case GEOM_RESULT_TEX7:
- /* fall-through */
- case GEOM_RESULT_VAR0:
- /* fall-through */
- default:
- assert(slot < Elements(gs_output_semantic_name));
- /* use default semantic info */
- gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC;
- gs_output_semantic_index[slot] = num_generic++;
- }
- }
- }
-
- assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION);
-
- /* find max output slot referenced to compute gs_num_outputs */
- for (attr = 0; attr < GEOM_RESULT_MAX; attr++) {
- if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot)
- maxSlot = outputMapping[attr];
- }
- gs_num_outputs = maxSlot + 1;
-
-#if 0 /* debug */
- {
- GLuint i;
- printf("outputMapping? %d\n", outputMapping ? 1 : 0);
- if (outputMapping) {
- printf("attr -> slot\n");
- for (i = 0; i < 16; i++) {
- printf(" %2d %3d\n", i, outputMapping[i]);
- }
- }
- printf("slot sem_name sem_index\n");
- for (i = 0; i < gs_num_outputs; i++) {
- printf(" %2d %d %d\n",
- i,
- gs_output_semantic_name[i],
- gs_output_semantic_index[i]);
- }
- }
-#endif
-
- /* free old shader state, if any */
- if (stgp->tgsi.tokens) {
- st_free_tokens(stgp->tgsi.tokens);
- stgp->tgsi.tokens = NULL;
- }
-
- ureg_property_gs_input_prim(ureg, stgp->Base.InputType);
- ureg_property_gs_output_prim(ureg, stgp->Base.OutputType);
- ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut);
-
- st_translate_mesa_program(st->ctx,
- TGSI_PROCESSOR_GEOMETRY,
- ureg,
- &stgp->Base.Base,
- /* inputs */
- gs_num_inputs,
- inputMapping,
- stgp->input_semantic_name,
- stgp->input_semantic_index,
- NULL,
- /* outputs */
- gs_num_outputs,
- outputMapping,
- gs_output_semantic_name,
- gs_output_semantic_index,
- FALSE);
-
- stgp->num_inputs = gs_num_inputs;
- stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL );
- ureg_destroy( ureg );
-
- /* fill in new variant */
- gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi);
- gpv->key = *key;
-
- if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) {
- _mesa_print_program(&stgp->Base.Base);
- debug_printf("\n");
- }
-
- if (ST_DEBUG & DEBUG_TGSI) {
- tgsi_dump(stgp->tgsi.tokens, 0);
- debug_printf("\n");
- }
-
- return gpv;
-}
-
-
-/**
- * Get/create geometry program variant.
- */
-struct st_gp_variant *
-st_get_gp_variant(struct st_context *st,
- struct st_geometry_program *stgp,
- const struct st_gp_variant_key *key)
-{
- struct st_gp_variant *gpv;
-
- /* Search for existing variant */
- for (gpv = stgp->variants; gpv; gpv = gpv->next) {
- if (memcmp(&gpv->key, key, sizeof(*key)) == 0) {
- break;
- }
- }
-
- if (!gpv) {
- /* create new */
- gpv = st_translate_geometry_program(st, stgp, key);
- if (gpv) {
- /* insert into list */
- gpv->next = stgp->variants;
- stgp->variants = gpv;
- }
- }
-
- return gpv;
-}
-
-
-
-
-/**
- * Debug- print current shader text
- */
-void
-st_print_shaders(struct gl_context *ctx)
-{
- struct gl_shader_program *shProg[3] = {
- ctx->Shader.CurrentVertexProgram,
- ctx->Shader.CurrentGeometryProgram,
- ctx->Shader.CurrentFragmentProgram,
- };
- unsigned j;
-
- for (j = 0; j < 3; j++) {
- unsigned i;
-
- if (shProg[j] == NULL)
- continue;
-
- for (i = 0; i < shProg[j]->NumShaders; i++) {
- struct gl_shader *sh;
-
- switch (shProg[j]->Shaders[i]->Type) {
- case GL_VERTEX_SHADER:
- sh = (i != 0) ? NULL : shProg[j]->Shaders[i];
- break;
- case GL_GEOMETRY_SHADER_ARB:
- sh = (i != 1) ? NULL : shProg[j]->Shaders[i];
- break;
- case GL_FRAGMENT_SHADER:
- sh = (i != 2) ? NULL : shProg[j]->Shaders[i];
- break;
- default:
- assert(0);
- sh = NULL;
- break;
- }
-
- if (sh != NULL) {
- printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders);
- printf("%s\n", sh->Source);
- }
- }
- }
-}
-
-
-/**
- * Vert/Geom/Frag programs have per-context variants. Free all the
- * variants attached to the given program which match the given context.
- */
-static void
-destroy_program_variants(struct st_context *st, struct gl_program *program)
-{
- if (!program)
- return;
-
- switch (program->Target) {
- case GL_VERTEX_PROGRAM_ARB:
- {
- struct st_vertex_program *stvp = (struct st_vertex_program *) program;
- struct st_vp_variant *vpv, **prevPtr = &stvp->variants;
-
- for (vpv = stvp->variants; vpv; ) {
- struct st_vp_variant *next = vpv->next;
- if (vpv->key.st == st) {
- /* unlink from list */
- *prevPtr = next;
- /* destroy this variant */
- delete_vp_variant(st, vpv);
- }
- else {
- prevPtr = &vpv->next;
- }
- vpv = next;
- }
- }
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- {
- struct st_fragment_program *stfp =
- (struct st_fragment_program *) program;
- struct st_fp_variant *fpv, **prevPtr = &stfp->variants;
-
- for (fpv = stfp->variants; fpv; ) {
- struct st_fp_variant *next = fpv->next;
- if (fpv->key.st == st) {
- /* unlink from list */
- *prevPtr = next;
- /* destroy this variant */
- delete_fp_variant(st, fpv);
- }
- else {
- prevPtr = &fpv->next;
- }
- fpv = next;
- }
- }
- break;
- case MESA_GEOMETRY_PROGRAM:
- {
- struct st_geometry_program *stgp =
- (struct st_geometry_program *) program;
- struct st_gp_variant *gpv, **prevPtr = &stgp->variants;
-
- for (gpv = stgp->variants; gpv; ) {
- struct st_gp_variant *next = gpv->next;
- if (gpv->key.st == st) {
- /* unlink from list */
- *prevPtr = next;
- /* destroy this variant */
- delete_gp_variant(st, gpv);
- }
- else {
- prevPtr = &gpv->next;
- }
- gpv = next;
- }
- }
- break;
- default:
- _mesa_problem(NULL, "Unexpected program target 0x%x in "
- "destroy_program_variants_cb()", program->Target);
- }
-}
-
-
-/**
- * Callback for _mesa_HashWalk. Free all the shader's program variants
- * which match the given context.
- */
-static void
-destroy_shader_program_variants_cb(GLuint key, void *data, void *userData)
-{
- struct st_context *st = (struct st_context *) userData;
- struct gl_shader *shader = (struct gl_shader *) data;
-
- switch (shader->Type) {
- case GL_SHADER_PROGRAM_MESA:
- {
- struct gl_shader_program *shProg = (struct gl_shader_program *) data;
- GLuint i;
-
- for (i = 0; i < shProg->NumShaders; i++) {
- destroy_program_variants(st, shProg->Shaders[i]->Program);
- }
-
- destroy_program_variants(st, (struct gl_program *)
- shProg->VertexProgram);
- destroy_program_variants(st, (struct gl_program *)
- shProg->FragmentProgram);
- destroy_program_variants(st, (struct gl_program *)
- shProg->GeometryProgram);
- }
- break;
- case GL_VERTEX_SHADER:
- case GL_FRAGMENT_SHADER:
- case GL_GEOMETRY_SHADER:
- {
- destroy_program_variants(st, shader->Program);
- }
- break;
- default:
- assert(0);
- }
-}
-
-
-/**
- * Callback for _mesa_HashWalk. Free all the program variants which match
- * the given context.
- */
-static void
-destroy_program_variants_cb(GLuint key, void *data, void *userData)
-{
- struct st_context *st = (struct st_context *) userData;
- struct gl_program *program = (struct gl_program *) data;
- destroy_program_variants(st, program);
-}
-
-
-/**
- * Walk over all shaders and programs to delete any variants which
- * belong to the given context.
- * This is called during context tear-down.
- */
-void
-st_destroy_program_variants(struct st_context *st)
-{
- /* ARB vert/frag program */
- _mesa_HashWalk(st->ctx->Shared->Programs,
- destroy_program_variants_cb, st);
-
- /* GLSL vert/frag/geom shaders */
- _mesa_HashWalk(st->ctx->Shared->ShaderObjects,
- destroy_shader_program_variants_cb, st);
-}
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + /* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * Brian Paul + */ + + +#include "main/imports.h" +#include "main/hash.h" +#include "main/mfeatures.h" +#include "main/mtypes.h" +#include "program/prog_parameter.h" +#include "program/prog_print.h" +#include "program/programopt.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "draw/draw_context.h" +#include "tgsi/tgsi_dump.h" +#include "tgsi/tgsi_ureg.h" + +#include "st_debug.h" +#include "st_cb_bitmap.h" +#include "st_cb_drawpixels.h" +#include "st_context.h" +#include "st_program.h" +#include "st_mesa_to_tgsi.h" +#include "cso_cache/cso_context.h" + + + +/** + * Delete a vertex program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_vp_variant(struct st_context *st, struct st_vp_variant *vpv) +{ + if (vpv->driver_shader) + cso_delete_vertex_shader(st->cso_context, vpv->driver_shader); + +#if FEATURE_feedback || FEATURE_rastpos + if (vpv->draw_shader) + draw_delete_vertex_shader( st->draw, vpv->draw_shader ); +#endif + + if (vpv->tgsi.tokens) + st_free_tokens(vpv->tgsi.tokens); + + FREE( vpv ); +} + + + +/** + * Clean out any old compilations: + */ +void +st_release_vp_variants( struct st_context *st, + struct st_vertex_program *stvp ) +{ + struct st_vp_variant *vpv; + + for (vpv = stvp->variants; vpv; ) { + struct st_vp_variant *next = vpv->next; + delete_vp_variant(st, vpv); + vpv = next; + } + + stvp->variants = NULL; +} + + + +/** + * Delete a fragment program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_fp_variant(struct st_context *st, struct st_fp_variant *fpv) +{ + if (fpv->driver_shader) + cso_delete_fragment_shader(st->cso_context, fpv->driver_shader); + if (fpv->parameters) + _mesa_free_parameter_list(fpv->parameters); + + FREE(fpv); +} + + +/** + * Free all variants of a fragment program. + */ +void +st_release_fp_variants(struct st_context *st, struct st_fragment_program *stfp) +{ + struct st_fp_variant *fpv; + + for (fpv = stfp->variants; fpv; ) { + struct st_fp_variant *next = fpv->next; + delete_fp_variant(st, fpv); + fpv = next; + } + + stfp->variants = NULL; +} + + +/** + * Delete a geometry program variant. Note the caller must unlink + * the variant from the linked list. + */ +static void +delete_gp_variant(struct st_context *st, struct st_gp_variant *gpv) +{ + if (gpv->driver_shader) + cso_delete_geometry_shader(st->cso_context, gpv->driver_shader); + + FREE(gpv); +} + + +/** + * Free all variants of a geometry program. + */ +void +st_release_gp_variants(struct st_context *st, struct st_geometry_program *stgp) +{ + struct st_gp_variant *gpv; + + for (gpv = stgp->variants; gpv; ) { + struct st_gp_variant *next = gpv->next; + delete_gp_variant(st, gpv); + gpv = next; + } + + stgp->variants = NULL; +} + + + + +/** + * Translate a Mesa vertex shader into a TGSI shader. + * \param outputMapping to map vertex program output registers (VERT_RESULT_x) + * to TGSI output slots + * \param tokensOut destination for TGSI tokens + * \return pointer to cached pipe_shader object. + */ +void +st_prepare_vertex_program(struct gl_context *ctx, + struct st_vertex_program *stvp) +{ + GLuint attr; + + stvp->num_inputs = 0; + stvp->num_outputs = 0; + + if (stvp->Base.IsPositionInvariant) + _mesa_insert_mvp_code(ctx, &stvp->Base); + + if (!stvp->glsl_to_tgsi) + assert(stvp->Base.Base.NumInstructions > 1); + + /* + * Determine number of inputs, the mappings between VERT_ATTRIB_x + * and TGSI generic input indexes, plus input attrib semantic info. + */ + for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { + if (stvp->Base.Base.InputsRead & (1 << attr)) { + stvp->input_to_index[attr] = stvp->num_inputs; + stvp->index_to_input[stvp->num_inputs] = attr; + stvp->num_inputs++; + } + } + /* bit of a hack, presetup potentially unused edgeflag input */ + stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; + stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; + + /* Compute mapping of vertex program outputs to slots. + */ + for (attr = 0; attr < VERT_RESULT_MAX; attr++) { + if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { + stvp->result_to_output[attr] = ~0; + } + else { + unsigned slot = stvp->num_outputs++; + + stvp->result_to_output[attr] = slot; + + switch (attr) { + case VERT_RESULT_HPOS: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL0: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_COL1: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stvp->output_semantic_index[slot] = 1; + break; + case VERT_RESULT_BFC0: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_BFC1: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + stvp->output_semantic_index[slot] = 1; + break; + case VERT_RESULT_FOGC: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_PSIZ: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + stvp->output_semantic_index[slot] = 0; + break; + case VERT_RESULT_EDGE: + assert(0); + break; + + case VERT_RESULT_TEX0: + case VERT_RESULT_TEX1: + case VERT_RESULT_TEX2: + case VERT_RESULT_TEX3: + case VERT_RESULT_TEX4: + case VERT_RESULT_TEX5: + case VERT_RESULT_TEX6: + case VERT_RESULT_TEX7: + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stvp->output_semantic_index[slot] = attr - VERT_RESULT_TEX0; + break; + + case VERT_RESULT_VAR0: + default: + assert(attr < VERT_RESULT_MAX); + stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stvp->output_semantic_index[slot] = (FRAG_ATTRIB_VAR0 - + FRAG_ATTRIB_TEX0 + + attr - + VERT_RESULT_VAR0); + break; + } + } + } + /* similar hack to above, presetup potentially unused edgeflag output */ + stvp->result_to_output[VERT_RESULT_EDGE] = stvp->num_outputs; + stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; + stvp->output_semantic_index[stvp->num_outputs] = 0; +} + + +/** + * Translate a vertex program to create a new variant. + */ +static struct st_vp_variant * +st_translate_vertex_program(struct st_context *st, + struct st_vertex_program *stvp, + const struct st_vp_variant_key *key) +{ + struct st_vp_variant *vpv = CALLOC_STRUCT(st_vp_variant); + struct pipe_context *pipe = st->pipe; + struct ureg_program *ureg; + enum pipe_error error; + unsigned num_outputs; + + st_prepare_vertex_program(st->ctx, stvp); + + if (!stvp->glsl_to_tgsi) + { + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stvp->Base.Base, PROGRAM_VARYING); + } + + ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); + if (ureg == NULL) { + FREE(vpv); + return NULL; + } + + vpv->key = *key; + + vpv->num_inputs = stvp->num_inputs; + num_outputs = stvp->num_outputs; + if (key->passthrough_edgeflags) { + vpv->num_inputs++; + num_outputs++; + } + + if (ST_DEBUG & DEBUG_MESA) { + _mesa_print_program(&stvp->Base.Base); + _mesa_print_program_parameters(st->ctx, &stvp->Base.Base); + debug_printf("\n"); + } + + if (stvp->glsl_to_tgsi) + error = st_translate_program(st->ctx, + TGSI_PROCESSOR_VERTEX, + ureg, + stvp->glsl_to_tgsi, + &stvp->Base.Base, + /* inputs */ + stvp->num_inputs, + stvp->input_to_index, + NULL, /* input semantic name */ + NULL, /* input semantic index */ + NULL, /* interp mode */ + /* outputs */ + stvp->num_outputs, + stvp->result_to_output, + stvp->output_semantic_name, + stvp->output_semantic_index, + key->passthrough_edgeflags ); + else + error = st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_VERTEX, + ureg, + &stvp->Base.Base, + /* inputs */ + vpv->num_inputs, + stvp->input_to_index, + NULL, /* input semantic name */ + NULL, /* input semantic index */ + NULL, + /* outputs */ + num_outputs, + stvp->result_to_output, + stvp->output_semantic_name, + stvp->output_semantic_index, + key->passthrough_edgeflags ); + + if (error) + goto fail; + + vpv->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + if (!vpv->tgsi.tokens) + goto fail; + + ureg_destroy( ureg ); + + vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump( vpv->tgsi.tokens, 0 ); + debug_printf("\n"); + } + + return vpv; + +fail: + debug_printf("%s: failed to translate Mesa program:\n", __FUNCTION__); + _mesa_print_program(&stvp->Base.Base); + debug_assert(0); + + ureg_destroy( ureg ); + return NULL; +} + + +/** + * Find/create a vertex program variant. + */ +struct st_vp_variant * +st_get_vp_variant(struct st_context *st, + struct st_vertex_program *stvp, + const struct st_vp_variant_key *key) +{ + struct st_vp_variant *vpv; + + /* Search for existing variant */ + for (vpv = stvp->variants; vpv; vpv = vpv->next) { + if (memcmp(&vpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!vpv) { + /* create now */ + vpv = st_translate_vertex_program(st, stvp, key); + if (vpv) { + /* insert into list */ + vpv->next = stvp->variants; + stvp->variants = vpv; + } + } + + return vpv; +} + + +/** + * Translate a Mesa fragment shader into a TGSI shader using extra info in + * the key. + * \return new fragment program variant + */ +static struct st_fp_variant * +st_translate_fragment_program(struct st_context *st, + struct st_fragment_program *stfp, + const struct st_fp_variant_key *key) +{ + struct pipe_context *pipe = st->pipe; + struct st_fp_variant *variant = CALLOC_STRUCT(st_fp_variant); + GLboolean deleteFP = GL_FALSE; + + if (!variant) + return NULL; + + assert(!(key->bitmap && key->drawpixels)); + +#if FEATURE_drawpix + if (key->bitmap) { + /* glBitmap drawing */ + struct gl_fragment_program *fp; /* we free this temp program below */ + + st_make_bitmap_fragment_program(st, &stfp->Base, + &fp, &variant->bitmap_sampler); + + variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); + stfp = st_fragment_program(fp); + deleteFP = GL_TRUE; + } + else if (key->drawpixels) { + /* glDrawPixels drawing */ + struct gl_fragment_program *fp; /* we free this temp program below */ + + if (key->drawpixels_z || key->drawpixels_stencil) { + fp = st_make_drawpix_z_stencil_program(st, key->drawpixels_z, + key->drawpixels_stencil); + } + else { + /* RGBA */ + st_make_drawpix_fragment_program(st, &stfp->Base, &fp); + variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters); + deleteFP = GL_TRUE; + } + stfp = st_fragment_program(fp); + } +#endif + + if (!stfp->tgsi.tokens) { + /* need to translate Mesa instructions to TGSI now */ + GLuint outputMapping[FRAG_RESULT_MAX]; + GLuint inputMapping[FRAG_ATTRIB_MAX]; + GLuint interpMode[PIPE_MAX_SHADER_INPUTS]; /* XXX size? */ + GLuint attr; + const GLbitfield inputsRead = stfp->Base.Base.InputsRead; + struct ureg_program *ureg; + + GLboolean write_all = GL_FALSE; + + ubyte input_semantic_name[PIPE_MAX_SHADER_INPUTS]; + ubyte input_semantic_index[PIPE_MAX_SHADER_INPUTS]; + uint fs_num_inputs = 0; + + ubyte fs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte fs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint fs_num_outputs = 0; + + if (!stfp->glsl_to_tgsi) + _mesa_remove_output_reads(&stfp->Base.Base, PROGRAM_OUTPUT); + + /* + * Convert Mesa program inputs to TGSI input register semantics. + */ + for (attr = 0; attr < FRAG_ATTRIB_MAX; attr++) { + if (inputsRead & (1 << attr)) { + const GLuint slot = fs_num_inputs++; + + inputMapping[attr] = slot; + + switch (attr) { + case FRAG_ATTRIB_WPOS: + input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL0: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_COL1: + input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + input_semantic_index[slot] = 1; + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + break; + case FRAG_ATTRIB_FOGC: + input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + case FRAG_ATTRIB_FACE: + input_semantic_name[slot] = TGSI_SEMANTIC_FACE; + input_semantic_index[slot] = 0; + interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; + break; + /* In most cases, there is nothing special about these + * inputs, so adopt a convention to use the generic + * semantic name and the mesa FRAG_ATTRIB_ number as the + * index. + * + * All that is required is that the vertex shader labels + * its own outputs similarly, and that the vertex shader + * generates at least every output required by the + * fragment shader plus fixed-function hardware (such as + * BFC). + * + * There is no requirement that semantic indexes start at + * zero or be restricted to a particular range -- nobody + * should be building tables based on semantic index. + */ + case FRAG_ATTRIB_PNTC: + case FRAG_ATTRIB_TEX0: + case FRAG_ATTRIB_TEX1: + case FRAG_ATTRIB_TEX2: + case FRAG_ATTRIB_TEX3: + case FRAG_ATTRIB_TEX4: + case FRAG_ATTRIB_TEX5: + case FRAG_ATTRIB_TEX6: + case FRAG_ATTRIB_TEX7: + case FRAG_ATTRIB_VAR0: + default: + /* Actually, let's try and zero-base this just for + * readability of the generated TGSI. + */ + assert(attr >= FRAG_ATTRIB_TEX0); + input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); + input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + if (attr == FRAG_ATTRIB_PNTC) + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + else + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + break; + } + } + else { + inputMapping[attr] = -1; + } + } + + /* + * Semantics and mapping for outputs + */ + { + uint numColors = 0; + GLbitfield64 outputsWritten = stfp->Base.Base.OutputsWritten; + + /* if z is written, emit that first */ + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_POSITION; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_DEPTH] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_DEPTH); + } + + if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) { + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_STENCIL; + fs_output_semantic_index[fs_num_outputs] = 0; + outputMapping[FRAG_RESULT_STENCIL] = fs_num_outputs; + fs_num_outputs++; + outputsWritten &= ~(1 << FRAG_RESULT_STENCIL); + } + + /* handle remaning outputs (color) */ + for (attr = 0; attr < FRAG_RESULT_MAX; attr++) { + if (outputsWritten & BITFIELD64_BIT(attr)) { + switch (attr) { + case FRAG_RESULT_DEPTH: + case FRAG_RESULT_STENCIL: + /* handled above */ + assert(0); + break; + case FRAG_RESULT_COLOR: + write_all = GL_TRUE; /* fallthrough */ + default: + assert(attr == FRAG_RESULT_COLOR || + (FRAG_RESULT_DATA0 <= attr && attr < FRAG_RESULT_MAX)); + fs_output_semantic_name[fs_num_outputs] = TGSI_SEMANTIC_COLOR; + fs_output_semantic_index[fs_num_outputs] = numColors; + outputMapping[attr] = fs_num_outputs; + numColors++; + break; + } + + fs_num_outputs++; + } + } + } + + ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT ); + if (ureg == NULL) + return NULL; + + if (ST_DEBUG & DEBUG_MESA) { + _mesa_print_program(&stfp->Base.Base); + _mesa_print_program_parameters(st->ctx, &stfp->Base.Base); + debug_printf("\n"); + } + if (write_all == GL_TRUE) + ureg_property_fs_color0_writes_all_cbufs(ureg, 1); + + if (stfp->glsl_to_tgsi) + st_translate_program(st->ctx, + TGSI_PROCESSOR_FRAGMENT, + ureg, + stfp->glsl_to_tgsi, + &stfp->Base.Base, + /* inputs */ + fs_num_inputs, + inputMapping, + input_semantic_name, + input_semantic_index, + interpMode, + /* outputs */ + fs_num_outputs, + outputMapping, + fs_output_semantic_name, + fs_output_semantic_index, FALSE ); + else + st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_FRAGMENT, + ureg, + &stfp->Base.Base, + /* inputs */ + fs_num_inputs, + inputMapping, + input_semantic_name, + input_semantic_index, + interpMode, + /* outputs */ + fs_num_outputs, + outputMapping, + fs_output_semantic_name, + fs_output_semantic_index, FALSE ); + + stfp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + ureg_destroy( ureg ); + } + + /* fill in variant */ + variant->driver_shader = pipe->create_fs_state(pipe, &stfp->tgsi); + variant->key = *key; + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump( stfp->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/ ); + debug_printf("\n"); + } + + if (deleteFP) { + /* Free the temporary program made above */ + struct gl_fragment_program *fp = &stfp->Base; + _mesa_reference_fragprog(st->ctx, &fp, NULL); + } + + return variant; +} + + +/** + * Translate fragment program if needed. + */ +struct st_fp_variant * +st_get_fp_variant(struct st_context *st, + struct st_fragment_program *stfp, + const struct st_fp_variant_key *key) +{ + struct st_fp_variant *fpv; + + /* Search for existing variant */ + for (fpv = stfp->variants; fpv; fpv = fpv->next) { + if (memcmp(&fpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!fpv) { + /* create new */ + fpv = st_translate_fragment_program(st, stfp, key); + if (fpv) { + /* insert into list */ + fpv->next = stfp->variants; + stfp->variants = fpv; + } + } + + return fpv; +} + + +/** + * Translate a geometry program to create a new variant. + */ +static struct st_gp_variant * +st_translate_geometry_program(struct st_context *st, + struct st_geometry_program *stgp, + const struct st_gp_variant_key *key) +{ + GLuint inputMapping[GEOM_ATTRIB_MAX]; + GLuint outputMapping[GEOM_RESULT_MAX]; + struct pipe_context *pipe = st->pipe; + GLuint attr; + const GLbitfield inputsRead = stgp->Base.Base.InputsRead; + GLuint vslot = 0; + GLuint num_generic = 0; + + uint gs_num_inputs = 0; + uint gs_builtin_inputs = 0; + uint gs_array_offset = 0; + + ubyte gs_output_semantic_name[PIPE_MAX_SHADER_OUTPUTS]; + ubyte gs_output_semantic_index[PIPE_MAX_SHADER_OUTPUTS]; + uint gs_num_outputs = 0; + + GLint i; + GLuint maxSlot = 0; + struct ureg_program *ureg; + + struct st_gp_variant *gpv; + + gpv = CALLOC_STRUCT(st_gp_variant); + if (!gpv) + return NULL; + + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_OUTPUT); + _mesa_remove_output_reads(&stgp->Base.Base, PROGRAM_VARYING); + + ureg = ureg_create( TGSI_PROCESSOR_GEOMETRY ); + if (ureg == NULL) { + FREE(gpv); + return NULL; + } + + /* which vertex output goes to the first geometry input */ + vslot = 0; + + memset(inputMapping, 0, sizeof(inputMapping)); + memset(outputMapping, 0, sizeof(outputMapping)); + + /* + * Convert Mesa program inputs to TGSI input register semantics. + */ + for (attr = 0; attr < GEOM_ATTRIB_MAX; attr++) { + if (inputsRead & (1 << attr)) { + const GLuint slot = gs_num_inputs; + + gs_num_inputs++; + + inputMapping[attr] = slot; + + stgp->input_map[slot + gs_array_offset] = vslot - gs_builtin_inputs; + stgp->input_to_index[attr] = vslot; + stgp->index_to_input[vslot] = attr; + ++vslot; + + if (attr != GEOM_ATTRIB_PRIMITIVE_ID) { + gs_array_offset += 2; + } else + ++gs_builtin_inputs; + +#if 0 + debug_printf("input map at %d = %d\n", + slot + gs_array_offset, stgp->input_map[slot + gs_array_offset]); +#endif + + switch (attr) { + case GEOM_ATTRIB_PRIMITIVE_ID: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_PRIMID; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_POSITION: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_COLOR0: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_COLOR1: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + stgp->input_semantic_index[slot] = 1; + break; + case GEOM_ATTRIB_FOG_FRAG_COORD: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_FOG; + stgp->input_semantic_index[slot] = 0; + break; + case GEOM_ATTRIB_TEX_COORD: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stgp->input_semantic_index[slot] = num_generic++; + break; + case GEOM_ATTRIB_VAR0: + /* fall-through */ + default: + stgp->input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + stgp->input_semantic_index[slot] = num_generic++; + } + } + } + + /* initialize output semantics to defaults */ + for (i = 0; i < PIPE_MAX_SHADER_OUTPUTS; i++) { + gs_output_semantic_name[i] = TGSI_SEMANTIC_GENERIC; + gs_output_semantic_index[i] = 0; + } + + num_generic = 0; + /* + * Determine number of outputs, the (default) output register + * mapping and the semantic information for each output. + */ + for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { + if (stgp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) { + GLuint slot; + + slot = gs_num_outputs; + gs_num_outputs++; + outputMapping[attr] = slot; + + switch (attr) { + case GEOM_RESULT_POS: + assert(slot == 0); + gs_output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_COL0: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_COL1: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; + gs_output_semantic_index[slot] = 1; + break; + case GEOM_RESULT_SCOL0: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_SCOL1: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; + gs_output_semantic_index[slot] = 1; + break; + case GEOM_RESULT_FOGC: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_FOG; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_PSIZ: + gs_output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; + gs_output_semantic_index[slot] = 0; + break; + case GEOM_RESULT_TEX0: + case GEOM_RESULT_TEX1: + case GEOM_RESULT_TEX2: + case GEOM_RESULT_TEX3: + case GEOM_RESULT_TEX4: + case GEOM_RESULT_TEX5: + case GEOM_RESULT_TEX6: + case GEOM_RESULT_TEX7: + /* fall-through */ + case GEOM_RESULT_VAR0: + /* fall-through */ + default: + assert(slot < Elements(gs_output_semantic_name)); + /* use default semantic info */ + gs_output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; + gs_output_semantic_index[slot] = num_generic++; + } + } + } + + assert(gs_output_semantic_name[0] == TGSI_SEMANTIC_POSITION); + + /* find max output slot referenced to compute gs_num_outputs */ + for (attr = 0; attr < GEOM_RESULT_MAX; attr++) { + if (outputMapping[attr] != ~0 && outputMapping[attr] > maxSlot) + maxSlot = outputMapping[attr]; + } + gs_num_outputs = maxSlot + 1; + +#if 0 /* debug */ + { + GLuint i; + printf("outputMapping? %d\n", outputMapping ? 1 : 0); + if (outputMapping) { + printf("attr -> slot\n"); + for (i = 0; i < 16; i++) { + printf(" %2d %3d\n", i, outputMapping[i]); + } + } + printf("slot sem_name sem_index\n"); + for (i = 0; i < gs_num_outputs; i++) { + printf(" %2d %d %d\n", + i, + gs_output_semantic_name[i], + gs_output_semantic_index[i]); + } + } +#endif + + /* free old shader state, if any */ + if (stgp->tgsi.tokens) { + st_free_tokens(stgp->tgsi.tokens); + stgp->tgsi.tokens = NULL; + } + + ureg_property_gs_input_prim(ureg, stgp->Base.InputType); + ureg_property_gs_output_prim(ureg, stgp->Base.OutputType); + ureg_property_gs_max_vertices(ureg, stgp->Base.VerticesOut); + + st_translate_mesa_program(st->ctx, + TGSI_PROCESSOR_GEOMETRY, + ureg, + &stgp->Base.Base, + /* inputs */ + gs_num_inputs, + inputMapping, + stgp->input_semantic_name, + stgp->input_semantic_index, + NULL, + /* outputs */ + gs_num_outputs, + outputMapping, + gs_output_semantic_name, + gs_output_semantic_index, + FALSE); + + stgp->num_inputs = gs_num_inputs; + stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL ); + ureg_destroy( ureg ); + + /* fill in new variant */ + gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi); + gpv->key = *key; + + if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) { + _mesa_print_program(&stgp->Base.Base); + debug_printf("\n"); + } + + if (ST_DEBUG & DEBUG_TGSI) { + tgsi_dump(stgp->tgsi.tokens, 0); + debug_printf("\n"); + } + + return gpv; +} + + +/** + * Get/create geometry program variant. + */ +struct st_gp_variant * +st_get_gp_variant(struct st_context *st, + struct st_geometry_program *stgp, + const struct st_gp_variant_key *key) +{ + struct st_gp_variant *gpv; + + /* Search for existing variant */ + for (gpv = stgp->variants; gpv; gpv = gpv->next) { + if (memcmp(&gpv->key, key, sizeof(*key)) == 0) { + break; + } + } + + if (!gpv) { + /* create new */ + gpv = st_translate_geometry_program(st, stgp, key); + if (gpv) { + /* insert into list */ + gpv->next = stgp->variants; + stgp->variants = gpv; + } + } + + return gpv; +} + + + + +/** + * Debug- print current shader text + */ +void +st_print_shaders(struct gl_context *ctx) +{ + struct gl_shader_program *shProg[3] = { + ctx->Shader.CurrentVertexProgram, + ctx->Shader.CurrentGeometryProgram, + ctx->Shader.CurrentFragmentProgram, + }; + unsigned j; + + for (j = 0; j < 3; j++) { + unsigned i; + + if (shProg[j] == NULL) + continue; + + for (i = 0; i < shProg[j]->NumShaders; i++) { + struct gl_shader *sh; + + switch (shProg[j]->Shaders[i]->Type) { + case GL_VERTEX_SHADER: + sh = (i != 0) ? NULL : shProg[j]->Shaders[i]; + break; + case GL_GEOMETRY_SHADER_ARB: + sh = (i != 1) ? NULL : shProg[j]->Shaders[i]; + break; + case GL_FRAGMENT_SHADER: + sh = (i != 2) ? NULL : shProg[j]->Shaders[i]; + break; + default: + assert(0); + sh = NULL; + break; + } + + if (sh != NULL) { + printf("GLSL shader %u of %u:\n", i, shProg[j]->NumShaders); + printf("%s\n", sh->Source); + } + } + } +} + + +/** + * Vert/Geom/Frag programs have per-context variants. Free all the + * variants attached to the given program which match the given context. + */ +static void +destroy_program_variants(struct st_context *st, struct gl_program *program) +{ + if (!program) + return; + + switch (program->Target) { + case GL_VERTEX_PROGRAM_ARB: + { + struct st_vertex_program *stvp = (struct st_vertex_program *) program; + struct st_vp_variant *vpv, **prevPtr = &stvp->variants; + + for (vpv = stvp->variants; vpv; ) { + struct st_vp_variant *next = vpv->next; + if (vpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_vp_variant(st, vpv); + } + else { + prevPtr = &vpv->next; + } + vpv = next; + } + } + break; + case GL_FRAGMENT_PROGRAM_ARB: + { + struct st_fragment_program *stfp = + (struct st_fragment_program *) program; + struct st_fp_variant *fpv, **prevPtr = &stfp->variants; + + for (fpv = stfp->variants; fpv; ) { + struct st_fp_variant *next = fpv->next; + if (fpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_fp_variant(st, fpv); + } + else { + prevPtr = &fpv->next; + } + fpv = next; + } + } + break; + case MESA_GEOMETRY_PROGRAM: + { + struct st_geometry_program *stgp = + (struct st_geometry_program *) program; + struct st_gp_variant *gpv, **prevPtr = &stgp->variants; + + for (gpv = stgp->variants; gpv; ) { + struct st_gp_variant *next = gpv->next; + if (gpv->key.st == st) { + /* unlink from list */ + *prevPtr = next; + /* destroy this variant */ + delete_gp_variant(st, gpv); + } + else { + prevPtr = &gpv->next; + } + gpv = next; + } + } + break; + default: + _mesa_problem(NULL, "Unexpected program target 0x%x in " + "destroy_program_variants_cb()", program->Target); + } +} + + +/** + * Callback for _mesa_HashWalk. Free all the shader's program variants + * which match the given context. + */ +static void +destroy_shader_program_variants_cb(GLuint key, void *data, void *userData) +{ + struct st_context *st = (struct st_context *) userData; + struct gl_shader *shader = (struct gl_shader *) data; + + switch (shader->Type) { + case GL_SHADER_PROGRAM_MESA: + { + struct gl_shader_program *shProg = (struct gl_shader_program *) data; + GLuint i; + + for (i = 0; i < shProg->NumShaders; i++) { + destroy_program_variants(st, shProg->Shaders[i]->Program); + } + + destroy_program_variants(st, (struct gl_program *) + shProg->VertexProgram); + destroy_program_variants(st, (struct gl_program *) + shProg->FragmentProgram); + destroy_program_variants(st, (struct gl_program *) + shProg->GeometryProgram); + } + break; + case GL_VERTEX_SHADER: + case GL_FRAGMENT_SHADER: + case GL_GEOMETRY_SHADER: + { + destroy_program_variants(st, shader->Program); + } + break; + default: + assert(0); + } +} + + +/** + * Callback for _mesa_HashWalk. Free all the program variants which match + * the given context. + */ +static void +destroy_program_variants_cb(GLuint key, void *data, void *userData) +{ + struct st_context *st = (struct st_context *) userData; + struct gl_program *program = (struct gl_program *) data; + destroy_program_variants(st, program); +} + + +/** + * Walk over all shaders and programs to delete any variants which + * belong to the given context. + * This is called during context tear-down. + */ +void +st_destroy_program_variants(struct st_context *st) +{ + /* ARB vert/frag program */ + _mesa_HashWalk(st->ctx->Shared->Programs, + destroy_program_variants_cb, st); + + /* GLSL vert/frag/geom shaders */ + _mesa_HashWalk(st->ctx->Shared->ShaderObjects, + destroy_shader_program_variants_cb, st); +} diff --git a/mesalib/src/mesa/state_tracker/st_texture.h b/mesalib/src/mesa/state_tracker/st_texture.h index fb1071fc3..50b7284e7 100644 --- a/mesalib/src/mesa/state_tracker/st_texture.h +++ b/mesalib/src/mesa/state_tracker/st_texture.h @@ -1,234 +1,234 @@ -/**************************************************************************
- *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
- * 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.
- *
- **************************************************************************/
-
-#ifndef ST_TEXTURE_H
-#define ST_TEXTURE_H
-
-
-#include "pipe/p_context.h"
-#include "util/u_sampler.h"
-
-#include "main/mtypes.h"
-
-
-struct pipe_resource;
-
-
-/**
- * Subclass of gl_texure_image.
- */
-struct st_texture_image
-{
- struct gl_texture_image base;
-
- /* If stImage->pt != NULL, image data is stored here.
- * Else if stImage->base.Data != NULL, image is stored there.
- * Else there is no image data.
- */
- struct pipe_resource *pt;
-
- struct pipe_transfer *transfer;
-};
-
-
-/**
- * Subclass of gl_texure_object.
- */
-struct st_texture_object
-{
- struct gl_texture_object base; /* The "parent" object */
-
- /* The texture must include at levels [0..lastLevel] once validated:
- */
- GLuint lastLevel;
-
- /** The size of the level=0 mipmap image.
- * Note that the number of 1D array layers will be in height0 and the
- * number of 2D array layers will be in depth0, as in GL.
- */
- GLuint width0, height0, depth0;
-
- /* On validation any active images held in main memory or in other
- * textures will be copied to this texture and the old storage freed.
- */
- struct pipe_resource *pt;
-
- /* Default sampler view attached to this texture object. Created lazily
- * on first binding.
- */
- struct pipe_sampler_view *sampler_view;
-
- /* True if there is/was a surface bound to this texture object. It helps
- * track whether the texture object is surface based or not.
- */
- GLboolean surface_based;
-};
-
-
-static INLINE struct st_texture_image *
-st_texture_image(struct gl_texture_image *img)
-{
- return (struct st_texture_image *) img;
-}
-
-static INLINE struct st_texture_object *
-st_texture_object(struct gl_texture_object *obj)
-{
- return (struct st_texture_object *) obj;
-}
-
-
-static INLINE struct pipe_resource *
-st_get_texobj_resource(struct gl_texture_object *texObj)
-{
- struct st_texture_object *stObj = st_texture_object(texObj);
- return stObj ? stObj->pt : NULL;
-}
-
-
-static INLINE struct pipe_resource *
-st_get_stobj_resource(struct st_texture_object *stObj)
-{
- return stObj ? stObj->pt : NULL;
-}
-
-
-static INLINE struct pipe_sampler_view *
-st_create_texture_sampler_view(struct pipe_context *pipe,
- struct pipe_resource *texture)
-{
- struct pipe_sampler_view templ;
-
- u_sampler_view_default_template(&templ, texture, texture->format);
-
- return pipe->create_sampler_view(pipe, texture, &templ);
-}
-
-
-static INLINE struct pipe_sampler_view *
-st_create_texture_sampler_view_format(struct pipe_context *pipe,
- struct pipe_resource *texture,
- enum pipe_format format)
-{
- struct pipe_sampler_view templ;
-
- u_sampler_view_default_template(&templ, texture, format);
-
- return pipe->create_sampler_view(pipe, texture, &templ);
-}
-
-
-static INLINE struct pipe_sampler_view *
-st_get_texture_sampler_view(struct st_texture_object *stObj,
- struct pipe_context *pipe)
-{
- if (!stObj || !stObj->pt) {
- return NULL;
- }
-
- if (!stObj->sampler_view) {
- stObj->sampler_view = st_create_texture_sampler_view(pipe, stObj->pt);
- }
-
- return stObj->sampler_view;
-}
-
-
-extern struct pipe_resource *
-st_texture_create(struct st_context *st,
- enum pipe_texture_target target,
- enum pipe_format format,
- GLuint last_level,
- GLuint width0,
- GLuint height0,
- GLuint depth0,
- GLuint layers,
- GLuint tex_usage );
-
-
-extern void
-st_gl_texture_dims_to_pipe_dims(GLenum texture,
- GLuint widthIn,
- GLuint heightIn,
- GLuint depthIn,
- GLuint *widthOut,
- GLuint *heightOut,
- GLuint *depthOut,
- GLuint *layersOut);
-
-/* Check if an image fits into an existing texture object.
- */
-extern GLboolean
-st_texture_match_image(const struct pipe_resource *pt,
- const struct gl_texture_image *image,
- GLuint face, GLuint level);
-
-/* Return a pointer to an image within a texture. Return image stride as
- * well.
- */
-extern GLubyte *
-st_texture_image_map(struct st_context *st,
- struct st_texture_image *stImage,
- GLuint zoffset,
- enum pipe_transfer_usage usage,
- unsigned x, unsigned y,
- unsigned w, unsigned h);
-
-extern void
-st_texture_image_unmap(struct st_context *st,
- struct st_texture_image *stImage);
-
-
-/* Return pointers to each 2d slice within an image. Indexed by depth
- * value.
- */
-extern const GLuint *
-st_texture_depth_offsets(struct pipe_resource *pt, GLuint level);
-
-
-/* Upload an image into a texture
- */
-extern void
-st_texture_image_data(struct st_context *st,
- struct pipe_resource *dst,
- GLuint face, GLuint level, void *src,
- GLuint src_row_pitch, GLuint src_image_pitch);
-
-
-/* Copy an image between two textures
- */
-extern void
-st_texture_image_copy(struct pipe_context *pipe,
- struct pipe_resource *dst, GLuint dstLevel,
- struct pipe_resource *src, GLuint srcLevel,
- GLuint face);
-
-
-extern struct pipe_resource *
-st_create_color_map_texture(struct gl_context *ctx);
-
-#endif
+/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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. + * + **************************************************************************/ + +#ifndef ST_TEXTURE_H +#define ST_TEXTURE_H + + +#include "pipe/p_context.h" +#include "util/u_sampler.h" + +#include "main/mtypes.h" + + +struct pipe_resource; + + +/** + * Subclass of gl_texure_image. + */ +struct st_texture_image +{ + struct gl_texture_image base; + + /* If stImage->pt != NULL, image data is stored here. + * Else if stImage->base.Data != NULL, image is stored there. + * Else there is no image data. + */ + struct pipe_resource *pt; + + struct pipe_transfer *transfer; +}; + + +/** + * Subclass of gl_texure_object. + */ +struct st_texture_object +{ + struct gl_texture_object base; /* The "parent" object */ + + /* The texture must include at levels [0..lastLevel] once validated: + */ + GLuint lastLevel; + + /** The size of the level=0 mipmap image. + * Note that the number of 1D array layers will be in height0 and the + * number of 2D array layers will be in depth0, as in GL. + */ + GLuint width0, height0, depth0; + + /* On validation any active images held in main memory or in other + * textures will be copied to this texture and the old storage freed. + */ + struct pipe_resource *pt; + + /* Default sampler view attached to this texture object. Created lazily + * on first binding. + */ + struct pipe_sampler_view *sampler_view; + + /* True if there is/was a surface bound to this texture object. It helps + * track whether the texture object is surface based or not. + */ + GLboolean surface_based; +}; + + +static INLINE struct st_texture_image * +st_texture_image(struct gl_texture_image *img) +{ + return (struct st_texture_image *) img; +} + +static INLINE struct st_texture_object * +st_texture_object(struct gl_texture_object *obj) +{ + return (struct st_texture_object *) obj; +} + + +static INLINE struct pipe_resource * +st_get_texobj_resource(struct gl_texture_object *texObj) +{ + struct st_texture_object *stObj = st_texture_object(texObj); + return stObj ? stObj->pt : NULL; +} + + +static INLINE struct pipe_resource * +st_get_stobj_resource(struct st_texture_object *stObj) +{ + return stObj ? stObj->pt : NULL; +} + + +static INLINE struct pipe_sampler_view * +st_create_texture_sampler_view(struct pipe_context *pipe, + struct pipe_resource *texture) +{ + struct pipe_sampler_view templ; + + u_sampler_view_default_template(&templ, texture, texture->format); + + return pipe->create_sampler_view(pipe, texture, &templ); +} + + +static INLINE struct pipe_sampler_view * +st_create_texture_sampler_view_format(struct pipe_context *pipe, + struct pipe_resource *texture, + enum pipe_format format) +{ + struct pipe_sampler_view templ; + + u_sampler_view_default_template(&templ, texture, format); + + return pipe->create_sampler_view(pipe, texture, &templ); +} + + +static INLINE struct pipe_sampler_view * +st_get_texture_sampler_view(struct st_texture_object *stObj, + struct pipe_context *pipe) +{ + if (!stObj || !stObj->pt) { + return NULL; + } + + if (!stObj->sampler_view) { + stObj->sampler_view = st_create_texture_sampler_view(pipe, stObj->pt); + } + + return stObj->sampler_view; +} + + +extern struct pipe_resource * +st_texture_create(struct st_context *st, + enum pipe_texture_target target, + enum pipe_format format, + GLuint last_level, + GLuint width0, + GLuint height0, + GLuint depth0, + GLuint layers, + GLuint tex_usage ); + + +extern void +st_gl_texture_dims_to_pipe_dims(GLenum texture, + GLuint widthIn, + GLuint heightIn, + GLuint depthIn, + GLuint *widthOut, + GLuint *heightOut, + GLuint *depthOut, + GLuint *layersOut); + +/* Check if an image fits into an existing texture object. + */ +extern GLboolean +st_texture_match_image(const struct pipe_resource *pt, + const struct gl_texture_image *image, + GLuint face, GLuint level); + +/* Return a pointer to an image within a texture. Return image stride as + * well. + */ +extern GLubyte * +st_texture_image_map(struct st_context *st, + struct st_texture_image *stImage, + GLuint zoffset, + enum pipe_transfer_usage usage, + unsigned x, unsigned y, + unsigned w, unsigned h); + +extern void +st_texture_image_unmap(struct st_context *st, + struct st_texture_image *stImage); + + +/* Return pointers to each 2d slice within an image. Indexed by depth + * value. + */ +extern const GLuint * +st_texture_depth_offsets(struct pipe_resource *pt, GLuint level); + + +/* Upload an image into a texture + */ +extern void +st_texture_image_data(struct st_context *st, + struct pipe_resource *dst, + GLuint face, GLuint level, void *src, + GLuint src_row_pitch, GLuint src_image_pitch); + + +/* Copy an image between two textures + */ +extern void +st_texture_image_copy(struct pipe_context *pipe, + struct pipe_resource *dst, GLuint dstLevel, + struct pipe_resource *src, GLuint srcLevel, + GLuint face); + + +extern struct pipe_resource * +st_create_color_map_texture(struct gl_context *ctx); + +#endif |