From 48d0dcbd5b7f80810ce259bc9ed6f57f99e27ca9 Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 16 Feb 2011 16:53:37 +0000 Subject: pixman mesa git update 16 Feb 2011 --- mesalib/src/mesa/state_tracker/st_atom_blend.c | 601 ++--- mesalib/src/mesa/state_tracker/st_cb_bitmap.c | 1783 ++++++------- .../src/mesa/state_tracker/st_cb_bufferobjects.c | 915 +++---- mesalib/src/mesa/state_tracker/st_cb_clear.c | 1122 ++++---- mesalib/src/mesa/state_tracker/st_cb_drawpixels.c | 2739 ++++++++++---------- mesalib/src/mesa/state_tracker/st_cb_drawtex.c | 611 ++--- mesalib/src/mesa/state_tracker/st_context.c | 5 + mesalib/src/mesa/state_tracker/st_context.h | 535 ++-- mesalib/src/mesa/state_tracker/st_draw.c | 1537 ++++++----- mesalib/src/mesa/state_tracker/st_draw_feedback.c | 1 - mesalib/src/mesa/state_tracker/st_gen_mipmap.c | 846 +++--- 11 files changed, 5350 insertions(+), 5345 deletions(-) (limited to 'mesalib/src/mesa/state_tracker') diff --git a/mesalib/src/mesa/state_tracker/st_atom_blend.c b/mesalib/src/mesa/state_tracker/st_atom_blend.c index 26bb3dab9..fb1c7a4ef 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_blend.c +++ b/mesalib/src/mesa/state_tracker/st_atom_blend.c @@ -1,299 +1,302 @@ -/************************************************************************** - * - * 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 - * 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(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(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; - unsigned num_state = 1; - unsigned i; - - memset(blend, 0, sizeof(*blend)); - - if (blend_per_rt(st->ctx) || colormask_per_rt(st->ctx)) { - num_state = st->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 (st->ctx->Color.ColorLogicOpEnabled || - (st->ctx->Color.BlendEnabled && - st->ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) { - /* logicop enabled */ - blend->logicop_enable = 1; - blend->logicop_func = translate_logicop(st->ctx->Color.LogicOp); - } - else if (st->ctx->Color.BlendEnabled) { - /* blending enabled */ - for (i = 0; i < num_state; i++) { - - blend->rt[i].blend_enable = (st->ctx->Color.BlendEnabled >> i) & 0x1; - - blend->rt[i].rgb_func = - translate_blend(st->ctx->Color.Blend[i].EquationRGB); - - if (st->ctx->Color.Blend[i].EquationRGB == GL_MIN || - st->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(st->ctx->Color.Blend[i].SrcRGB); - blend->rt[i].rgb_dst_factor = - translate_blend(st->ctx->Color.Blend[i].DstRGB); - } - - blend->rt[i].alpha_func = - translate_blend(st->ctx->Color.Blend[i].EquationA); - - if (st->ctx->Color.Blend[i].EquationA == GL_MIN || - st->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(st->ctx->Color.Blend[i].SrcA); - blend->rt[i].alpha_dst_factor = - translate_blend(st->ctx->Color.Blend[i].DstA); - } - } - } - else { - /* no blending / logicop */ - } - - /* Colormask - maybe reverse these bits? */ - for (i = 0; i < num_state; i++) { - if (st->ctx->Color.ColorMask[i][0]) - blend->rt[i].colormask |= PIPE_MASK_R; - if (st->ctx->Color.ColorMask[i][1]) - blend->rt[i].colormask |= PIPE_MASK_G; - if (st->ctx->Color.ColorMask[i][2]) - blend->rt[i].colormask |= PIPE_MASK_B; - if (st->ctx->Color.ColorMask[i][3]) - blend->rt[i].colormask |= PIPE_MASK_A; - } - - if (st->ctx->Color.DitherFlag) - blend->dither = 1; - - if (st->ctx->Multisample.Enabled) { - /* unlike in gallium/d3d10 these operations are only performed - if msaa is enabled */ - if (st->ctx->Multisample.SampleAlphaToCoverage) - blend->alpha_to_coverage = 1; - if (st->ctx->Multisample.SampleAlphaToOne) - blend->alpha_to_one = 1; - } - - cso_set_blend(st->cso_context, blend); - - { - struct pipe_blend_color bc; - COPY_4FV(bc.color, st->ctx->Color.BlendColor); - 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 + * 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(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(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; + unsigned num_state = 1; + unsigned i, j; + + memset(blend, 0, sizeof(*blend)); + + if (blend_per_rt(st->ctx) || colormask_per_rt(st->ctx)) { + num_state = st->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 (st->ctx->Color.ColorLogicOpEnabled || + (st->ctx->Color.BlendEnabled && + st->ctx->Color.Blend[0].EquationRGB == GL_LOGIC_OP)) { + /* logicop enabled */ + blend->logicop_enable = 1; + blend->logicop_func = translate_logicop(st->ctx->Color.LogicOp); + } + else if (st->ctx->Color.BlendEnabled) { + /* blending enabled */ + for (i = 0, j = 0; i < num_state; i++) { + + blend->rt[i].blend_enable = (st->ctx->Color.BlendEnabled >> i) & 0x1; + + if (st->ctx->Extensions.ARB_draw_buffers_blend) + j = i; + + blend->rt[i].rgb_func = + translate_blend(st->ctx->Color.Blend[j].EquationRGB); + + if (st->ctx->Color.Blend[i].EquationRGB == GL_MIN || + st->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(st->ctx->Color.Blend[j].SrcRGB); + blend->rt[i].rgb_dst_factor = + translate_blend(st->ctx->Color.Blend[j].DstRGB); + } + + blend->rt[i].alpha_func = + translate_blend(st->ctx->Color.Blend[j].EquationA); + + if (st->ctx->Color.Blend[i].EquationA == GL_MIN || + st->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(st->ctx->Color.Blend[j].SrcA); + blend->rt[i].alpha_dst_factor = + translate_blend(st->ctx->Color.Blend[j].DstA); + } + } + } + else { + /* no blending / logicop */ + } + + /* Colormask - maybe reverse these bits? */ + for (i = 0; i < num_state; i++) { + if (st->ctx->Color.ColorMask[i][0]) + blend->rt[i].colormask |= PIPE_MASK_R; + if (st->ctx->Color.ColorMask[i][1]) + blend->rt[i].colormask |= PIPE_MASK_G; + if (st->ctx->Color.ColorMask[i][2]) + blend->rt[i].colormask |= PIPE_MASK_B; + if (st->ctx->Color.ColorMask[i][3]) + blend->rt[i].colormask |= PIPE_MASK_A; + } + + if (st->ctx->Color.DitherFlag) + blend->dither = 1; + + if (st->ctx->Multisample.Enabled) { + /* unlike in gallium/d3d10 these operations are only performed + if msaa is enabled */ + if (st->ctx->Multisample.SampleAlphaToCoverage) + blend->alpha_to_coverage = 1; + if (st->ctx->Multisample.SampleAlphaToOne) + blend->alpha_to_one = 1; + } + + cso_set_blend(st->cso_context, blend); + + { + struct pipe_blend_color bc; + COPY_4FV(bc.color, st->ctx->Color.BlendColor); + 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_cb_bitmap.c b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c index ddd130a81..0ea567155 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_bitmap.c +++ b/mesalib/src/mesa/state_tracker/st_cb_bitmap.c @@ -1,890 +1,893 @@ -/************************************************************************** - * - * 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 "program/program.h" -#include "program/prog_print.h" - -#include "st_context.h" -#include "st_atom.h" -#include "st_atom_constbuf.h" -#include "st_program.h" -#include "st_cb_bitmap.h" -#include "st_texture.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "pipe/p_shader_tokens.h" -#include "util/u_inlines.h" -#include "util/u_draw_quad.h" -#include "util/u_simple_shaders.h" -#include "program/prog_instruction.h" -#include "cso_cache/cso_context.h" - - -#if FEATURE_drawpix - -/** - * glBitmaps are drawn as textured quads. The user's bitmap pattern - * is stored in a texture image. An alpha8 texture format is used. - * The fragment shader samples a bit (texel) from the texture, then - * discards the fragment if the bit is off. - * - * Note that we actually store the inverse image of the bitmap to - * simplify the fragment program. An "on" bit gets stored as texel=0x0 - * and an "off" bit is stored as texel=0xff. Then we kill the - * fragment if the negated texel value is less than zero. - */ - - -/** - * The bitmap cache attempts to accumulate multiple glBitmap calls in a - * buffer which is then rendered en mass upon a flush, state change, etc. - * A wide, short buffer is used to target the common case of a series - * of glBitmap calls being used to draw text. - */ -static GLboolean UseBitmapCache = GL_TRUE; - - -#define BITMAP_CACHE_WIDTH 512 -#define BITMAP_CACHE_HEIGHT 32 - -struct bitmap_cache -{ - /** Window pos to render the cached image */ - GLint xpos, ypos; - /** Bounds of region used in window coords */ - GLint xmin, ymin, xmax, ymax; - - GLfloat color[4]; - - /** Bitmap's Z position */ - GLfloat zpos; - - struct pipe_resource *texture; - struct pipe_transfer *trans; - - GLboolean empty; - - /** An I8 texture image: */ - ubyte *buffer; -}; - - -/** Epsilon for Z comparisons */ -#define Z_EPSILON 1e-06 - - -/** - * Make fragment program for glBitmap: - * Sample the texture and kill the fragment if the bit is 0. - * This program will be combined with the user's fragment program. - */ -static struct st_fragment_program * -make_bitmap_fragment_program(struct gl_context *ctx, GLuint samplerIndex) -{ - struct st_context *st = st_context(ctx); - struct st_fragment_program *stfp; - struct gl_program *p; - GLuint ic = 0; - - p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); - if (!p) - return NULL; - - p->NumInstructions = 3; - - p->Instructions = _mesa_alloc_instructions(p->NumInstructions); - if (!p->Instructions) { - ctx->Driver.DeleteProgram(ctx, p); - return NULL; - } - _mesa_init_instructions(p->Instructions, p->NumInstructions); - - /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */ - p->Instructions[ic].Opcode = OPCODE_TEX; - p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY; - p->Instructions[ic].DstReg.Index = 0; - p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; - p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; - p->Instructions[ic].TexSrcUnit = samplerIndex; - p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; - ic++; - - /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */ - p->Instructions[ic].Opcode = OPCODE_KIL; - p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY; - - if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM) - p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_XXXX; - - p->Instructions[ic].SrcReg[0].Index = 0; - p->Instructions[ic].SrcReg[0].Negate = NEGATE_XYZW; - ic++; - - /* END; */ - p->Instructions[ic++].Opcode = OPCODE_END; - - assert(ic == p->NumInstructions); - - p->InputsRead = FRAG_BIT_TEX0; - p->OutputsWritten = 0x0; - p->SamplersUsed = (1 << samplerIndex); - - stfp = (struct st_fragment_program *) p; - stfp->Base.UsesKill = GL_TRUE; - - return stfp; -} - - -static int -find_free_bit(uint bitfield) -{ - int i; - for (i = 0; i < 32; i++) { - if ((bitfield & (1 << i)) == 0) { - return i; - } - } - return -1; -} - - -/** - * Combine basic bitmap fragment program with the user-defined program. - * \param st current context - * \param fpIn the incoming fragment program - * \param fpOut the new fragment program which does fragment culling - * \param bitmap_sampler sampler number for the bitmap texture - */ -void -st_make_bitmap_fragment_program(struct st_context *st, - struct gl_fragment_program *fpIn, - struct gl_fragment_program **fpOut, - GLuint *bitmap_sampler) -{ - struct st_fragment_program *bitmap_prog; - struct gl_program *newProg; - uint sampler; - - /* - * Generate new program which is the user-defined program prefixed - * with the bitmap sampler/kill instructions. - */ - sampler = find_free_bit(fpIn->Base.SamplersUsed); - bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler); - - newProg = _mesa_combine_programs(st->ctx, - &bitmap_prog->Base.Base, - &fpIn->Base); - /* done with this after combining */ - st_reference_fragprog(st, &bitmap_prog, NULL); - -#if 0 - { - printf("Combined bitmap 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 - - /* return results */ - *fpOut = (struct gl_fragment_program *) newProg; - *bitmap_sampler = sampler; -} - - -/** - * Copy user-provide bitmap bits into texture buffer, expanding - * bits into texels. - * "On" bits will set texels to 0x0. - * "Off" bits will not modify texels. - * Note that the image is actually going to be upside down in - * the texture. We deal with that with texcoords. - */ -static void -unpack_bitmap(struct st_context *st, - GLint px, GLint py, GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap, - ubyte *destBuffer, uint destStride) -{ - destBuffer += py * destStride + px; - - _mesa_expand_bitmap(width, height, unpack, bitmap, - destBuffer, destStride, 0x0); -} - - -/** - * Create a texture which represents a bitmap image. - */ -static struct pipe_resource * -make_bitmap_texture(struct gl_context *ctx, GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct pipe_transfer *transfer; - ubyte *dest; - struct pipe_resource *pt; - - /* PBO source... */ - bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap); - if (!bitmap) { - return NULL; - } - - /** - * Create texture to hold bitmap pattern. - */ - pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format, - 0, width, height, 1, 1, - PIPE_BIND_SAMPLER_VIEW); - if (!pt) { - _mesa_unmap_pbo_source(ctx, unpack); - return NULL; - } - - transfer = pipe_get_transfer(st->pipe, pt, 0, 0, - PIPE_TRANSFER_WRITE, - 0, 0, width, height); - - dest = pipe_transfer_map(pipe, transfer); - - /* Put image into texture transfer */ - memset(dest, 0xff, height * transfer->stride); - unpack_bitmap(st, 0, 0, width, height, unpack, bitmap, - dest, transfer->stride); - - _mesa_unmap_pbo_source(ctx, unpack); - - /* Release transfer */ - pipe_transfer_unmap(pipe, transfer); - pipe->transfer_destroy(pipe, transfer); - - return pt; -} - -static GLuint -setup_bitmap_vertex_data(struct st_context *st, bool normalized, - int x, int y, int width, int height, - float z, const float color[4]) -{ - struct pipe_context *pipe = st->pipe; - const struct gl_framebuffer *fb = st->ctx->DrawBuffer; - const GLfloat fb_width = (GLfloat)fb->Width; - const GLfloat fb_height = (GLfloat)fb->Height; - const GLfloat x0 = (GLfloat)x; - const GLfloat x1 = (GLfloat)(x + width); - const GLfloat y0 = (GLfloat)y; - const GLfloat y1 = (GLfloat)(y + height); - GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0; - GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop; - 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); - const GLuint max_slots = 1; /* 4096 / sizeof(st->bitmap.vertices); */ - GLuint i; - - if(!normalized) - { - sRight = width; - tBot = height; - } - - /* 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. - */ - if (st->bitmap.vbuf_slot >= max_slots) { - pipe_resource_reference(&st->bitmap.vbuf, NULL); - st->bitmap.vbuf_slot = 0; - } - - if (!st->bitmap.vbuf) { - st->bitmap.vbuf = pipe_buffer_create(pipe->screen, - PIPE_BIND_VERTEX_BUFFER, - max_slots * - sizeof(st->bitmap.vertices)); - } - - /* Positions are in clip coords since we need to do clipping in case - * the bitmap quad goes beyond the window bounds. - */ - st->bitmap.vertices[0][0][0] = clip_x0; - st->bitmap.vertices[0][0][1] = clip_y0; - st->bitmap.vertices[0][2][0] = sLeft; - st->bitmap.vertices[0][2][1] = tTop; - - st->bitmap.vertices[1][0][0] = clip_x1; - st->bitmap.vertices[1][0][1] = clip_y0; - st->bitmap.vertices[1][2][0] = sRight; - st->bitmap.vertices[1][2][1] = tTop; - - st->bitmap.vertices[2][0][0] = clip_x1; - st->bitmap.vertices[2][0][1] = clip_y1; - st->bitmap.vertices[2][2][0] = sRight; - st->bitmap.vertices[2][2][1] = tBot; - - st->bitmap.vertices[3][0][0] = clip_x0; - st->bitmap.vertices[3][0][1] = clip_y1; - st->bitmap.vertices[3][2][0] = sLeft; - st->bitmap.vertices[3][2][1] = tBot; - - /* same for all verts: */ - for (i = 0; i < 4; i++) { - st->bitmap.vertices[i][0][2] = z; - st->bitmap.vertices[i][0][3] = 1.0; - st->bitmap.vertices[i][1][0] = color[0]; - st->bitmap.vertices[i][1][1] = color[1]; - st->bitmap.vertices[i][1][2] = color[2]; - st->bitmap.vertices[i][1][3] = color[3]; - st->bitmap.vertices[i][2][2] = 0.0; /*R*/ - st->bitmap.vertices[i][2][3] = 1.0; /*Q*/ - } - - /* put vertex data into vbuf */ - pipe_buffer_write_nooverlap(st->pipe, - st->bitmap.vbuf, - st->bitmap.vbuf_slot - * sizeof(st->bitmap.vertices), - sizeof st->bitmap.vertices, - st->bitmap.vertices); - - return st->bitmap.vbuf_slot++ * sizeof st->bitmap.vertices; -} - - - -/** - * Render a glBitmap by drawing a textured quad - */ -static void -draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, - GLsizei width, GLsizei height, - struct pipe_sampler_view *sv, - const GLfloat *color) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - struct cso_context *cso = st->cso_context; - struct st_fp_variant *fpv; - struct st_fp_variant_key key; - GLuint maxSize; - GLuint offset; - - memset(&key, 0, sizeof(key)); - key.st = st; - key.bitmap = GL_TRUE; - - fpv = st_get_fp_variant(st, st->fp, &key); - - /* As an optimization, Mesa's fragment programs will sometimes get the - * primary color from a statevar/constant rather than a varying variable. - * when that's the case, we need to ensure that we use the 'color' - * parameter and not the current attribute color (which may have changed - * through glRasterPos and state validation. - * So, we force the proper color here. Not elegant, but it works. - */ - { - GLfloat colorSave[4]; - COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]); - COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color); - st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); - COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave); - } - - - /* limit checks */ - /* XXX if the bitmap is larger than the 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 <= (GLsizei)maxSize); - assert(height <= (GLsizei)maxSize); - - cso_save_rasterizer(cso); - cso_save_samplers(cso); - cso_save_fragment_sampler_views(cso); - cso_save_viewport(cso); - cso_save_fragment_shader(cso); - cso_save_vertex_shader(cso); - cso_save_vertex_elements(cso); - - /* rasterizer state: just scissor */ - st->bitmap.rasterizer.scissor = ctx->Scissor.Enabled; - cso_set_rasterizer(cso, &st->bitmap.rasterizer); - - /* fragment shader state: TEX lookup program */ - cso_set_fragment_shader_handle(cso, fpv->driver_shader); - - /* vertex shader state: position + texcoord pass-through */ - cso_set_vertex_shader_handle(cso, st->bitmap.vs); - - /* user samplers, plus our bitmap sampler */ - { - struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; - uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_samplers); - uint i; - for (i = 0; i < st->state.num_samplers; i++) { - samplers[i] = &st->state.samplers[i]; - } - samplers[fpv->bitmap_sampler] = - &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT]; - cso_set_samplers(cso, num, (const struct pipe_sampler_state **) samplers); - } - - /* user textures, plus the bitmap texture */ - { - struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; - uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_textures); - memcpy(sampler_views, st->state.sampler_views, sizeof(sampler_views)); - sampler_views[fpv->bitmap_sampler] = sv; - cso_set_fragment_sampler_views(cso, num, sampler_views); - } - - /* 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] = 0.5f; - vp.scale[3] = 1.0f; - vp.translate[0] = 0.5f * width; - vp.translate[1] = 0.5f * height; - 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); - - /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ - z = z * 2.0 - 1.0; - - /* draw textured quad */ - offset = setup_bitmap_vertex_data(st, - sv->texture->target != PIPE_TEXTURE_RECT, - x, y, width, height, z, color); - - util_draw_vertex_buffer(pipe, st->bitmap.vbuf, offset, - PIPE_PRIM_TRIANGLE_FAN, - 4, /* verts */ - 3); /* attribs/vert */ - - - /* restore state */ - cso_restore_rasterizer(cso); - cso_restore_samplers(cso); - cso_restore_fragment_sampler_views(cso); - cso_restore_viewport(cso); - cso_restore_fragment_shader(cso); - cso_restore_vertex_shader(cso); - cso_restore_vertex_elements(cso); -} - - -static void -reset_cache(struct st_context *st) -{ - struct pipe_context *pipe = st->pipe; - struct bitmap_cache *cache = st->bitmap.cache; - - /*memset(cache->buffer, 0xff, sizeof(cache->buffer));*/ - cache->empty = GL_TRUE; - - cache->xmin = 1000000; - cache->xmax = -1000000; - cache->ymin = 1000000; - cache->ymax = -1000000; - - if (cache->trans) { - pipe->transfer_destroy(pipe, cache->trans); - cache->trans = NULL; - } - - assert(!cache->texture); - - /* allocate a new texture */ - cache->texture = st_texture_create(st, PIPE_TEXTURE_2D, - st->bitmap.tex_format, 0, - BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, - 1, 1, - PIPE_BIND_SAMPLER_VIEW); -} - - -/** Print bitmap image to stdout (debug) */ -static void -print_cache(const struct bitmap_cache *cache) -{ - int i, j, k; - - for (i = 0; i < BITMAP_CACHE_HEIGHT; i++) { - k = BITMAP_CACHE_WIDTH * (BITMAP_CACHE_HEIGHT - i - 1); - for (j = 0; j < BITMAP_CACHE_WIDTH; j++) { - if (cache->buffer[k]) - printf("X"); - else - printf(" "); - k++; - } - printf("\n"); - } -} - - -/** - * Create gallium pipe_transfer object for the bitmap cache. - */ -static void -create_cache_trans(struct st_context *st) -{ - struct pipe_context *pipe = st->pipe; - struct bitmap_cache *cache = st->bitmap.cache; - - if (cache->trans) - return; - - /* Map the texture transfer. - * Subsequent glBitmap calls will write into the texture image. - */ - cache->trans = pipe_get_transfer(st->pipe, cache->texture, 0, 0, - PIPE_TRANSFER_WRITE, 0, 0, - BITMAP_CACHE_WIDTH, - BITMAP_CACHE_HEIGHT); - cache->buffer = pipe_transfer_map(pipe, cache->trans); - - /* init image to all 0xff */ - memset(cache->buffer, 0xff, cache->trans->stride * BITMAP_CACHE_HEIGHT); -} - - -/** - * If there's anything in the bitmap cache, draw/flush it now. - */ -void -st_flush_bitmap_cache(struct st_context *st) -{ - if (!st->bitmap.cache->empty) { - struct bitmap_cache *cache = st->bitmap.cache; - - if (st->ctx->DrawBuffer) { - struct pipe_context *pipe = st->pipe; - struct pipe_sampler_view *sv; - - assert(cache->xmin <= cache->xmax); - -/* printf("flush size %d x %d at %d, %d\n", - cache->xmax - cache->xmin, - cache->ymax - cache->ymin, - cache->xpos, cache->ypos); -*/ - - /* The texture transfer has been mapped until now. - * So unmap and release the texture transfer before drawing. - */ - if (cache->trans) { - if (0) - print_cache(cache); - pipe_transfer_unmap(pipe, cache->trans); - cache->buffer = NULL; - - pipe->transfer_destroy(pipe, cache->trans); - cache->trans = NULL; - } - - sv = st_create_texture_sampler_view(st->pipe, cache->texture); - if (sv) { - draw_bitmap_quad(st->ctx, - cache->xpos, - cache->ypos, - cache->zpos, - BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, - sv, - cache->color); - - pipe_sampler_view_reference(&sv, NULL); - } - } - - /* release/free the texture */ - pipe_resource_reference(&cache->texture, NULL); - - reset_cache(st); - } -} - - -/** - * Flush bitmap cache and release vertex buffer. - */ -void -st_flush_bitmap( struct st_context *st ) -{ - st_flush_bitmap_cache(st); - - /* Release vertex buffer to avoid synchronous rendering if we were - * to map it in the next frame. - */ - pipe_resource_reference(&st->bitmap.vbuf, NULL); - st->bitmap.vbuf_slot = 0; -} - - -/** - * Try to accumulate this glBitmap call in the bitmap cache. - * \return GL_TRUE for success, GL_FALSE if bitmap is too large, etc. - */ -static GLboolean -accum_bitmap(struct st_context *st, - GLint x, GLint y, GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, - const GLubyte *bitmap ) -{ - struct bitmap_cache *cache = st->bitmap.cache; - int px = -999, py = -999; - const GLfloat z = st->ctx->Current.RasterPos[2]; - - if (width > BITMAP_CACHE_WIDTH || - height > BITMAP_CACHE_HEIGHT) - return GL_FALSE; /* too big to cache */ - - if (!cache->empty) { - px = x - cache->xpos; /* pos in buffer */ - py = y - cache->ypos; - if (px < 0 || px + width > BITMAP_CACHE_WIDTH || - py < 0 || py + height > BITMAP_CACHE_HEIGHT || - !TEST_EQ_4V(st->ctx->Current.RasterColor, cache->color) || - ((fabs(z - cache->zpos) > Z_EPSILON))) { - /* This bitmap would extend beyond cache bounds, or the bitmap - * color is changing - * so flush and continue. - */ - st_flush_bitmap_cache(st); - } - } - - if (cache->empty) { - /* Initialize. Center bitmap vertically in the buffer. */ - px = 0; - py = (BITMAP_CACHE_HEIGHT - height) / 2; - cache->xpos = x; - cache->ypos = y - py; - cache->zpos = z; - cache->empty = GL_FALSE; - COPY_4FV(cache->color, st->ctx->Current.RasterColor); - } - - assert(px != -999); - assert(py != -999); - - if (x < cache->xmin) - cache->xmin = x; - if (y < cache->ymin) - cache->ymin = y; - if (x + width > cache->xmax) - cache->xmax = x + width; - if (y + height > cache->ymax) - cache->ymax = y + height; - - /* create the transfer if needed */ - create_cache_trans(st); - - unpack_bitmap(st, px, py, width, height, unpack, bitmap, - cache->buffer, BITMAP_CACHE_WIDTH); - - return GL_TRUE; /* accumulated */ -} - - - -/** - * Called via ctx->Driver.Bitmap() - */ -static void -st_Bitmap(struct gl_context *ctx, GLint x, GLint y, - GLsizei width, GLsizei height, - const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) -{ - struct st_context *st = st_context(ctx); - struct pipe_resource *pt; - - if (width == 0 || height == 0) - return; - - st_validate_state(st); - - if (!st->bitmap.vs) { - /* create pass-through vertex shader now */ - const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, - TGSI_SEMANTIC_COLOR, - TGSI_SEMANTIC_GENERIC }; - const uint semantic_indexes[] = { 0, 0, 0 }; - st->bitmap.vs = util_make_vertex_passthrough_shader(st->pipe, 3, - semantic_names, - semantic_indexes); - } - - if (UseBitmapCache && accum_bitmap(st, x, y, width, height, unpack, bitmap)) - return; - - pt = make_bitmap_texture(ctx, width, height, unpack, bitmap); - if (pt) { - struct pipe_sampler_view *sv = - st_create_texture_sampler_view(st->pipe, pt); - - assert(pt->target == PIPE_TEXTURE_2D || pt->target == PIPE_TEXTURE_RECT); - - if (sv) { - draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2], - width, height, sv, - st->ctx->Current.RasterColor); - - pipe_sampler_view_reference(&sv, NULL); - } - - /* release/free the texture */ - pipe_resource_reference(&pt, NULL); - } -} - - -/** Per-context init */ -void -st_init_bitmap_functions(struct dd_function_table *functions) -{ - functions->Bitmap = st_Bitmap; -} - - -/** Per-context init */ -void -st_init_bitmap(struct st_context *st) -{ - struct pipe_sampler_state *sampler = &st->bitmap.samplers[0]; - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; - - /* init sampler state once */ - 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; - st->bitmap.samplers[1] = *sampler; - st->bitmap.samplers[1].normalized_coords = 1; - - /* init baseline rasterizer state once */ - memset(&st->bitmap.rasterizer, 0, sizeof(st->bitmap.rasterizer)); - st->bitmap.rasterizer.gl_rasterization_rules = 1; - - /* find a usable texture format */ - if (screen->is_format_supported(screen, PIPE_FORMAT_I8_UNORM, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - st->bitmap.tex_format = PIPE_FORMAT_I8_UNORM; - } - else if (screen->is_format_supported(screen, PIPE_FORMAT_A8_UNORM, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - st->bitmap.tex_format = PIPE_FORMAT_A8_UNORM; - } - else if (screen->is_format_supported(screen, PIPE_FORMAT_L8_UNORM, - PIPE_TEXTURE_2D, 0, - PIPE_BIND_SAMPLER_VIEW, 0)) { - st->bitmap.tex_format = PIPE_FORMAT_L8_UNORM; - } - else { - /* XXX support more formats */ - assert(0); - } - - /* alloc bitmap cache object */ - st->bitmap.cache = ST_CALLOC_STRUCT(bitmap_cache); - - reset_cache(st); -} - - -/** Per-context tear-down */ -void -st_destroy_bitmap(struct st_context *st) -{ - struct pipe_context *pipe = st->pipe; - struct bitmap_cache *cache = st->bitmap.cache; - - if (st->bitmap.vs) { - cso_delete_vertex_shader(st->cso_context, st->bitmap.vs); - st->bitmap.vs = NULL; - } - - if (st->bitmap.vbuf) { - pipe_resource_reference(&st->bitmap.vbuf, NULL); - st->bitmap.vbuf = NULL; - } - - if (cache) { - if (cache->trans) { - pipe_transfer_unmap(pipe, cache->trans); - pipe->transfer_destroy(pipe, cache->trans); - } - pipe_resource_reference(&st->bitmap.cache->texture, NULL); - free(st->bitmap.cache); - st->bitmap.cache = NULL; - } -} - -#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 "program/program.h" +#include "program/prog_print.h" + +#include "st_context.h" +#include "st_atom.h" +#include "st_atom_constbuf.h" +#include "st_program.h" +#include "st_cb_bitmap.h" +#include "st_texture.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "util/u_inlines.h" +#include "util/u_draw_quad.h" +#include "util/u_simple_shaders.h" +#include "program/prog_instruction.h" +#include "cso_cache/cso_context.h" + + +#if FEATURE_drawpix + +/** + * glBitmaps are drawn as textured quads. The user's bitmap pattern + * is stored in a texture image. An alpha8 texture format is used. + * The fragment shader samples a bit (texel) from the texture, then + * discards the fragment if the bit is off. + * + * Note that we actually store the inverse image of the bitmap to + * simplify the fragment program. An "on" bit gets stored as texel=0x0 + * and an "off" bit is stored as texel=0xff. Then we kill the + * fragment if the negated texel value is less than zero. + */ + + +/** + * The bitmap cache attempts to accumulate multiple glBitmap calls in a + * buffer which is then rendered en mass upon a flush, state change, etc. + * A wide, short buffer is used to target the common case of a series + * of glBitmap calls being used to draw text. + */ +static GLboolean UseBitmapCache = GL_TRUE; + + +#define BITMAP_CACHE_WIDTH 512 +#define BITMAP_CACHE_HEIGHT 32 + +struct bitmap_cache +{ + /** Window pos to render the cached image */ + GLint xpos, ypos; + /** Bounds of region used in window coords */ + GLint xmin, ymin, xmax, ymax; + + GLfloat color[4]; + + /** Bitmap's Z position */ + GLfloat zpos; + + struct pipe_resource *texture; + struct pipe_transfer *trans; + + GLboolean empty; + + /** An I8 texture image: */ + ubyte *buffer; +}; + + +/** Epsilon for Z comparisons */ +#define Z_EPSILON 1e-06 + + +/** + * Make fragment program for glBitmap: + * Sample the texture and kill the fragment if the bit is 0. + * This program will be combined with the user's fragment program. + */ +static struct st_fragment_program * +make_bitmap_fragment_program(struct gl_context *ctx, GLuint samplerIndex) +{ + struct st_context *st = st_context(ctx); + struct st_fragment_program *stfp; + struct gl_program *p; + GLuint ic = 0; + + p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0); + if (!p) + return NULL; + + p->NumInstructions = 3; + + p->Instructions = _mesa_alloc_instructions(p->NumInstructions); + if (!p->Instructions) { + ctx->Driver.DeleteProgram(ctx, p); + return NULL; + } + _mesa_init_instructions(p->Instructions, p->NumInstructions); + + /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY; + p->Instructions[ic].DstReg.Index = 0; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = samplerIndex; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + + /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */ + p->Instructions[ic].Opcode = OPCODE_KIL; + p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY; + + if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM) + p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_XXXX; + + p->Instructions[ic].SrcReg[0].Index = 0; + p->Instructions[ic].SrcReg[0].Negate = NEGATE_XYZW; + ic++; + + /* END; */ + p->Instructions[ic++].Opcode = OPCODE_END; + + assert(ic == p->NumInstructions); + + p->InputsRead = FRAG_BIT_TEX0; + p->OutputsWritten = 0x0; + p->SamplersUsed = (1 << samplerIndex); + + stfp = (struct st_fragment_program *) p; + stfp->Base.UsesKill = GL_TRUE; + + return stfp; +} + + +static int +find_free_bit(uint bitfield) +{ + int i; + for (i = 0; i < 32; i++) { + if ((bitfield & (1 << i)) == 0) { + return i; + } + } + return -1; +} + + +/** + * Combine basic bitmap fragment program with the user-defined program. + * \param st current context + * \param fpIn the incoming fragment program + * \param fpOut the new fragment program which does fragment culling + * \param bitmap_sampler sampler number for the bitmap texture + */ +void +st_make_bitmap_fragment_program(struct st_context *st, + struct gl_fragment_program *fpIn, + struct gl_fragment_program **fpOut, + GLuint *bitmap_sampler) +{ + struct st_fragment_program *bitmap_prog; + struct gl_program *newProg; + uint sampler; + + /* + * Generate new program which is the user-defined program prefixed + * with the bitmap sampler/kill instructions. + */ + sampler = find_free_bit(fpIn->Base.SamplersUsed); + bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler); + + newProg = _mesa_combine_programs(st->ctx, + &bitmap_prog->Base.Base, + &fpIn->Base); + /* done with this after combining */ + st_reference_fragprog(st, &bitmap_prog, NULL); + +#if 0 + { + printf("Combined bitmap 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 + + /* return results */ + *fpOut = (struct gl_fragment_program *) newProg; + *bitmap_sampler = sampler; +} + + +/** + * Copy user-provide bitmap bits into texture buffer, expanding + * bits into texels. + * "On" bits will set texels to 0x0. + * "Off" bits will not modify texels. + * Note that the image is actually going to be upside down in + * the texture. We deal with that with texcoords. + */ +static void +unpack_bitmap(struct st_context *st, + GLint px, GLint py, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap, + ubyte *destBuffer, uint destStride) +{ + destBuffer += py * destStride + px; + + _mesa_expand_bitmap(width, height, unpack, bitmap, + destBuffer, destStride, 0x0); +} + + +/** + * Create a texture which represents a bitmap image. + */ +static struct pipe_resource * +make_bitmap_texture(struct gl_context *ctx, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct pipe_transfer *transfer; + ubyte *dest; + struct pipe_resource *pt; + + /* PBO source... */ + bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap); + if (!bitmap) { + return NULL; + } + + /** + * Create texture to hold bitmap pattern. + */ + pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format, + 0, width, height, 1, 1, + PIPE_BIND_SAMPLER_VIEW); + if (!pt) { + _mesa_unmap_pbo_source(ctx, unpack); + return NULL; + } + + transfer = pipe_get_transfer(st->pipe, pt, 0, 0, + PIPE_TRANSFER_WRITE, + 0, 0, width, height); + + dest = pipe_transfer_map(pipe, transfer); + + /* Put image into texture transfer */ + memset(dest, 0xff, height * transfer->stride); + unpack_bitmap(st, 0, 0, width, height, unpack, bitmap, + dest, transfer->stride); + + _mesa_unmap_pbo_source(ctx, unpack); + + /* Release transfer */ + pipe_transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); + + return pt; +} + +static GLuint +setup_bitmap_vertex_data(struct st_context *st, bool normalized, + int x, int y, int width, int height, + float z, const float color[4]) +{ + struct pipe_context *pipe = st->pipe; + const struct gl_framebuffer *fb = st->ctx->DrawBuffer; + const GLfloat fb_width = (GLfloat)fb->Width; + const GLfloat fb_height = (GLfloat)fb->Height; + const GLfloat x0 = (GLfloat)x; + const GLfloat x1 = (GLfloat)(x + width); + const GLfloat y0 = (GLfloat)y; + const GLfloat y1 = (GLfloat)(y + height); + GLfloat sLeft = (GLfloat)0.0, sRight = (GLfloat)1.0; + GLfloat tTop = (GLfloat)0.0, tBot = (GLfloat)1.0 - tTop; + 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); + const GLuint max_slots = 1; /* 4096 / sizeof(st->bitmap.vertices); */ + GLuint i; + + if(!normalized) + { + sRight = width; + tBot = height; + } + + /* 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. + */ + if (st->bitmap.vbuf_slot >= max_slots) { + pipe_resource_reference(&st->bitmap.vbuf, NULL); + st->bitmap.vbuf_slot = 0; + } + + if (!st->bitmap.vbuf) { + st->bitmap.vbuf = pipe_buffer_create(pipe->screen, + PIPE_BIND_VERTEX_BUFFER, + PIPE_USAGE_STREAM, + max_slots * + sizeof(st->bitmap.vertices)); + } + + /* Positions are in clip coords since we need to do clipping in case + * the bitmap quad goes beyond the window bounds. + */ + st->bitmap.vertices[0][0][0] = clip_x0; + st->bitmap.vertices[0][0][1] = clip_y0; + st->bitmap.vertices[0][2][0] = sLeft; + st->bitmap.vertices[0][2][1] = tTop; + + st->bitmap.vertices[1][0][0] = clip_x1; + st->bitmap.vertices[1][0][1] = clip_y0; + st->bitmap.vertices[1][2][0] = sRight; + st->bitmap.vertices[1][2][1] = tTop; + + st->bitmap.vertices[2][0][0] = clip_x1; + st->bitmap.vertices[2][0][1] = clip_y1; + st->bitmap.vertices[2][2][0] = sRight; + st->bitmap.vertices[2][2][1] = tBot; + + st->bitmap.vertices[3][0][0] = clip_x0; + st->bitmap.vertices[3][0][1] = clip_y1; + st->bitmap.vertices[3][2][0] = sLeft; + st->bitmap.vertices[3][2][1] = tBot; + + /* same for all verts: */ + for (i = 0; i < 4; i++) { + st->bitmap.vertices[i][0][2] = z; + st->bitmap.vertices[i][0][3] = 1.0; + st->bitmap.vertices[i][1][0] = color[0]; + st->bitmap.vertices[i][1][1] = color[1]; + st->bitmap.vertices[i][1][2] = color[2]; + st->bitmap.vertices[i][1][3] = color[3]; + st->bitmap.vertices[i][2][2] = 0.0; /*R*/ + st->bitmap.vertices[i][2][3] = 1.0; /*Q*/ + } + + /* put vertex data into vbuf */ + pipe_buffer_write_nooverlap(st->pipe, + st->bitmap.vbuf, + st->bitmap.vbuf_slot + * sizeof(st->bitmap.vertices), + sizeof st->bitmap.vertices, + st->bitmap.vertices); + + return st->bitmap.vbuf_slot++ * sizeof st->bitmap.vertices; +} + + + +/** + * Render a glBitmap by drawing a textured quad + */ +static void +draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, + GLsizei width, GLsizei height, + struct pipe_sampler_view *sv, + const GLfloat *color) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + struct cso_context *cso = st->cso_context; + struct st_fp_variant *fpv; + struct st_fp_variant_key key; + GLuint maxSize; + GLuint offset; + + memset(&key, 0, sizeof(key)); + key.st = st; + key.bitmap = GL_TRUE; + + fpv = st_get_fp_variant(st, st->fp, &key); + + /* As an optimization, Mesa's fragment programs will sometimes get the + * primary color from a statevar/constant rather than a varying variable. + * when that's the case, we need to ensure that we use the 'color' + * parameter and not the current attribute color (which may have changed + * through glRasterPos and state validation. + * So, we force the proper color here. Not elegant, but it works. + */ + { + GLfloat colorSave[4]; + COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]); + COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color); + st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); + COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave); + } + + + /* limit checks */ + /* XXX if the bitmap is larger than the 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 <= (GLsizei)maxSize); + assert(height <= (GLsizei)maxSize); + + cso_save_rasterizer(cso); + cso_save_samplers(cso); + cso_save_fragment_sampler_views(cso); + cso_save_viewport(cso); + cso_save_fragment_shader(cso); + cso_save_vertex_shader(cso); + cso_save_vertex_elements(cso); + cso_save_vertex_buffers(cso); + + /* rasterizer state: just scissor */ + st->bitmap.rasterizer.scissor = ctx->Scissor.Enabled; + cso_set_rasterizer(cso, &st->bitmap.rasterizer); + + /* fragment shader state: TEX lookup program */ + cso_set_fragment_shader_handle(cso, fpv->driver_shader); + + /* vertex shader state: position + texcoord pass-through */ + cso_set_vertex_shader_handle(cso, st->bitmap.vs); + + /* user samplers, plus our bitmap sampler */ + { + struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; + uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_samplers); + uint i; + for (i = 0; i < st->state.num_samplers; i++) { + samplers[i] = &st->state.samplers[i]; + } + samplers[fpv->bitmap_sampler] = + &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT]; + cso_set_samplers(cso, num, (const struct pipe_sampler_state **) samplers); + } + + /* user textures, plus the bitmap texture */ + { + struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; + uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_textures); + memcpy(sampler_views, st->state.sampler_views, sizeof(sampler_views)); + sampler_views[fpv->bitmap_sampler] = sv; + cso_set_fragment_sampler_views(cso, num, sampler_views); + } + + /* 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] = 0.5f; + vp.scale[3] = 1.0f; + vp.translate[0] = 0.5f * width; + vp.translate[1] = 0.5f * height; + 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); + + /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ + z = z * 2.0 - 1.0; + + /* draw textured quad */ + offset = setup_bitmap_vertex_data(st, + sv->texture->target != PIPE_TEXTURE_RECT, + x, y, width, height, z, color); + + util_draw_vertex_buffer(pipe, st->cso_context, st->bitmap.vbuf, offset, + PIPE_PRIM_TRIANGLE_FAN, + 4, /* verts */ + 3); /* attribs/vert */ + + + /* restore state */ + cso_restore_rasterizer(cso); + cso_restore_samplers(cso); + cso_restore_fragment_sampler_views(cso); + cso_restore_viewport(cso); + cso_restore_fragment_shader(cso); + cso_restore_vertex_shader(cso); + cso_restore_vertex_elements(cso); + cso_restore_vertex_buffers(cso); +} + + +static void +reset_cache(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + struct bitmap_cache *cache = st->bitmap.cache; + + /*memset(cache->buffer, 0xff, sizeof(cache->buffer));*/ + cache->empty = GL_TRUE; + + cache->xmin = 1000000; + cache->xmax = -1000000; + cache->ymin = 1000000; + cache->ymax = -1000000; + + if (cache->trans) { + pipe->transfer_destroy(pipe, cache->trans); + cache->trans = NULL; + } + + assert(!cache->texture); + + /* allocate a new texture */ + cache->texture = st_texture_create(st, PIPE_TEXTURE_2D, + st->bitmap.tex_format, 0, + BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, + 1, 1, + PIPE_BIND_SAMPLER_VIEW); +} + + +/** Print bitmap image to stdout (debug) */ +static void +print_cache(const struct bitmap_cache *cache) +{ + int i, j, k; + + for (i = 0; i < BITMAP_CACHE_HEIGHT; i++) { + k = BITMAP_CACHE_WIDTH * (BITMAP_CACHE_HEIGHT - i - 1); + for (j = 0; j < BITMAP_CACHE_WIDTH; j++) { + if (cache->buffer[k]) + printf("X"); + else + printf(" "); + k++; + } + printf("\n"); + } +} + + +/** + * Create gallium pipe_transfer object for the bitmap cache. + */ +static void +create_cache_trans(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + struct bitmap_cache *cache = st->bitmap.cache; + + if (cache->trans) + return; + + /* Map the texture transfer. + * Subsequent glBitmap calls will write into the texture image. + */ + cache->trans = pipe_get_transfer(st->pipe, cache->texture, 0, 0, + PIPE_TRANSFER_WRITE, 0, 0, + BITMAP_CACHE_WIDTH, + BITMAP_CACHE_HEIGHT); + cache->buffer = pipe_transfer_map(pipe, cache->trans); + + /* init image to all 0xff */ + memset(cache->buffer, 0xff, cache->trans->stride * BITMAP_CACHE_HEIGHT); +} + + +/** + * If there's anything in the bitmap cache, draw/flush it now. + */ +void +st_flush_bitmap_cache(struct st_context *st) +{ + if (!st->bitmap.cache->empty) { + struct bitmap_cache *cache = st->bitmap.cache; + + if (st->ctx->DrawBuffer) { + struct pipe_context *pipe = st->pipe; + struct pipe_sampler_view *sv; + + assert(cache->xmin <= cache->xmax); + +/* printf("flush size %d x %d at %d, %d\n", + cache->xmax - cache->xmin, + cache->ymax - cache->ymin, + cache->xpos, cache->ypos); +*/ + + /* The texture transfer has been mapped until now. + * So unmap and release the texture transfer before drawing. + */ + if (cache->trans) { + if (0) + print_cache(cache); + pipe_transfer_unmap(pipe, cache->trans); + cache->buffer = NULL; + + pipe->transfer_destroy(pipe, cache->trans); + cache->trans = NULL; + } + + sv = st_create_texture_sampler_view(st->pipe, cache->texture); + if (sv) { + draw_bitmap_quad(st->ctx, + cache->xpos, + cache->ypos, + cache->zpos, + BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, + sv, + cache->color); + + pipe_sampler_view_reference(&sv, NULL); + } + } + + /* release/free the texture */ + pipe_resource_reference(&cache->texture, NULL); + + reset_cache(st); + } +} + + +/** + * Flush bitmap cache and release vertex buffer. + */ +void +st_flush_bitmap( struct st_context *st ) +{ + st_flush_bitmap_cache(st); + + /* Release vertex buffer to avoid synchronous rendering if we were + * to map it in the next frame. + */ + pipe_resource_reference(&st->bitmap.vbuf, NULL); + st->bitmap.vbuf_slot = 0; +} + + +/** + * Try to accumulate this glBitmap call in the bitmap cache. + * \return GL_TRUE for success, GL_FALSE if bitmap is too large, etc. + */ +static GLboolean +accum_bitmap(struct st_context *st, + GLint x, GLint y, GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, + const GLubyte *bitmap ) +{ + struct bitmap_cache *cache = st->bitmap.cache; + int px = -999, py = -999; + const GLfloat z = st->ctx->Current.RasterPos[2]; + + if (width > BITMAP_CACHE_WIDTH || + height > BITMAP_CACHE_HEIGHT) + return GL_FALSE; /* too big to cache */ + + if (!cache->empty) { + px = x - cache->xpos; /* pos in buffer */ + py = y - cache->ypos; + if (px < 0 || px + width > BITMAP_CACHE_WIDTH || + py < 0 || py + height > BITMAP_CACHE_HEIGHT || + !TEST_EQ_4V(st->ctx->Current.RasterColor, cache->color) || + ((fabs(z - cache->zpos) > Z_EPSILON))) { + /* This bitmap would extend beyond cache bounds, or the bitmap + * color is changing + * so flush and continue. + */ + st_flush_bitmap_cache(st); + } + } + + if (cache->empty) { + /* Initialize. Center bitmap vertically in the buffer. */ + px = 0; + py = (BITMAP_CACHE_HEIGHT - height) / 2; + cache->xpos = x; + cache->ypos = y - py; + cache->zpos = z; + cache->empty = GL_FALSE; + COPY_4FV(cache->color, st->ctx->Current.RasterColor); + } + + assert(px != -999); + assert(py != -999); + + if (x < cache->xmin) + cache->xmin = x; + if (y < cache->ymin) + cache->ymin = y; + if (x + width > cache->xmax) + cache->xmax = x + width; + if (y + height > cache->ymax) + cache->ymax = y + height; + + /* create the transfer if needed */ + create_cache_trans(st); + + unpack_bitmap(st, px, py, width, height, unpack, bitmap, + cache->buffer, BITMAP_CACHE_WIDTH); + + return GL_TRUE; /* accumulated */ +} + + + +/** + * Called via ctx->Driver.Bitmap() + */ +static void +st_Bitmap(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, + const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap ) +{ + struct st_context *st = st_context(ctx); + struct pipe_resource *pt; + + if (width == 0 || height == 0) + return; + + st_validate_state(st); + + if (!st->bitmap.vs) { + /* create pass-through vertex shader now */ + const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_COLOR, + TGSI_SEMANTIC_GENERIC }; + const uint semantic_indexes[] = { 0, 0, 0 }; + st->bitmap.vs = util_make_vertex_passthrough_shader(st->pipe, 3, + semantic_names, + semantic_indexes); + } + + if (UseBitmapCache && accum_bitmap(st, x, y, width, height, unpack, bitmap)) + return; + + pt = make_bitmap_texture(ctx, width, height, unpack, bitmap); + if (pt) { + struct pipe_sampler_view *sv = + st_create_texture_sampler_view(st->pipe, pt); + + assert(pt->target == PIPE_TEXTURE_2D || pt->target == PIPE_TEXTURE_RECT); + + if (sv) { + draw_bitmap_quad(ctx, x, y, ctx->Current.RasterPos[2], + width, height, sv, + st->ctx->Current.RasterColor); + + pipe_sampler_view_reference(&sv, NULL); + } + + /* release/free the texture */ + pipe_resource_reference(&pt, NULL); + } +} + + +/** Per-context init */ +void +st_init_bitmap_functions(struct dd_function_table *functions) +{ + functions->Bitmap = st_Bitmap; +} + + +/** Per-context init */ +void +st_init_bitmap(struct st_context *st) +{ + struct pipe_sampler_state *sampler = &st->bitmap.samplers[0]; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + + /* init sampler state once */ + 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; + st->bitmap.samplers[1] = *sampler; + st->bitmap.samplers[1].normalized_coords = 1; + + /* init baseline rasterizer state once */ + memset(&st->bitmap.rasterizer, 0, sizeof(st->bitmap.rasterizer)); + st->bitmap.rasterizer.gl_rasterization_rules = 1; + + /* find a usable texture format */ + if (screen->is_format_supported(screen, PIPE_FORMAT_I8_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) { + st->bitmap.tex_format = PIPE_FORMAT_I8_UNORM; + } + else if (screen->is_format_supported(screen, PIPE_FORMAT_A8_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) { + st->bitmap.tex_format = PIPE_FORMAT_A8_UNORM; + } + else if (screen->is_format_supported(screen, PIPE_FORMAT_L8_UNORM, + PIPE_TEXTURE_2D, 0, + PIPE_BIND_SAMPLER_VIEW, 0)) { + st->bitmap.tex_format = PIPE_FORMAT_L8_UNORM; + } + else { + /* XXX support more formats */ + assert(0); + } + + /* alloc bitmap cache object */ + st->bitmap.cache = ST_CALLOC_STRUCT(bitmap_cache); + + reset_cache(st); +} + + +/** Per-context tear-down */ +void +st_destroy_bitmap(struct st_context *st) +{ + struct pipe_context *pipe = st->pipe; + struct bitmap_cache *cache = st->bitmap.cache; + + if (st->bitmap.vs) { + cso_delete_vertex_shader(st->cso_context, st->bitmap.vs); + st->bitmap.vs = NULL; + } + + if (st->bitmap.vbuf) { + pipe_resource_reference(&st->bitmap.vbuf, NULL); + st->bitmap.vbuf = NULL; + } + + if (cache) { + if (cache->trans) { + pipe_transfer_unmap(pipe, cache->trans); + pipe->transfer_destroy(pipe, cache->trans); + } + pipe_resource_reference(&st->bitmap.cache->texture, NULL); + free(st->bitmap.cache); + st->bitmap.cache = NULL; + } +} + +#endif /* FEATURE_drawpix */ diff --git a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c index ba8a8cf89..12528f49f 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c +++ b/mesalib/src/mesa/state_tracker/st_cb_bufferobjects.c @@ -1,447 +1,468 @@ -/************************************************************************** - * - * 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, - GLenum target, - 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, - GLenum target, - 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 buffer_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: - buffer_usage = PIPE_BIND_RENDER_TARGET; - break; - case GL_ARRAY_BUFFER_ARB: - buffer_usage = PIPE_BIND_VERTEX_BUFFER; - break; - case GL_ELEMENT_ARRAY_BUFFER_ARB: - buffer_usage = PIPE_BIND_INDEX_BUFFER; - break; - default: - buffer_usage = 0; - } - - pipe_resource_reference( &st_obj->buffer, NULL ); - - if (size != 0) { - st_obj->buffer = pipe_buffer_create(pipe->screen, buffer_usage, size); - - if (!st_obj->buffer) { - return GL_FALSE; - } - - if (data) - pipe_buffer_write(st_context(ctx)->pipe, st_obj->buffer, 0, - size, data); - return GL_TRUE; - } - - return GL_TRUE; -} - - -/** - * Dummy data whose's pointer is used for zero size buffers or ranges. - */ -static long st_bufferobj_zero_length = 0; - - - -/** - * Called via glMapBufferARB(). - */ -static void * -st_bufferobj_map(struct gl_context *ctx, GLenum target, GLenum access, - struct gl_buffer_object *obj) -{ - struct st_buffer_object *st_obj = st_buffer_object(obj); - uint flags; - - switch (access) { - case GL_WRITE_ONLY: - flags = PIPE_TRANSFER_WRITE; - break; - case GL_READ_ONLY: - flags = PIPE_TRANSFER_READ; - break; - case GL_READ_WRITE: - default: - flags = PIPE_TRANSFER_READ_WRITE; - break; - } - - /* Handle zero-size buffers here rather than in drivers */ - if (obj->Size == 0) { - obj->Pointer = &st_bufferobj_zero_length; - } - else { - obj->Pointer = pipe_buffer_map(st_context(ctx)->pipe, - st_obj->buffer, - flags, - &st_obj->transfer); - } - - if (obj->Pointer) { - obj->Offset = 0; - obj->Length = obj->Size; - } - return obj->Pointer; -} - - -/** - * Called via glMapBufferRange(). - */ -static void * -st_bufferobj_map_range(struct gl_context *ctx, GLenum target, - 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_RANGE_BIT) - flags |= PIPE_TRANSFER_DISCARD; - - if (access & GL_MAP_INVALIDATE_BUFFER_BIT) - flags |= PIPE_TRANSFER_DISCARD; - - 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); - - /* - * We go out of way here to hide the degenerate yet valid case of zero - * length range from the pipe driver. - */ - if (!length) { - obj->Pointer = &st_bufferobj_zero_length; - } - else { - 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, GLenum target, - 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, GLenum target, 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_transfer *src_transfer; - struct pipe_transfer *dst_transfer; - ubyte *srcPtr, *dstPtr; - - if(!size) - return; - - /* buffer should not already be mapped */ - assert(!src->Pointer); - assert(!dst->Pointer); - - srcPtr = (ubyte *) pipe_buffer_map_range(pipe, - srcObj->buffer, - readOffset, size, - PIPE_TRANSFER_READ, - &src_transfer); - - dstPtr = (ubyte *) pipe_buffer_map_range(pipe, - dstObj->buffer, - writeOffset, size, - PIPE_TRANSFER_WRITE, - &dst_transfer); - - if (srcPtr && dstPtr) - memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); - - pipe_buffer_unmap(pipe, src_transfer); - pipe_buffer_unmap(pipe, dst_transfer); -} - - -/* 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->MapBuffer = st_bufferobj_map; - 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, + GLenum target, + 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, + GLenum target, + 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(st_context(ctx)->pipe, st_obj->buffer, 0, + size, data); + return GL_TRUE; + } + + return GL_TRUE; +} + + +/** + * Dummy data whose's pointer is used for zero size buffers or ranges. + */ +static long st_bufferobj_zero_length = 0; + + + +/** + * Called via glMapBufferARB(). + */ +static void * +st_bufferobj_map(struct gl_context *ctx, GLenum target, GLenum access, + struct gl_buffer_object *obj) +{ + struct st_buffer_object *st_obj = st_buffer_object(obj); + uint flags; + + switch (access) { + case GL_WRITE_ONLY: + flags = PIPE_TRANSFER_WRITE; + break; + case GL_READ_ONLY: + flags = PIPE_TRANSFER_READ; + break; + case GL_READ_WRITE: + default: + flags = PIPE_TRANSFER_READ_WRITE; + break; + } + + /* Handle zero-size buffers here rather than in drivers */ + if (obj->Size == 0) { + obj->Pointer = &st_bufferobj_zero_length; + } + else { + obj->Pointer = pipe_buffer_map(st_context(ctx)->pipe, + st_obj->buffer, + flags, + &st_obj->transfer); + } + + if (obj->Pointer) { + obj->Offset = 0; + obj->Length = obj->Size; + } + return obj->Pointer; +} + + +/** + * Called via glMapBufferRange(). + */ +static void * +st_bufferobj_map_range(struct gl_context *ctx, GLenum target, + 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_RANGE_BIT) + flags |= PIPE_TRANSFER_DISCARD; + + if (access & GL_MAP_INVALIDATE_BUFFER_BIT) + flags |= PIPE_TRANSFER_DISCARD; + + 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); + + /* + * We go out of way here to hide the degenerate yet valid case of zero + * length range from the pipe driver. + */ + if (!length) { + obj->Pointer = &st_bufferobj_zero_length; + } + else { + 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, GLenum target, + 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, GLenum target, 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_transfer *src_transfer; + struct pipe_transfer *dst_transfer; + ubyte *srcPtr, *dstPtr; + + if(!size) + return; + + /* buffer should not already be mapped */ + assert(!src->Pointer); + assert(!dst->Pointer); + + srcPtr = (ubyte *) pipe_buffer_map_range(pipe, + srcObj->buffer, + readOffset, size, + PIPE_TRANSFER_READ, + &src_transfer); + + dstPtr = (ubyte *) pipe_buffer_map_range(pipe, + dstObj->buffer, + writeOffset, size, + PIPE_TRANSFER_WRITE, + &dst_transfer); + + if (srcPtr && dstPtr) + memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); + + pipe_buffer_unmap(pipe, src_transfer); + pipe_buffer_unmap(pipe, dst_transfer); +} + + +/* 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->MapBuffer = st_bufferobj_map; + 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 3e27be271..d2e0cd73c 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_clear.c +++ b/mesalib/src/mesa/state_tracker/st_cb_clear.c @@ -1,559 +1,563 @@ -/************************************************************************** - * - * 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 - * 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_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_context *pipe = st->pipe; - 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); - - /* fragment shader state: color pass-through program */ - st->clear.fs = util_make_fragment_passthrough_shader(pipe); - - /* vertex shader state: color/position pass-through */ - { - const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, - TGSI_SEMANTIC_COLOR }; - const uint semantic_indexes[] = { 0, 0 }; - st->clear.vs = util_make_vertex_passthrough_shader(pipe, 2, - semantic_names, - semantic_indexes); - } -} - - -/** - * 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; - } -} - - -/** - * 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, - 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->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; - - /* - 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); - - /* 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); - cso_set_fragment_shader_handle(st->cso_context, st->clear.fs); - cso_set_vertex_shader_handle(st->cso_context, st->clear.vs); - - /* draw quad matching scissor rect (XXX verify coord round-off) */ - draw_quad(st, x0, y0, x1, y1, - (GLfloat) ctx->Depth.Clear, ctx->Color.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); -} - - -/** - * 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); - - 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); - - 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. - */ - 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; - st->pipe->clear(st->pipe, clear_buffers, ctx->Color.ClearColor, - 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 + * 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_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_context *pipe = st->pipe; + 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); + + /* fragment shader state: color pass-through program */ + st->clear.fs = util_make_fragment_passthrough_shader(pipe); + + /* vertex shader state: color/position pass-through */ + { + const uint semantic_names[] = { TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_COLOR }; + const uint semantic_indexes[] = { 0, 0 }; + st->clear.vs = util_make_vertex_passthrough_shader(pipe, 2, + semantic_names, + semantic_indexes); + } +} + + +/** + * 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; + } +} + + +/** + * 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; + + /* + 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); + cso_set_fragment_shader_handle(st->cso_context, st->clear.fs); + cso_set_vertex_shader_handle(st->cso_context, st->clear.vs); + + /* draw quad matching scissor rect (XXX verify coord round-off) */ + draw_quad(st, x0, y0, x1, y1, + (GLfloat) ctx->Depth.Clear, ctx->Color.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); + + 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); + + 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. + */ + 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; + st->pipe->clear(st->pipe, clear_buffers, ctx->Color.ClearColor, + 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 56c7e8581..07527002b 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawpixels.c @@ -1,1368 +1,1371 @@ -/************************************************************************** - * - * 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/texformat.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; -} - - - -/** - * 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; - - if (is_passthrough_program(fpIn)) { - newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, - &st->pixel_xfer.program->Base); - } - 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 |= (1 << FRAG_RESULT_DEPTH); - if (write_stencil) - p->OutputsWritten |= (1 << 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 base format for drawing/copying an image - * of the given format. - */ -static GLenum -base_format(GLenum format) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; - case GL_STENCIL_INDEX: - return GL_STENCIL_INDEX; - default: - return GL_RGBA; - } -} - - -/** - * Return a texture internalFormat for drawing/copying an image - * of the given format and type. - */ -static GLenum -internal_format(GLenum format, GLenum type) -{ - switch (format) { - case GL_DEPTH_COMPONENT: - return GL_DEPTH_COMPONENT; - case GL_DEPTH_STENCIL: - return GL_DEPTH_STENCIL; - 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 { - return GL_RGBA; - } - } -} - - -/** - * 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; - GLuint cpp; - GLenum baseFormat, intFormat; - - baseFormat = base_format(format); - intFormat = internal_format(format, type); - - mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, - format, type, GL_FALSE); - assert(mformat); - - pipeFormat = st_mesa_format_to_pipe_format(mformat); - assert(pipeFormat); - cpp = util_format_get_blocksize(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 */ - baseFormat, /* 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, - sizeof(verts)); - pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); - - util_draw_vertex_buffer(pipe, 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); - 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.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); - 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(st_context(ctx)->pipe, strb->texture, 0, 0, - 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]; - 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) { - _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, 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; - 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; - enum pipe_format stencil_format = PIPE_FORMAT_NONE; - 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) { - enum pipe_format tex_format; - /* can we write to stencil if not fallback */ - if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) - goto stencil_fallback; - - tex_format = st_choose_format(st->pipe->screen, base_format(format), - PIPE_TEXTURE_2D, - 0, PIPE_BIND_SAMPLER_VIEW); - if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) - stencil_format = PIPE_FORMAT_X24S8_USCALED; - else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) - stencil_format = PIPE_FORMAT_S8X24_USCALED; - else - stencil_format = PIPE_FORMAT_S8_USCALED; - if (stencil_format == PIPE_FORMAT_NONE) - goto stencil_fallback; - } - - /* 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]) { - if (write_stencil) { - 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); - } - } - return; - -stencil_fallback: - draw_stencil_pixels(ctx, x, y, width, height, format, type, - unpack, pixels); -} - - - -/** - * 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(st_context(ctx)->pipe, - rbDraw->texture, 0, 0, - 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; - default: - assert(0); - } - } - - free(buffer); - - /* unmap the stencil buffer */ - pipe_transfer_unmap(pipe, ptDraw); - pipe->transfer_destroy(pipe, ptDraw); -} - - -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; - } - - /* - * 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, 0)) { - texFormat = srcFormat; - } - else { - /* srcFormat can't be used as a texture format */ - if (type == GL_DEPTH) { - texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, - 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, 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, - pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ - rbRead->texture, /* src tex */ - 0, - &src_box); - - } - else { - /* CPU-based fallback/conversion */ - struct pipe_transfer *ptRead = - pipe_get_transfer(st->pipe, rbRead->texture, 0, 0, - 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, readX, readY, 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, readX, readY, 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/texformat.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; +} + + + +/** + * 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; + + if (is_passthrough_program(fpIn)) { + newProg = (struct gl_program *) _mesa_clone_fragment_program(st->ctx, + &st->pixel_xfer.program->Base); + } + 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 |= (1 << FRAG_RESULT_DEPTH); + if (write_stencil) + p->OutputsWritten |= (1 << 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 base format for drawing/copying an image + * of the given format. + */ +static GLenum +base_format(GLenum format) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + case GL_STENCIL_INDEX: + return GL_STENCIL_INDEX; + default: + return GL_RGBA; + } +} + + +/** + * Return a texture internalFormat for drawing/copying an image + * of the given format and type. + */ +static GLenum +internal_format(GLenum format, GLenum type) +{ + switch (format) { + case GL_DEPTH_COMPONENT: + return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + return GL_DEPTH_STENCIL; + 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 { + return GL_RGBA; + } + } +} + + +/** + * 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; + GLuint cpp; + GLenum baseFormat, intFormat; + + baseFormat = base_format(format); + intFormat = internal_format(format, type); + + mformat = st_ChooseTextureFormat_renderable(ctx, intFormat, + format, type, GL_FALSE); + assert(mformat); + + pipeFormat = st_mesa_format_to_pipe_format(mformat); + assert(pipeFormat); + cpp = util_format_get_blocksize(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 */ + baseFormat, /* 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.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(st_context(ctx)->pipe, strb->texture, 0, 0, + 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]; + 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) { + _mesa_unpack_depth_span(ctx, spanWidth, GL_UNSIGNED_INT, 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; + 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; + enum pipe_format stencil_format = PIPE_FORMAT_NONE; + 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) { + enum pipe_format tex_format; + /* can we write to stencil if not fallback */ + if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) + goto stencil_fallback; + + tex_format = st_choose_format(st->pipe->screen, base_format(format), + PIPE_TEXTURE_2D, + 0, PIPE_BIND_SAMPLER_VIEW); + if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) + stencil_format = PIPE_FORMAT_X24S8_USCALED; + else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) + stencil_format = PIPE_FORMAT_S8X24_USCALED; + else + stencil_format = PIPE_FORMAT_S8_USCALED; + if (stencil_format == PIPE_FORMAT_NONE) + goto stencil_fallback; + } + + /* 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]) { + if (write_stencil) { + 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); + } + } + return; + +stencil_fallback: + draw_stencil_pixels(ctx, x, y, width, height, format, type, + unpack, pixels); +} + + + +/** + * 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(st_context(ctx)->pipe, + rbDraw->texture, 0, 0, + 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; + default: + assert(0); + } + } + + free(buffer); + + /* unmap the stencil buffer */ + pipe_transfer_unmap(pipe, ptDraw); + pipe->transfer_destroy(pipe, ptDraw); +} + + +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; + } + + /* + * 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, 0)) { + texFormat = srcFormat; + } + else { + /* srcFormat can't be used as a texture format */ + if (type == GL_DEPTH) { + texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, + 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, 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, + pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ + rbRead->texture, /* src tex */ + 0, + &src_box); + + } + else { + /* CPU-based fallback/conversion */ + struct pipe_transfer *ptRead = + pipe_get_transfer(st->pipe, rbRead->texture, 0, 0, + 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, readX, readY, 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, readX, readY, 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 5976f1048..86ceb9d78 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_drawtex.c +++ b/mesalib/src/mesa/state_tracker/st_cb_drawtex.c @@ -1,304 +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, - 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); - - { - 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, 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); -} - - -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_context.c b/mesalib/src/mesa/state_tracker/st_context.c index dccbff3c1..7a19f35bb 100644 --- a/mesalib/src/mesa/state_tracker/st_context.c +++ b/mesalib/src/mesa/state_tracker/st_context.c @@ -203,6 +203,11 @@ static void st_destroy_context_priv( struct st_context *st ) st_destroy_drawpix(st); st_destroy_drawtex(st); + /* Unreference any user vertex buffers. */ + for (i = 0; i < st->num_user_vbs; i++) { + pipe_resource_reference(&st->user_vb[i], NULL); + } + for (i = 0; i < Elements(st->state.sampler_views); i++) { pipe_sampler_view_reference(&st->state.sampler_views[i], NULL); } diff --git a/mesalib/src/mesa/state_tracker/st_context.h b/mesalib/src/mesa/state_tracker/st_context.h index 492ee600e..77765f023 100644 --- a/mesalib/src/mesa/state_tracker/st_context.h +++ b/mesalib/src/mesa/state_tracker/st_context.h @@ -1,265 +1,270 @@ -/************************************************************************** - * - * 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 *sampler_list[PIPE_MAX_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_scissor_state scissor; - struct pipe_viewport_state viewport; - unsigned sample_mask; - - GLuint num_samplers; - GLuint num_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; -}; - - -/* 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 revalidate; -}; - - -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 *sampler_list[PIPE_MAX_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_scissor_state scissor; + struct pipe_viewport_state viewport; + unsigned sample_mask; + + GLuint num_samplers; + GLuint num_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 pipe_resource *user_vb[PIPE_MAX_ATTRIBS]; + unsigned user_vb_stride[PIPE_MAX_ATTRIBS]; + unsigned num_user_vbs; +}; + + +/* 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 revalidate; +}; + + +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 19466ea44..830e3e3c1 100644 --- a/mesalib/src/mesa/state_tracker/st_draw.c +++ b/mesalib/src/mesa/state_tracker/st_draw.c @@ -1,788 +1,749 @@ -/************************************************************************** - * - * 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_elements(), pipe->draw_range_elements() or pipe->draw_arrays(). - * - * Authors: - * Keith Whitwell - */ - - -#include "main/imports.h" -#include "main/image.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. - */ -GLuint -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); - assert(size >= 1); - assert(size <= 4); - assert(format == GL_RGBA || format == GL_BGRA); - - 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 0; /* silence compiler warning */ -} - - - - - -/** - * Examine the active arrays to determine if we have interleaved - * vertex arrays all living in one VBO, or all living in user space. - * \param userSpace returns whether the arrays are 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, - GLboolean *userSpace) -{ - GLuint attr; - const struct gl_buffer_object *firstBufObj = NULL; - GLint firstStride = -1; - GLuint num_client_arrays = 0; - const GLubyte *client_addr = NULL; - - for (attr = 0; attr < vpv->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj; - const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */ - - if (firstStride < 0) { - firstStride = stride; - } - else if (firstStride != stride) { - return GL_FALSE; - } - - if (!bufObj || !bufObj->Name) { - num_client_arrays++; - /* Try to detect if the client-space arrays are - * "close" to each other. - */ - if (!client_addr) { - client_addr = arrays[mesaAttr]->Ptr; - } - else if (abs(arrays[mesaAttr]->Ptr - client_addr) > firstStride) { - /* arrays start too far apart */ - return GL_FALSE; - } - } - else if (!firstBufObj) { - firstBufObj = bufObj; - } - else if (bufObj != firstBufObj) { - return GL_FALSE; - } - } - - *userSpace = (num_client_arrays == vpv->num_inputs); - /* debug_printf("user space: %s (%d arrays, %d inputs)\n", - (int)*userSpace ? "Yes" : "No", num_client_arrays, vp->num_inputs); */ - - return GL_TRUE; -} - - -/** - * Compute the memory range occupied by the arrays. - */ -static void -get_arrays_bounds(const struct st_vertex_program *vp, - const struct st_vp_variant *vpv, - const struct gl_client_array **arrays, - GLuint max_index, - const GLubyte **low, const GLubyte **high) -{ - const GLubyte *low_addr = NULL; - const GLubyte *high_addr = NULL; - GLuint attr; - - /* debug_printf("get_arrays_bounds: Handling %u attrs\n", vpv->num_inputs); */ - - for (attr = 0; attr < vpv->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - const GLint stride = arrays[mesaAttr]->StrideB; - const GLubyte *start = arrays[mesaAttr]->Ptr; - const unsigned sz = (arrays[mesaAttr]->Size * - _mesa_sizeof_type(arrays[mesaAttr]->Type)); - const GLubyte *end = start + (max_index * stride) + sz; - - /* debug_printf("attr %u: stride %d size %u start %p end %p\n", - attr, stride, sz, start, end); */ - - if (attr == 0) { - low_addr = start; - high_addr = end; - } - else { - low_addr = MIN2(low_addr, start); - high_addr = MAX2(high_addr, end); - } - } - - *low = low_addr; - *high = high_addr; -} - - -/** - * 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, - GLuint max_index, - GLboolean userSpace, - struct pipe_vertex_buffer *vbuffer, - struct pipe_vertex_element velements[]) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - GLuint attr; - const GLubyte *offset0 = NULL; - - for (attr = 0; attr < vpv->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; - struct st_buffer_object *stobj = st_buffer_object(bufobj); - GLsizei stride = arrays[mesaAttr]->StrideB; - - /*printf("stobj %u = %p\n", attr, (void*)stobj);*/ - - if (attr == 0) { - const GLubyte *low, *high; - - get_arrays_bounds(vp, vpv, arrays, max_index, &low, &high); - /* debug_printf("buffer range: %p %p range %d max index %u\n", - low, high, high - low, max_index); */ - - offset0 = low; - if (userSpace) { - vbuffer->buffer = - pipe_user_buffer_create(pipe->screen, (void *) low, high - low, - PIPE_BIND_VERTEX_BUFFER); - vbuffer->buffer_offset = 0; - } - else { - vbuffer->buffer = NULL; - pipe_resource_reference(&vbuffer->buffer, stobj->buffer); - vbuffer->buffer_offset = pointer_to_offset(low); - } - vbuffer->stride = stride; /* in bytes */ - vbuffer->max_index = max_index; - } - - /* - if (arrays[mesaAttr]->InstanceDivisor) - vbuffer[attr].max_index = arrays[mesaAttr]->_MaxElement; - else - vbuffer[attr].max_index = max_index; - */ - - velements[attr].src_offset = - (unsigned) (arrays[mesaAttr]->Ptr - offset0); - velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor; - velements[attr].vertex_buffer_index = 0; - velements[attr].src_format = - st_pipe_vertex_format(arrays[mesaAttr]->Type, - arrays[mesaAttr]->Size, - arrays[mesaAttr]->Format, - arrays[mesaAttr]->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, - GLuint max_index, - GLboolean *userSpace, - struct pipe_vertex_buffer vbuffer[], - struct pipe_vertex_element velements[]) -{ - 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]; - struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; - GLsizei stride = arrays[mesaAttr]->StrideB; - - *userSpace = GL_FALSE; - - if (bufobj && bufobj->Name) { - /* 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); - /*printf("stobj %u = %p\n", attr, (void*) stobj);*/ - - vbuffer[attr].buffer = NULL; - pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer); - vbuffer[attr].buffer_offset = pointer_to_offset(arrays[mesaAttr]->Ptr); - } - else { - /* attribute data is in user-space memory, not a VBO */ - uint bytes; - /*printf("user-space array %d stride %d\n", attr, stride);*/ - - *userSpace = GL_TRUE; - - /* wrap user data */ - if (arrays[mesaAttr]->Ptr) { - /* user's vertex array */ - if (arrays[mesaAttr]->StrideB) { - bytes = arrays[mesaAttr]->StrideB * (max_index + 1); - } - else { - bytes = arrays[mesaAttr]->Size - * _mesa_sizeof_type(arrays[mesaAttr]->Type); - } - vbuffer[attr].buffer = - pipe_user_buffer_create(pipe->screen, - (void *) arrays[mesaAttr]->Ptr, bytes, - PIPE_BIND_VERTEX_BUFFER); - } - else { - /* no array, use ctx->Current.Attrib[] value */ - bytes = sizeof(ctx->Current.Attrib[0]); - vbuffer[attr].buffer = - pipe_user_buffer_create(pipe->screen, - (void *) ctx->Current.Attrib[mesaAttr], - bytes, - PIPE_BIND_VERTEX_BUFFER); - stride = 0; - } - - vbuffer[attr].buffer_offset = 0; - } - - assert(velements[attr].src_offset <= 2048); /* 11-bit field */ - - /* common-case setup */ - vbuffer[attr].stride = stride; /* in bytes */ - if (arrays[mesaAttr]->InstanceDivisor) - vbuffer[attr].max_index = arrays[mesaAttr]->_MaxElement; - else - vbuffer[attr].max_index = max_index; - - velements[attr].src_offset = 0; - velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor; - velements[attr].vertex_buffer_index = attr; - velements[attr].src_format - = st_pipe_vertex_format(arrays[mesaAttr]->Type, - arrays[mesaAttr]->Size, - arrays[mesaAttr]->Format, - arrays[mesaAttr]->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 && bufobj->Name) { - /* 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 imporant 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; -} - - - -/** - * 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; - const struct st_vertex_program *vp; - const struct st_vp_variant *vpv; - struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS]; - GLuint attr; - struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; - unsigned num_vbuffers, num_velements; - struct pipe_index_buffer ibuffer; - GLboolean userSpace = GL_FALSE; - GLboolean vertDataEdgeFlags; - struct pipe_draw_info info; - unsigned i; - - /* Mesa core state should have been validated already */ - assert(ctx->NewState == 0x0); - - /* Gallium probably doesn't want this in some cases. */ - if (!index_bounds_valid) - if (!vbo_all_varyings_in_vbos(arrays)) - vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); - - /* 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); - - /* must get these after state validation! */ - vp = st->vp; - vpv = st->vp_variant; - -#if 0 - if (MESA_VERBOSE & VERBOSE_GLSL) { - check_uniforms(ctx); - } -#else - (void) check_uniforms; -#endif - - memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs); - /* - * Setup the vbuffer[] and velements[] arrays. - */ - if (is_interleaved_arrays(vp, vpv, arrays, &userSpace)) { - /*printf("Draw interleaved\n");*/ - setup_interleaved_attribs(ctx, vp, vpv, arrays, max_index, userSpace, - vbuffer, velements); - num_vbuffers = 1; - num_velements = vpv->num_inputs; - if (num_velements == 0) - num_vbuffers = 0; - } - else { - /*printf("Draw non-interleaved\n");*/ - setup_non_interleaved_attribs(ctx, vp, vpv, arrays, max_index, - &userSpace, vbuffer, velements); - num_vbuffers = vpv->num_inputs; - num_velements = vpv->num_inputs; - } - -#if 0 - { - GLuint i; - for (i = 0; i < num_vbuffers; i++) { - printf("buffers[%d].stride = %u\n", i, vbuffer[i].stride); - printf("buffers[%d].max_index = %u\n", i, vbuffer[i].max_index); - printf("buffers[%d].buffer_offset = %u\n", i, vbuffer[i].buffer_offset); - printf("buffers[%d].buffer = %p\n", i, (void*) vbuffer[i].buffer); - } - for (i = 0; i < num_velements; i++) { - printf("vlements[%d].vbuffer_index = %u\n", i, velements[i].vertex_buffer_index); - printf("vlements[%d].src_offset = %u\n", i, velements[i].src_offset); - printf("vlements[%d].format = %s\n", i, util_format_name(velements[i].src_format)); - } - } -#endif - - pipe->set_vertex_buffers(pipe, num_vbuffers, vbuffer); - cso_set_vertex_elements(st->cso_context, num_velements, velements); - - 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 = st->ctx->Array.PrimitiveRestart; - info.restart_index = st->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); - - /* unreference buffers (frees wrapped user-space buffer objects) */ - for (attr = 0; attr < num_vbuffers; attr++) { - pipe_resource_reference(&vbuffer[attr].buffer, NULL); - assert(!vbuffer[attr].buffer); - } - - if (userSpace) - { - pipe->set_vertex_buffers(pipe, 0, 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_elements(), pipe->draw_range_elements() or pipe->draw_arrays(). + * + * Authors: + * Keith Whitwell + */ + + +#include "main/imports.h" +#include "main/image.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. + */ +GLuint +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); + assert(size >= 1); + assert(size <= 4); + assert(format == GL_RGBA || format == GL_BGRA); + + 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 0; /* silence compiler warning */ +} + + + + + +/** + * Examine the active arrays to determine if we have interleaved + * vertex arrays all living in one VBO, or all living in user space. + * \param userSpace returns whether the arrays are 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 *client_addr = NULL; + + for (attr = 0; attr < vpv->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj; + const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */ + + if (firstStride < 0) { + firstStride = stride; + } + else if (firstStride != stride) { + return GL_FALSE; + } + + if (!bufObj || !bufObj->Name) { + /* Try to detect if the client-space arrays are + * "close" to each other. + */ + if (!client_addr) { + client_addr = arrays[mesaAttr]->Ptr; + } + else if (abs(arrays[mesaAttr]->Ptr - client_addr) > firstStride) { + /* arrays start too far apart */ + return GL_FALSE; + } + } + else if (!firstBufObj) { + firstBufObj = bufObj; + } + else if (bufObj != firstBufObj) { + return GL_FALSE; + } + } + + 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) +{ + struct st_context *st = st_context(ctx); + struct pipe_context *pipe = st->pipe; + GLuint attr; + const GLubyte *low_addr = NULL; + + /* Find the lowest address. */ + for (attr = 0; attr < vpv->num_inputs; attr++) { + const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr; + + low_addr = !low_addr ? start : MIN2(low_addr, start); + } + + for (attr = 0; attr < vpv->num_inputs; attr++) { + const GLuint mesaAttr = vp->index_to_input[attr]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + struct st_buffer_object *stobj = st_buffer_object(bufobj); + GLsizei stride = arrays[mesaAttr]->StrideB; + + if (attr == 0) { + if (bufobj && bufobj->Name) { + vbuffer->buffer = NULL; + pipe_resource_reference(&vbuffer->buffer, stobj->buffer); + vbuffer->buffer_offset = pointer_to_offset(low_addr); + } else { + vbuffer->buffer = + pipe_user_buffer_create(pipe->screen, (void*)low_addr, + stride * (max_index + 1), + PIPE_BIND_VERTEX_BUFFER); + vbuffer->buffer_offset = 0; + + /* Track user vertex buffers. */ + pipe_resource_reference(&st->user_vb[0], vbuffer->buffer); + st->user_vb_stride[0] = stride; + st->num_user_vbs = 1; + } + vbuffer->stride = stride; /* in bytes */ + } + + velements[attr].src_offset = + (unsigned) (arrays[mesaAttr]->Ptr - low_addr); + velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor; + velements[attr].vertex_buffer_index = 0; + velements[attr].src_format = + st_pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Format, + arrays[mesaAttr]->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) +{ + 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]; + struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; + GLsizei stride = arrays[mesaAttr]->StrideB; + + if (bufobj && bufobj->Name) { + /* 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(arrays[mesaAttr]->Ptr); + } + else { + /* wrap user data */ + if (arrays[mesaAttr]->Ptr) { + vbuffer[attr].buffer = + pipe_user_buffer_create(pipe->screen, + (void *) arrays[mesaAttr]->Ptr, + stride * (max_index + 1), + PIPE_BIND_VERTEX_BUFFER); + } + else { + /* no array, use ctx->Current.Attrib[] value */ + uint bytes = sizeof(ctx->Current.Attrib[0]); + vbuffer[attr].buffer = + pipe_user_buffer_create(pipe->screen, + (void *) ctx->Current.Attrib[mesaAttr], + bytes, + PIPE_BIND_VERTEX_BUFFER); + stride = 0; + } + + vbuffer[attr].buffer_offset = 0; + + /* Track user vertex buffers. */ + pipe_resource_reference(&st->user_vb[attr], vbuffer->buffer); + st->user_vb_stride[attr] = stride; + st->num_user_vbs = MAX2(st->num_user_vbs, attr+1); + } + + /* common-case setup */ + vbuffer[attr].stride = stride; /* in bytes */ + + velements[attr].src_offset = 0; + velements[attr].instance_divisor = arrays[mesaAttr]->InstanceDivisor; + velements[attr].vertex_buffer_index = attr; + velements[attr].src_format + = st_pipe_vertex_format(arrays[mesaAttr]->Type, + arrays[mesaAttr]->Size, + arrays[mesaAttr]->Format, + arrays[mesaAttr]->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 && bufobj->Name) { + /* 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 imporant 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) +{ + 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_vbs; i++) { + pipe_resource_reference(&st->user_vb[i], NULL); + } + st->num_user_vbs = 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_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_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; + GLboolean new_array = + st->dirty.st && (st->dirty.mesa & (_NEW_ARRAY | _NEW_PROGRAM)) != 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 (!vbo_all_varyings_in_vbos(arrays)) + vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index); + } 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); + } + } + + /* 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); + } + +#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. */ + if (!new_array && st->num_user_vbs) { + for (i = 0; i < st->num_user_vbs; i++) { + if (st->user_vb[i]) { + unsigned stride = st->user_vb_stride[i]; + + if (stride) { + pipe->redefine_user_buffer(pipe, st->user_vb[i], + min_index * stride, + (max_index + 1 - min_index) * stride); + } else { + /* stride == 0 */ + pipe->redefine_user_buffer(pipe, st->user_vb[i], + 0, st->user_vb[i]->width0); + } + } + } + } + + 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 = st->ctx->Array.PrimitiveRestart; + info.restart_index = st->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_draw_feedback.c b/mesalib/src/mesa/state_tracker/st_draw_feedback.c index 545b32d75..1e1220bfe 100644 --- a/mesalib/src/mesa/state_tracker/st_draw_feedback.c +++ b/mesalib/src/mesa/state_tracker/st_draw_feedback.c @@ -179,7 +179,6 @@ st_feedback_draw_vbo(struct gl_context *ctx, /* common-case setup */ vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ - vbuffers[attr].max_index = max_index; velements[attr].instance_divisor = 0; velements[attr].vertex_buffer_index = attr; velements[attr].src_format = diff --git a/mesalib/src/mesa/state_tracker/st_gen_mipmap.c b/mesalib/src/mesa/state_tracker/st_gen_mipmap.c index 0be66a2c2..18eb3be68 100644 --- a/mesalib/src/mesa/state_tracker/st_gen_mipmap.c +++ b/mesalib/src/mesa/state_tracker/st_gen_mipmap.c @@ -1,424 +1,422 @@ -/************************************************************************** - * - * Copyright 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. - * - **************************************************************************/ - - -#include "main/imports.h" -#include "main/mipmap.h" -#include "main/teximage.h" - -#include "pipe/p_context.h" -#include "pipe/p_defines.h" -#include "util/u_inlines.h" -#include "util/u_format.h" -#include "util/u_gen_mipmap.h" - -#include "st_debug.h" -#include "st_context.h" -#include "st_texture.h" -#include "st_gen_mipmap.h" -#include "st_cb_texture.h" - - -/** - * one-time init for generate mipmap - * XXX Note: there may be other times we need no-op/simple state like this. - * In that case, some code refactoring would be good. - */ -void -st_init_generate_mipmap(struct st_context *st) -{ - st->gen_mipmap = util_create_gen_mipmap(st->pipe, st->cso_context); -} - - -void -st_destroy_generate_mipmap(struct st_context *st) -{ - util_destroy_gen_mipmap(st->gen_mipmap); - st->gen_mipmap = NULL; -} - - -/** - * Generate mipmap levels using hardware rendering. - * \return TRUE if successful, FALSE if not possible - */ -static boolean -st_render_mipmap(struct st_context *st, - GLenum target, - struct st_texture_object *stObj, - uint baseLevel, uint lastLevel) -{ - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; - struct pipe_sampler_view *psv = st_get_texture_sampler_view(stObj, pipe); - const uint face = _mesa_tex_target_to_face(target); - - assert(psv->texture == stObj->pt); -#if 0 - assert(target != GL_TEXTURE_3D); /* implemented but untested */ -#endif - - /* check if we can render in the texture's format */ - /* XXX should probably kill this and always use util_gen_mipmap - since this implements a sw fallback as well */ - if (!screen->is_format_supported(screen, psv->format, psv->texture->target, - 0, PIPE_BIND_RENDER_TARGET, 0)) { - return FALSE; - } - - util_gen_mipmap(st->gen_mipmap, psv, face, baseLevel, lastLevel, - PIPE_TEX_FILTER_LINEAR); - - return TRUE; -} - - -/** - * Helper function to decompress an image. The result is a 32-bpp RGBA - * image with stride==width. - */ -static void -decompress_image(enum pipe_format format, - const uint8_t *src, uint8_t *dst, - unsigned width, unsigned height) -{ - const struct util_format_description *desc = util_format_description(format); - const uint bw = util_format_get_blockwidth(format); - const uint bh = util_format_get_blockheight(format); - const uint dst_stride = 4 * MAX2(width, bw); - const uint src_stride = util_format_get_stride(format, width); - - desc->unpack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height); - - if (width < bw || height < bh) { - /* We're decompressing an image smaller than the compression - * block size. We don't want garbage pixel values in the region - * outside (width x height) so replicate pixels from the (width - * x height) region to fill out the (bw x bh) block size. - */ - uint x, y; - for (y = 0; y < bh; y++) { - for (x = 0; x < bw; x++) { - if (x >= width || y >= height) { - uint p = (y * bw + x) * 4; - dst[p + 0] = dst[0]; - dst[p + 1] = dst[1]; - dst[p + 2] = dst[2]; - dst[p + 3] = dst[3]; - } - } - } - } -} - - -/** - * Helper function to compress an image. The source is a 32-bpp RGBA image - * with stride==width. - */ -static void -compress_image(enum pipe_format format, - const uint8_t *src, uint8_t *dst, - unsigned width, unsigned height) -{ - const struct util_format_description *desc = util_format_description(format); - const uint dst_stride = util_format_get_stride(format, width); - const uint src_stride = 4 * width; - - desc->pack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height); -} - - -/** - * Software fallback for generate mipmap levels. - */ -static void -fallback_generate_mipmap(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj) -{ - struct pipe_context *pipe = st_context(ctx)->pipe; - struct pipe_resource *pt = st_get_texobj_resource(texObj); - const uint baseLevel = texObj->BaseLevel; - const uint lastLevel = pt->last_level; - const uint face = _mesa_tex_target_to_face(target); - uint dstLevel; - GLenum datatype; - GLuint comps; - GLboolean compressed; - - if (ST_DEBUG & DEBUG_FALLBACK) - debug_printf("%s: fallback processing\n", __FUNCTION__); - - assert(target != GL_TEXTURE_3D); /* not done yet */ - - compressed = - _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat); - - if (compressed) { - datatype = GL_UNSIGNED_BYTE; - comps = 4; - } - else { - _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat, - &datatype, &comps); - assert(comps > 0 && "bad texture format in fallback_generate_mipmap()"); - } - - for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { - const uint srcLevel = dstLevel - 1; - const uint srcWidth = u_minify(pt->width0, srcLevel); - const uint srcHeight = u_minify(pt->height0, srcLevel); - const uint srcDepth = u_minify(pt->depth0, srcLevel); - const uint dstWidth = u_minify(pt->width0, dstLevel); - const uint dstHeight = u_minify(pt->height0, dstLevel); - const uint dstDepth = u_minify(pt->depth0, dstLevel); - struct pipe_transfer *srcTrans, *dstTrans; - const ubyte *srcData; - ubyte *dstData; - int srcStride, dstStride; - - srcTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, srcLevel, - face, - PIPE_TRANSFER_READ, 0, 0, - srcWidth, srcHeight); - - dstTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, dstLevel, - face, - PIPE_TRANSFER_WRITE, 0, 0, - dstWidth, dstHeight); - - srcData = (ubyte *) pipe_transfer_map(pipe, srcTrans); - dstData = (ubyte *) pipe_transfer_map(pipe, dstTrans); - - srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format); - dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format); - - /* this cannot work correctly for 3d since it does - not respect layerStride. */ - if (compressed) { - const enum pipe_format format = pt->format; - const uint bw = util_format_get_blockwidth(format); - const uint bh = util_format_get_blockheight(format); - const uint srcWidth2 = align(srcWidth, bw); - const uint srcHeight2 = align(srcHeight, bh); - const uint dstWidth2 = align(dstWidth, bw); - const uint dstHeight2 = align(dstHeight, bh); - uint8_t *srcTemp, *dstTemp; - - assert(comps == 4); - - srcTemp = malloc(srcWidth2 * srcHeight2 * comps + 000); - dstTemp = malloc(dstWidth2 * dstHeight2 * comps + 000); - - /* decompress the src image: srcData -> srcTemp */ - decompress_image(format, srcData, srcTemp, srcWidth, srcHeight); - - _mesa_generate_mipmap_level(target, datatype, comps, - 0 /*border*/, - srcWidth2, srcHeight2, srcDepth, - srcTemp, - srcWidth2, /* stride in texels */ - dstWidth2, dstHeight2, dstDepth, - dstTemp, - dstWidth2); /* stride in texels */ - - /* compress the new image: dstTemp -> dstData */ - compress_image(format, dstTemp, dstData, dstWidth, dstHeight); - - free(srcTemp); - free(dstTemp); - } - else { - _mesa_generate_mipmap_level(target, datatype, comps, - 0 /*border*/, - srcWidth, srcHeight, srcDepth, - srcData, - srcStride, /* stride in texels */ - dstWidth, dstHeight, dstDepth, - dstData, - dstStride); /* stride in texels */ - } - - pipe_transfer_unmap(pipe, srcTrans); - pipe_transfer_unmap(pipe, dstTrans); - - pipe->transfer_destroy(pipe, srcTrans); - pipe->transfer_destroy(pipe, dstTrans); - } -} - - -/** - * Compute the expected number of mipmap levels in the texture given - * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/ - * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap - * levels should be generated. - */ -static GLuint -compute_num_levels(struct gl_context *ctx, - struct gl_texture_object *texObj, - GLenum target) -{ - if (target == GL_TEXTURE_RECTANGLE_ARB) { - return 1; - } - else { - const struct gl_texture_image *baseImage = - _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel); - GLuint size, numLevels; - - size = MAX2(baseImage->Width2, baseImage->Height2); - size = MAX2(size, baseImage->Depth2); - - numLevels = texObj->BaseLevel; - - while (size > 0) { - numLevels++; - size >>= 1; - } - - numLevels = MIN2(numLevels, texObj->MaxLevel + 1); - - assert(numLevels >= 1); - - return numLevels; - } -} - - -/** - * Called via ctx->Driver.GenerateMipmap(). - */ -void -st_generate_mipmap(struct gl_context *ctx, GLenum target, - struct gl_texture_object *texObj) -{ - struct st_context *st = st_context(ctx); - struct st_texture_object *stObj = st_texture_object(texObj); - struct pipe_resource *pt = st_get_texobj_resource(texObj); - const uint baseLevel = texObj->BaseLevel; - uint lastLevel; - uint dstLevel; - - if (!pt) - return; - - /* not sure if this ultimately actually should work, - but we're not supporting multisampled textures yet. */ - assert(pt->nr_samples < 2); - - /* find expected last mipmap level to generate*/ - lastLevel = compute_num_levels(ctx, texObj, target) - 1; - - if (lastLevel == 0) - return; - - if (pt->last_level < lastLevel) { - /* The current gallium texture doesn't have space for all the - * mipmap levels we need to generate. So allocate a new texture. - */ - struct pipe_resource *oldTex = stObj->pt; - - /* create new texture with space for more levels */ - stObj->pt = st_texture_create(st, - oldTex->target, - oldTex->format, - lastLevel, - oldTex->width0, - oldTex->height0, - oldTex->depth0, - oldTex->array_size, - oldTex->bind); - - /* The texture isn't in a "complete" state yet so set the expected - * lastLevel here, since it won't get done in st_finalize_texture(). - */ - stObj->lastLevel = lastLevel; - - /* This will copy the old texture's base image into the new texture - * which we just allocated. - */ - st_finalize_texture(ctx, st->pipe, texObj); - - /* release the old tex (will likely be freed too) */ - pipe_resource_reference(&oldTex, NULL); - pipe_sampler_view_reference(&stObj->sampler_view, NULL); - - pt = stObj->pt; - } - else { - /* Make sure that the base texture image data is present in the - * texture buffer. - */ - st_finalize_texture(ctx, st->pipe, texObj); - } - - assert(pt->last_level >= lastLevel); - - /* Try to generate the mipmap by rendering/texturing. If that fails, - * use the software fallback. - */ - if (!st_render_mipmap(st, target, stObj, baseLevel, lastLevel)) { - /* since the util code actually also has a fallback, should - probably make it never fail and kill this */ - fallback_generate_mipmap(ctx, target, texObj); - } - - /* Fill in the Mesa gl_texture_image fields */ - for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { - const uint srcLevel = dstLevel - 1; - const struct gl_texture_image *srcImage - = _mesa_get_tex_image(ctx, texObj, target, srcLevel); - struct gl_texture_image *dstImage; - struct st_texture_image *stImage; - uint dstWidth = u_minify(pt->width0, dstLevel); - uint dstHeight = u_minify(pt->height0, dstLevel); - uint dstDepth = u_minify(pt->depth0, dstLevel); - uint border = srcImage->Border; - - dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel); - if (!dstImage) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); - return; - } - - /* Free old image data */ - if (dstImage->Data) - ctx->Driver.FreeTexImageData(ctx, dstImage); - - /* initialize new image */ - _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight, - dstDepth, border, srcImage->InternalFormat, - srcImage->TexFormat); - - stImage = st_texture_image(dstImage); - stImage->level = dstLevel; - - pipe_resource_reference(&stImage->pt, pt); - } -} +/************************************************************************** + * + * Copyright 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. + * + **************************************************************************/ + + +#include "main/imports.h" +#include "main/mipmap.h" +#include "main/teximage.h" + +#include "pipe/p_context.h" +#include "pipe/p_defines.h" +#include "util/u_inlines.h" +#include "util/u_format.h" +#include "util/u_gen_mipmap.h" + +#include "st_debug.h" +#include "st_context.h" +#include "st_texture.h" +#include "st_gen_mipmap.h" +#include "st_cb_texture.h" + + +/** + * one-time init for generate mipmap + * XXX Note: there may be other times we need no-op/simple state like this. + * In that case, some code refactoring would be good. + */ +void +st_init_generate_mipmap(struct st_context *st) +{ + st->gen_mipmap = util_create_gen_mipmap(st->pipe, st->cso_context); +} + + +void +st_destroy_generate_mipmap(struct st_context *st) +{ + util_destroy_gen_mipmap(st->gen_mipmap); + st->gen_mipmap = NULL; +} + + +/** + * Generate mipmap levels using hardware rendering. + * \return TRUE if successful, FALSE if not possible + */ +static boolean +st_render_mipmap(struct st_context *st, + GLenum target, + struct st_texture_object *stObj, + uint baseLevel, uint lastLevel) +{ + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; + struct pipe_sampler_view *psv = st_get_texture_sampler_view(stObj, pipe); + const uint face = _mesa_tex_target_to_face(target); + + assert(psv->texture == stObj->pt); +#if 0 + assert(target != GL_TEXTURE_3D); /* implemented but untested */ +#endif + + /* check if we can render in the texture's format */ + /* XXX should probably kill this and always use util_gen_mipmap + since this implements a sw fallback as well */ + if (!screen->is_format_supported(screen, psv->format, psv->texture->target, + 0, PIPE_BIND_RENDER_TARGET, 0)) { + return FALSE; + } + + util_gen_mipmap(st->gen_mipmap, psv, face, baseLevel, lastLevel, + PIPE_TEX_FILTER_LINEAR); + + return TRUE; +} + + +/** + * Helper function to decompress an image. The result is a 32-bpp RGBA + * image with stride==width. + */ +static void +decompress_image(enum pipe_format format, + const uint8_t *src, uint8_t *dst, + unsigned width, unsigned height, unsigned src_stride) +{ + const struct util_format_description *desc = util_format_description(format); + const uint bw = util_format_get_blockwidth(format); + const uint bh = util_format_get_blockheight(format); + const uint dst_stride = 4 * MAX2(width, bw); + + desc->unpack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height); + + if (width < bw || height < bh) { + /* We're decompressing an image smaller than the compression + * block size. We don't want garbage pixel values in the region + * outside (width x height) so replicate pixels from the (width + * x height) region to fill out the (bw x bh) block size. + */ + uint x, y; + for (y = 0; y < bh; y++) { + for (x = 0; x < bw; x++) { + if (x >= width || y >= height) { + uint p = (y * bw + x) * 4; + dst[p + 0] = dst[0]; + dst[p + 1] = dst[1]; + dst[p + 2] = dst[2]; + dst[p + 3] = dst[3]; + } + } + } + } +} + + +/** + * Helper function to compress an image. The source is a 32-bpp RGBA image + * with stride==width. + */ +static void +compress_image(enum pipe_format format, + const uint8_t *src, uint8_t *dst, + unsigned width, unsigned height, unsigned dst_stride) +{ + const struct util_format_description *desc = util_format_description(format); + const uint src_stride = 4 * width; + + desc->pack_rgba_8unorm(dst, dst_stride, src, src_stride, width, height); +} + + +/** + * Software fallback for generate mipmap levels. + */ +static void +fallback_generate_mipmap(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + struct pipe_context *pipe = st_context(ctx)->pipe; + struct pipe_resource *pt = st_get_texobj_resource(texObj); + const uint baseLevel = texObj->BaseLevel; + const uint lastLevel = pt->last_level; + const uint face = _mesa_tex_target_to_face(target); + uint dstLevel; + GLenum datatype; + GLuint comps; + GLboolean compressed; + + if (ST_DEBUG & DEBUG_FALLBACK) + debug_printf("%s: fallback processing\n", __FUNCTION__); + + assert(target != GL_TEXTURE_3D); /* not done yet */ + + compressed = + _mesa_is_format_compressed(texObj->Image[face][baseLevel]->TexFormat); + + if (compressed) { + datatype = GL_UNSIGNED_BYTE; + comps = 4; + } + else { + _mesa_format_to_type_and_comps(texObj->Image[face][baseLevel]->TexFormat, + &datatype, &comps); + assert(comps > 0 && "bad texture format in fallback_generate_mipmap()"); + } + + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + const uint srcWidth = u_minify(pt->width0, srcLevel); + const uint srcHeight = u_minify(pt->height0, srcLevel); + const uint srcDepth = u_minify(pt->depth0, srcLevel); + const uint dstWidth = u_minify(pt->width0, dstLevel); + const uint dstHeight = u_minify(pt->height0, dstLevel); + const uint dstDepth = u_minify(pt->depth0, dstLevel); + struct pipe_transfer *srcTrans, *dstTrans; + const ubyte *srcData; + ubyte *dstData; + int srcStride, dstStride; + + srcTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, srcLevel, + face, + PIPE_TRANSFER_READ, 0, 0, + srcWidth, srcHeight); + + dstTrans = pipe_get_transfer(st_context(ctx)->pipe, pt, dstLevel, + face, + PIPE_TRANSFER_WRITE, 0, 0, + dstWidth, dstHeight); + + srcData = (ubyte *) pipe_transfer_map(pipe, srcTrans); + dstData = (ubyte *) pipe_transfer_map(pipe, dstTrans); + + srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->resource->format); + dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->resource->format); + + /* this cannot work correctly for 3d since it does + not respect layerStride. */ + if (compressed) { + const enum pipe_format format = pt->format; + const uint bw = util_format_get_blockwidth(format); + const uint bh = util_format_get_blockheight(format); + const uint srcWidth2 = align(srcWidth, bw); + const uint srcHeight2 = align(srcHeight, bh); + const uint dstWidth2 = align(dstWidth, bw); + const uint dstHeight2 = align(dstHeight, bh); + uint8_t *srcTemp, *dstTemp; + + assert(comps == 4); + + srcTemp = malloc(srcWidth2 * srcHeight2 * comps + 000); + dstTemp = malloc(dstWidth2 * dstHeight2 * comps + 000); + + /* decompress the src image: srcData -> srcTemp */ + decompress_image(format, srcData, srcTemp, srcWidth, srcHeight, srcTrans->stride); + + _mesa_generate_mipmap_level(target, datatype, comps, + 0 /*border*/, + srcWidth2, srcHeight2, srcDepth, + srcTemp, + srcWidth2, /* stride in texels */ + dstWidth2, dstHeight2, dstDepth, + dstTemp, + dstWidth2); /* stride in texels */ + + /* compress the new image: dstTemp -> dstData */ + compress_image(format, dstTemp, dstData, dstWidth, dstHeight, dstTrans->stride); + + free(srcTemp); + free(dstTemp); + } + else { + _mesa_generate_mipmap_level(target, datatype, comps, + 0 /*border*/, + srcWidth, srcHeight, srcDepth, + srcData, + srcStride, /* stride in texels */ + dstWidth, dstHeight, dstDepth, + dstData, + dstStride); /* stride in texels */ + } + + pipe_transfer_unmap(pipe, srcTrans); + pipe_transfer_unmap(pipe, dstTrans); + + pipe->transfer_destroy(pipe, srcTrans); + pipe->transfer_destroy(pipe, dstTrans); + } +} + + +/** + * Compute the expected number of mipmap levels in the texture given + * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/ + * GL_TEXTURE_MAX_LEVEL settings. This will tell us how many mipmap + * levels should be generated. + */ +static GLuint +compute_num_levels(struct gl_context *ctx, + struct gl_texture_object *texObj, + GLenum target) +{ + if (target == GL_TEXTURE_RECTANGLE_ARB) { + return 1; + } + else { + const struct gl_texture_image *baseImage = + _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel); + GLuint size, numLevels; + + size = MAX2(baseImage->Width2, baseImage->Height2); + size = MAX2(size, baseImage->Depth2); + + numLevels = texObj->BaseLevel; + + while (size > 0) { + numLevels++; + size >>= 1; + } + + numLevels = MIN2(numLevels, texObj->MaxLevel + 1); + + assert(numLevels >= 1); + + return numLevels; + } +} + + +/** + * Called via ctx->Driver.GenerateMipmap(). + */ +void +st_generate_mipmap(struct gl_context *ctx, GLenum target, + struct gl_texture_object *texObj) +{ + struct st_context *st = st_context(ctx); + struct st_texture_object *stObj = st_texture_object(texObj); + struct pipe_resource *pt = st_get_texobj_resource(texObj); + const uint baseLevel = texObj->BaseLevel; + uint lastLevel; + uint dstLevel; + + if (!pt) + return; + + /* not sure if this ultimately actually should work, + but we're not supporting multisampled textures yet. */ + assert(pt->nr_samples < 2); + + /* find expected last mipmap level to generate*/ + lastLevel = compute_num_levels(ctx, texObj, target) - 1; + + if (lastLevel == 0) + return; + + if (pt->last_level < lastLevel) { + /* The current gallium texture doesn't have space for all the + * mipmap levels we need to generate. So allocate a new texture. + */ + struct pipe_resource *oldTex = stObj->pt; + + /* create new texture with space for more levels */ + stObj->pt = st_texture_create(st, + oldTex->target, + oldTex->format, + lastLevel, + oldTex->width0, + oldTex->height0, + oldTex->depth0, + oldTex->array_size, + oldTex->bind); + + /* The texture isn't in a "complete" state yet so set the expected + * lastLevel here, since it won't get done in st_finalize_texture(). + */ + stObj->lastLevel = lastLevel; + + /* This will copy the old texture's base image into the new texture + * which we just allocated. + */ + st_finalize_texture(ctx, st->pipe, texObj); + + /* release the old tex (will likely be freed too) */ + pipe_resource_reference(&oldTex, NULL); + pipe_sampler_view_reference(&stObj->sampler_view, NULL); + + pt = stObj->pt; + } + else { + /* Make sure that the base texture image data is present in the + * texture buffer. + */ + st_finalize_texture(ctx, st->pipe, texObj); + } + + assert(pt->last_level >= lastLevel); + + /* Try to generate the mipmap by rendering/texturing. If that fails, + * use the software fallback. + */ + if (!st_render_mipmap(st, target, stObj, baseLevel, lastLevel)) { + /* since the util code actually also has a fallback, should + probably make it never fail and kill this */ + fallback_generate_mipmap(ctx, target, texObj); + } + + /* Fill in the Mesa gl_texture_image fields */ + for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { + const uint srcLevel = dstLevel - 1; + const struct gl_texture_image *srcImage + = _mesa_get_tex_image(ctx, texObj, target, srcLevel); + struct gl_texture_image *dstImage; + struct st_texture_image *stImage; + uint dstWidth = u_minify(pt->width0, dstLevel); + uint dstHeight = u_minify(pt->height0, dstLevel); + uint dstDepth = u_minify(pt->depth0, dstLevel); + uint border = srcImage->Border; + + dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel); + if (!dstImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); + return; + } + + /* Free old image data */ + if (dstImage->Data) + ctx->Driver.FreeTexImageData(ctx, dstImage); + + /* initialize new image */ + _mesa_init_teximage_fields(ctx, target, dstImage, dstWidth, dstHeight, + dstDepth, border, srcImage->InternalFormat, + srcImage->TexFormat); + + stImage = st_texture_image(dstImage); + stImage->level = dstLevel; + + pipe_resource_reference(&stImage->pt, pt); + } +} -- cgit v1.2.3